]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/ledger.c
xnu-2422.1.72.tar.gz
[apple/xnu.git] / osfmk / kern / ledger.c
1 /*
2 * Copyright (c) 2010 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * @OSF_COPYRIGHT@
30 */
31
32 #include <kern/lock.h>
33 #include <kern/ledger.h>
34 #include <kern/kalloc.h>
35 #include <kern/task.h>
36
37 #include <kern/processor.h>
38 #include <kern/machine.h>
39 #include <kern/queue.h>
40 #include <sys/errno.h>
41
42 #include <libkern/OSAtomic.h>
43 #include <mach/mach_types.h>
44
45 /*
46 * Ledger entry flags. Bits in second nibble (masked by 0xF0) are used for
47 * ledger actions (LEDGER_ACTION_BLOCK, etc).
48 */
49 #define LF_ENTRY_ACTIVE 0x0001 /* entry is active if set */
50 #define LF_WAKE_NEEDED 0x0100 /* one or more threads are asleep */
51 #define LF_WAKE_INPROGRESS 0x0200 /* the wait queue is being processed */
52 #define LF_REFILL_SCHEDULED 0x0400 /* a refill timer has been set */
53 #define LF_REFILL_INPROGRESS 0x0800 /* the ledger is being refilled */
54 #define LF_CALLED_BACK 0x1000 /* callback was called for balance in deficit */
55 #define LF_WARNED 0x2000 /* callback was called for balance warning */
56 #define LF_TRACKING_MAX 0x4000 /* track max balance over user-specfied time */
57
58 /* Determine whether a ledger entry exists and has been initialized and active */
59 #define ENTRY_VALID(l, e) \
60 (((l) != NULL) && ((e) >= 0) && ((e) < (l)->l_size) && \
61 (((l)->l_entries[e].le_flags & LF_ENTRY_ACTIVE) == LF_ENTRY_ACTIVE))
62
63 #ifdef LEDGER_DEBUG
64 int ledger_debug = 0;
65
66 #define ASSERT(a) assert(a)
67 #define lprintf(a) if (ledger_debug) { \
68 printf("%lld ", abstime_to_nsecs(mach_absolute_time() / 1000000)); \
69 printf a ; \
70 }
71 #else
72 #define lprintf(a)
73 #define ASSERT(a)
74 #endif
75
76 struct ledger_callback {
77 ledger_callback_t lc_func;
78 const void *lc_param0;
79 const void *lc_param1;
80 };
81
82 struct entry_template {
83 char et_key[LEDGER_NAME_MAX];
84 char et_group[LEDGER_NAME_MAX];
85 char et_units[LEDGER_NAME_MAX];
86 uint32_t et_flags;
87 struct ledger_callback *et_callback;
88 };
89
90 lck_grp_t ledger_lck_grp;
91
92 /*
93 * Modifying the reference count, table size, or table contents requires
94 * holding the lt_lock. Modfying the table address requires both lt_lock
95 * and setting the inuse bit. This means that the lt_entries field can be
96 * safely dereferenced if you hold either the lock or the inuse bit. The
97 * inuse bit exists solely to allow us to swap in a new, larger entries
98 * table without requiring a full lock to be acquired on each lookup.
99 * Accordingly, the inuse bit should never be held for longer than it takes
100 * to extract a value from the table - i.e., 2 or 3 memory references.
101 */
102 struct ledger_template {
103 const char *lt_name;
104 int lt_refs;
105 int lt_cnt;
106 int lt_table_size;
107 volatile uint32_t lt_inuse;
108 lck_mtx_t lt_lock;
109 struct entry_template *lt_entries;
110 };
111
112 #define template_lock(template) lck_mtx_lock(&(template)->lt_lock)
113 #define template_unlock(template) lck_mtx_unlock(&(template)->lt_lock)
114
115 #define TEMPLATE_INUSE(s, t) { \
116 s = splsched(); \
117 while (OSCompareAndSwap(0, 1, &((t)->lt_inuse))) \
118 ; \
119 }
120
121 #define TEMPLATE_IDLE(s, t) { \
122 (t)->lt_inuse = 0; \
123 splx(s); \
124 }
125
126 /*
127 * Use 2 "tocks" to track the rolling maximum balance of a ledger entry.
128 */
129 #define NTOCKS 2
130 /*
131 * The explicit alignment is to ensure that atomic operations don't panic
132 * on ARM.
133 */
134 struct ledger_entry {
135 volatile uint32_t le_flags;
136 ledger_amount_t le_limit;
137 ledger_amount_t le_warn_level;
138 volatile ledger_amount_t le_credit __attribute__((aligned(8)));
139 volatile ledger_amount_t le_debit __attribute__((aligned(8)));
140 union {
141 struct {
142 /*
143 * XXX - the following two fields can go away if we move all of
144 * the refill logic into process policy
145 */
146 uint64_t le_refill_period;
147 uint64_t le_last_refill;
148 } le_refill;
149 struct _le_peak {
150 uint32_t le_max; /* Lower 32-bits of observed max balance */
151 uint32_t le_time; /* time when this peak was observed */
152 } le_peaks[NTOCKS];
153 } _le;
154 } __attribute__((aligned(8)));
155
156 struct ledger {
157 int l_id;
158 struct ledger_template *l_template;
159 int l_refs;
160 int l_size;
161 struct ledger_entry *l_entries;
162 };
163
164 static int ledger_cnt = 0;
165 /* ledger ast helper functions */
166 static uint32_t ledger_check_needblock(ledger_t l, uint64_t now);
167 static kern_return_t ledger_perform_blocking(ledger_t l);
168 static uint32_t flag_set(volatile uint32_t *flags, uint32_t bit);
169 static uint32_t flag_clear(volatile uint32_t *flags, uint32_t bit);
170
171 #if 0
172 static void
173 debug_callback(const void *p0, __unused const void *p1)
174 {
175 printf("ledger: resource exhausted [%s] for task %p\n",
176 (const char *)p0, p1);
177 }
178 #endif
179
180 /************************************/
181
182 static uint64_t
183 abstime_to_nsecs(uint64_t abstime)
184 {
185 uint64_t nsecs;
186
187 absolutetime_to_nanoseconds(abstime, &nsecs);
188 return (nsecs);
189 }
190
191 static uint64_t
192 nsecs_to_abstime(uint64_t nsecs)
193 {
194 uint64_t abstime;
195
196 nanoseconds_to_absolutetime(nsecs, &abstime);
197 return (abstime);
198 }
199
200 void
201 ledger_init(void)
202 {
203 lck_grp_init(&ledger_lck_grp, "ledger", LCK_GRP_ATTR_NULL);
204 }
205
206 ledger_template_t
207 ledger_template_create(const char *name)
208 {
209 ledger_template_t template;
210
211 template = (ledger_template_t)kalloc(sizeof (*template));
212 if (template == NULL)
213 return (NULL);
214
215 template->lt_name = name;
216 template->lt_refs = 1;
217 template->lt_cnt = 0;
218 template->lt_table_size = 1;
219 template->lt_inuse = 0;
220 lck_mtx_init(&template->lt_lock, &ledger_lck_grp, LCK_ATTR_NULL);
221
222 template->lt_entries = (struct entry_template *)
223 kalloc(sizeof (struct entry_template) * template->lt_table_size);
224 if (template->lt_entries == NULL) {
225 kfree(template, sizeof (*template));
226 template = NULL;
227 }
228
229 return (template);
230 }
231
232 void
233 ledger_template_dereference(ledger_template_t template)
234 {
235 template_lock(template);
236 template->lt_refs--;
237 template_unlock(template);
238
239 if (template->lt_refs == 0)
240 kfree(template, sizeof (*template));
241 }
242
243 /*
244 * Add a new entry to the list of entries in a ledger template. There is
245 * currently no mechanism to remove an entry. Implementing such a mechanism
246 * would require us to maintain per-entry reference counts, which we would
247 * prefer to avoid if possible.
248 */
249 int
250 ledger_entry_add(ledger_template_t template, const char *key,
251 const char *group, const char *units)
252 {
253 int idx;
254 struct entry_template *et;
255
256 if ((key == NULL) || (strlen(key) >= LEDGER_NAME_MAX))
257 return (-1);
258
259 template_lock(template);
260
261 /* If the table is full, attempt to double its size */
262 if (template->lt_cnt == template->lt_table_size) {
263 struct entry_template *new_entries, *old_entries;
264 int old_cnt, old_sz;
265 spl_t s;
266
267 old_cnt = template->lt_table_size;
268 old_sz = (int)(old_cnt * sizeof (struct entry_template));
269 new_entries = kalloc(old_sz * 2);
270 if (new_entries == NULL) {
271 template_unlock(template);
272 return (-1);
273 }
274 memcpy(new_entries, template->lt_entries, old_sz);
275 memset(((char *)new_entries) + old_sz, 0, old_sz);
276 template->lt_table_size = old_cnt * 2;
277
278 old_entries = template->lt_entries;
279
280 TEMPLATE_INUSE(s, template);
281 template->lt_entries = new_entries;
282 TEMPLATE_IDLE(s, template);
283
284 kfree(old_entries, old_sz);
285 }
286
287 et = &template->lt_entries[template->lt_cnt];
288 strlcpy(et->et_key, key, LEDGER_NAME_MAX);
289 strlcpy(et->et_group, group, LEDGER_NAME_MAX);
290 strlcpy(et->et_units, units, LEDGER_NAME_MAX);
291 et->et_flags = LF_ENTRY_ACTIVE;
292 et->et_callback = NULL;
293
294 idx = template->lt_cnt++;
295 template_unlock(template);
296
297 return (idx);
298 }
299
300
301 kern_return_t
302 ledger_entry_setactive(ledger_t ledger, int entry)
303 {
304 struct ledger_entry *le;
305
306 if ((ledger == NULL) || (entry < 0) || (entry >= ledger->l_size))
307 return (KERN_INVALID_ARGUMENT);
308
309 le = &ledger->l_entries[entry];
310 if ((le->le_flags & LF_ENTRY_ACTIVE) == 0) {
311 flag_set(&le->le_flags, LF_ENTRY_ACTIVE);
312 }
313 return (KERN_SUCCESS);
314 }
315
316
317 int
318 ledger_key_lookup(ledger_template_t template, const char *key)
319 {
320 int idx;
321
322 template_lock(template);
323 for (idx = 0; idx < template->lt_cnt; idx++)
324 if (template->lt_entries[idx].et_key &&
325 (strcmp(key, template->lt_entries[idx].et_key) == 0))
326 break;
327
328 if (idx >= template->lt_cnt)
329 idx = -1;
330 template_unlock(template);
331
332 return (idx);
333 }
334
335 /*
336 * Create a new ledger based on the specified template. As part of the
337 * ledger creation we need to allocate space for a table of ledger entries.
338 * The size of the table is based on the size of the template at the time
339 * the ledger is created. If additional entries are added to the template
340 * after the ledger is created, they will not be tracked in this ledger.
341 */
342 ledger_t
343 ledger_instantiate(ledger_template_t template, int entry_type)
344 {
345 ledger_t ledger;
346 size_t sz;
347 int i;
348
349 ledger = (ledger_t)kalloc(sizeof (struct ledger));
350 if (ledger == NULL)
351 return (LEDGER_NULL);
352
353 ledger->l_template = template;
354 ledger->l_id = ledger_cnt++;
355 ledger->l_refs = 1;
356
357 template_lock(template);
358 template->lt_refs++;
359 ledger->l_size = template->lt_cnt;
360 template_unlock(template);
361
362 sz = ledger->l_size * sizeof (struct ledger_entry);
363 ledger->l_entries = kalloc(sz);
364 if (sz && (ledger->l_entries == NULL)) {
365 ledger_template_dereference(template);
366 kfree(ledger, sizeof(struct ledger));
367 return (LEDGER_NULL);
368 }
369
370 template_lock(template);
371 assert(ledger->l_size <= template->lt_cnt);
372 for (i = 0; i < ledger->l_size; i++) {
373 struct ledger_entry *le = &ledger->l_entries[i];
374 struct entry_template *et = &template->lt_entries[i];
375
376 le->le_flags = et->et_flags;
377 /* make entry inactive by removing active bit */
378 if (entry_type == LEDGER_CREATE_INACTIVE_ENTRIES)
379 flag_clear(&le->le_flags, LF_ENTRY_ACTIVE);
380 /*
381 * If template has a callback, this entry is opted-in,
382 * by default.
383 */
384 if (et->et_callback != NULL)
385 flag_set(&le->le_flags, LEDGER_ACTION_CALLBACK);
386 le->le_credit = 0;
387 le->le_debit = 0;
388 le->le_limit = LEDGER_LIMIT_INFINITY;
389 le->le_warn_level = LEDGER_LIMIT_INFINITY;
390 le->_le.le_refill.le_refill_period = 0;
391 le->_le.le_refill.le_last_refill = 0;
392 }
393 template_unlock(template);
394
395 return (ledger);
396 }
397
398 static uint32_t
399 flag_set(volatile uint32_t *flags, uint32_t bit)
400 {
401 return (OSBitOrAtomic(bit, flags));
402 }
403
404 static uint32_t
405 flag_clear(volatile uint32_t *flags, uint32_t bit)
406 {
407 return (OSBitAndAtomic(~bit, flags));
408 }
409
410 /*
411 * Take a reference on a ledger
412 */
413 kern_return_t
414 ledger_reference(ledger_t ledger)
415 {
416 if (!LEDGER_VALID(ledger))
417 return (KERN_INVALID_ARGUMENT);
418 OSIncrementAtomic(&ledger->l_refs);
419 return (KERN_SUCCESS);
420 }
421
422 int
423 ledger_reference_count(ledger_t ledger)
424 {
425 if (!LEDGER_VALID(ledger))
426 return (-1);
427
428 return (ledger->l_refs);
429 }
430
431 /*
432 * Remove a reference on a ledger. If this is the last reference,
433 * deallocate the unused ledger.
434 */
435 kern_return_t
436 ledger_dereference(ledger_t ledger)
437 {
438 int v;
439
440 if (!LEDGER_VALID(ledger))
441 return (KERN_INVALID_ARGUMENT);
442
443 v = OSDecrementAtomic(&ledger->l_refs);
444 ASSERT(v >= 1);
445
446 /* Just released the last reference. Free it. */
447 if (v == 1) {
448 kfree(ledger->l_entries,
449 ledger->l_size * sizeof (struct ledger_entry));
450 kfree(ledger, sizeof (*ledger));
451 }
452
453 return (KERN_SUCCESS);
454 }
455
456 /*
457 * Determine whether an entry has exceeded its warning level.
458 */
459 static inline int
460 warn_level_exceeded(struct ledger_entry *le)
461 {
462 ledger_amount_t balance;
463
464 assert((le->le_credit >= 0) && (le->le_debit >= 0));
465
466 /*
467 * XXX - Currently, we only support warnings for ledgers which
468 * use positive limits.
469 */
470 balance = le->le_credit - le->le_debit;
471 if ((le->le_warn_level != LEDGER_LIMIT_INFINITY) && (balance > le->le_warn_level))
472 return (1);
473 return (0);
474 }
475
476 /*
477 * Determine whether an entry has exceeded its limit.
478 */
479 static inline int
480 limit_exceeded(struct ledger_entry *le)
481 {
482 ledger_amount_t balance;
483
484 assert((le->le_credit >= 0) && (le->le_debit >= 0));
485
486 balance = le->le_credit - le->le_debit;
487 if ((le->le_limit <= 0) && (balance < le->le_limit))
488 return (1);
489
490 if ((le->le_limit > 0) && (balance > le->le_limit))
491 return (1);
492 return (0);
493 }
494
495 static inline struct ledger_callback *
496 entry_get_callback(ledger_t ledger, int entry)
497 {
498 struct ledger_callback *callback;
499 spl_t s;
500
501 TEMPLATE_INUSE(s, ledger->l_template);
502 callback = ledger->l_template->lt_entries[entry].et_callback;
503 TEMPLATE_IDLE(s, ledger->l_template);
504
505 return (callback);
506 }
507
508 /*
509 * If the ledger value is positive, wake up anybody waiting on it.
510 */
511 static inline void
512 ledger_limit_entry_wakeup(struct ledger_entry *le)
513 {
514 uint32_t flags;
515
516 if (!limit_exceeded(le)) {
517 flags = flag_clear(&le->le_flags, LF_CALLED_BACK);
518
519 while (le->le_flags & LF_WAKE_NEEDED) {
520 flag_clear(&le->le_flags, LF_WAKE_NEEDED);
521 thread_wakeup((event_t)le);
522 }
523 }
524 }
525
526 /*
527 * Refill the coffers.
528 */
529 static void
530 ledger_refill(uint64_t now, ledger_t ledger, int entry)
531 {
532 uint64_t elapsed, period, periods;
533 struct ledger_entry *le;
534 ledger_amount_t balance, due;
535
536 le = &ledger->l_entries[entry];
537
538 assert(le->le_limit != LEDGER_LIMIT_INFINITY);
539
540 /*
541 * If another thread is handling the refill already, we're not
542 * needed.
543 */
544 if (flag_set(&le->le_flags, LF_REFILL_INPROGRESS) & LF_REFILL_INPROGRESS) {
545 return;
546 }
547
548 /*
549 * If the timestamp we're about to use to refill is older than the
550 * last refill, then someone else has already refilled this ledger
551 * and there's nothing for us to do here.
552 */
553 if (now <= le->_le.le_refill.le_last_refill) {
554 flag_clear(&le->le_flags, LF_REFILL_INPROGRESS);
555 return;
556 }
557
558 /*
559 * See how many refill periods have passed since we last
560 * did a refill.
561 */
562 period = le->_le.le_refill.le_refill_period;
563 elapsed = now - le->_le.le_refill.le_last_refill;
564 if ((period == 0) || (elapsed < period)) {
565 flag_clear(&le->le_flags, LF_REFILL_INPROGRESS);
566 return;
567 }
568
569 /*
570 * Optimize for the most common case of only one or two
571 * periods elapsing.
572 */
573 periods = 0;
574 while ((periods < 2) && (elapsed > 0)) {
575 periods++;
576 elapsed -= period;
577 }
578
579 /*
580 * OK, it's been a long time. Do a divide to figure out
581 * how long.
582 */
583 if (elapsed > 0)
584 periods = (now - le->_le.le_refill.le_last_refill) / period;
585
586 balance = le->le_credit - le->le_debit;
587 due = periods * le->le_limit;
588 if (balance - due < 0)
589 due = balance;
590
591 assert(due >= 0);
592
593 OSAddAtomic64(due, &le->le_debit);
594
595 assert(le->le_debit >= 0);
596
597 /*
598 * If we've completely refilled the pool, set the refill time to now.
599 * Otherwise set it to the time at which it last should have been
600 * fully refilled.
601 */
602 if (balance == due)
603 le->_le.le_refill.le_last_refill = now;
604 else
605 le->_le.le_refill.le_last_refill += (le->_le.le_refill.le_refill_period * periods);
606
607 flag_clear(&le->le_flags, LF_REFILL_INPROGRESS);
608
609 lprintf(("Refill %lld %lld->%lld\n", periods, balance, balance - due));
610 if (!limit_exceeded(le))
611 ledger_limit_entry_wakeup(le);
612 }
613
614 /*
615 * In tenths of a second, the length of one lookback period (a "tock") for
616 * ledger rolling maximum calculations. The effective lookback window will be this times
617 * NTOCKS.
618 *
619 * Use a tock length of 2.5 seconds to get a total lookback period of 5 seconds.
620 *
621 * XXX Could make this caller-definable, at the point that rolling max tracking
622 * is enabled for the entry.
623 */
624 #define TOCKLEN 25
625
626 /*
627 * How many sched_tick's are there in one tock (one of our lookback periods)?
628 *
629 * X sched_ticks 2.5 sec N sched_ticks
630 * --------------- = ---------- * -------------
631 * tock tock sec
632 *
633 * where N sched_ticks/sec is calculated via 1 << SCHED_TICK_SHIFT (see sched_prim.h)
634 *
635 * This should give us 20 sched_tick's in one 2.5 second-long tock.
636 */
637 #define SCHED_TICKS_PER_TOCK ((TOCKLEN * (1 << SCHED_TICK_SHIFT)) / 10)
638
639 /*
640 * Rolling max timestamps use their own unit (let's call this a "tock"). One tock is the
641 * length of one lookback period that we use for our rolling max calculation.
642 *
643 * Calculate the current time in tocks from sched_tick (which runs at a some
644 * fixed rate).
645 */
646 #define CURRENT_TOCKSTAMP() (sched_tick / SCHED_TICKS_PER_TOCK)
647
648 /*
649 * Does the given tockstamp fall in either the current or the previous tocks?
650 */
651 #define TOCKSTAMP_IS_STALE(now, tock) ((((now) - (tock)) < NTOCKS) ? FALSE : TRUE)
652
653 static void
654 ledger_check_new_balance(ledger_t ledger, int entry)
655 {
656 struct ledger_entry *le;
657
658 le = &ledger->l_entries[entry];
659
660 if (le->le_flags & LF_TRACKING_MAX) {
661 ledger_amount_t balance = le->le_credit - le->le_debit;
662 uint32_t now = CURRENT_TOCKSTAMP();
663 struct _le_peak *p = &le->_le.le_peaks[now % NTOCKS];
664
665 if (!TOCKSTAMP_IS_STALE(now, p->le_time) || (balance > p->le_max)) {
666 /*
667 * The current balance is greater than the previously
668 * observed peak for the current time block, *or* we
669 * haven't yet recorded a peak for the current time block --
670 * so this is our new peak.
671 *
672 * (We only track the lower 32-bits of a balance for rolling
673 * max purposes.)
674 */
675 p->le_max = (uint32_t)balance;
676 p->le_time = now;
677 }
678 }
679
680 /* Check to see whether we're due a refill */
681 if (le->le_flags & LF_REFILL_SCHEDULED) {
682 uint64_t now = mach_absolute_time();
683 if ((now - le->_le.le_refill.le_last_refill) > le->_le.le_refill.le_refill_period)
684 ledger_refill(now, ledger, entry);
685 }
686
687 if (limit_exceeded(le)) {
688 /*
689 * We've exceeded the limit for this entry. There
690 * are several possible ways to handle it. We can block,
691 * we can execute a callback, or we can ignore it. In
692 * either of the first two cases, we want to set the AST
693 * flag so we can take the appropriate action just before
694 * leaving the kernel. The one caveat is that if we have
695 * already called the callback, we don't want to do it
696 * again until it gets rearmed.
697 */
698 if ((le->le_flags & LEDGER_ACTION_BLOCK) ||
699 (!(le->le_flags & LF_CALLED_BACK) &&
700 entry_get_callback(ledger, entry))) {
701 set_astledger(current_thread());
702 }
703 } else {
704 /*
705 * The balance on the account is below the limit.
706 *
707 * If there are any threads blocked on this entry, now would
708 * be a good time to wake them up.
709 */
710 if (le->le_flags & LF_WAKE_NEEDED)
711 ledger_limit_entry_wakeup(le);
712
713 if (le->le_flags & LEDGER_ACTION_CALLBACK) {
714 /*
715 * Client has requested that a callback be invoked whenever
716 * the ledger's balance crosses into or out of the warning
717 * level.
718 */
719 if (warn_level_exceeded(le)) {
720 /*
721 * This ledger's balance is above the warning level.
722 */
723 if ((le->le_flags & LF_WARNED) == 0) {
724 /*
725 * If we are above the warning level and
726 * have not yet invoked the callback,
727 * set the AST so it can be done before returning
728 * to userland.
729 */
730 set_astledger(current_thread());
731 }
732 } else {
733 /*
734 * This ledger's balance is below the warning level.
735 */
736 if (le->le_flags & LF_WARNED) {
737 /*
738 * If we are below the warning level and
739 * the LF_WARNED flag is still set, we need
740 * to invoke the callback to let the client
741 * know the ledger balance is now back below
742 * the warning level.
743 */
744 set_astledger(current_thread());
745 }
746 }
747 }
748 }
749 }
750
751 /*
752 * Add value to an entry in a ledger.
753 */
754 kern_return_t
755 ledger_credit(ledger_t ledger, int entry, ledger_amount_t amount)
756 {
757 ledger_amount_t old, new;
758 struct ledger_entry *le;
759
760 if (!ENTRY_VALID(ledger, entry) || (amount < 0))
761 return (KERN_INVALID_VALUE);
762
763 if (amount == 0)
764 return (KERN_SUCCESS);
765
766 le = &ledger->l_entries[entry];
767
768 old = OSAddAtomic64(amount, &le->le_credit);
769 new = old + amount;
770 lprintf(("%p Credit %lld->%lld\n", current_thread(), old, new));
771 ledger_check_new_balance(ledger, entry);
772
773 return (KERN_SUCCESS);
774 }
775
776 /*
777 * Zero the balance of a ledger by adding to its credit or debit, whichever is smaller.
778 * Note that some clients of ledgers (notably, task wakeup statistics) require that
779 * le_credit only ever increase as a function of ledger_credit().
780 */
781 kern_return_t
782 ledger_zero_balance(ledger_t ledger, int entry)
783 {
784 struct ledger_entry *le;
785
786 if (!ENTRY_VALID(ledger, entry))
787 return (KERN_INVALID_VALUE);
788
789 le = &ledger->l_entries[entry];
790
791 top:
792 if (le->le_credit > le->le_debit) {
793 if (!OSCompareAndSwap64(le->le_debit, le->le_credit, &le->le_debit))
794 goto top;
795 lprintf(("%p zeroed %lld->%lld\n", current_thread(), le->le_debit, le->le_credit));
796 } else if (le->le_credit < le->le_debit) {
797 if (!OSCompareAndSwap64(le->le_credit, le->le_debit, &le->le_credit))
798 goto top;
799 lprintf(("%p zeroed %lld->%lld\n", current_thread(), le->le_credit, le->le_debit));
800 }
801
802 return (KERN_SUCCESS);
803 }
804
805 kern_return_t
806 ledger_get_limit(ledger_t ledger, int entry, ledger_amount_t *limit)
807 {
808 struct ledger_entry *le;
809
810 if (!ENTRY_VALID(ledger, entry))
811 return (KERN_INVALID_VALUE);
812
813 le = &ledger->l_entries[entry];
814 *limit = le->le_limit;
815
816 lprintf(("ledger_get_limit: %lld\n", *limit));
817
818 return (KERN_SUCCESS);
819 }
820
821 /*
822 * Adjust the limit of a limited resource. This does not affect the
823 * current balance, so the change doesn't affect the thread until the
824 * next refill.
825 *
826 * warn_level: If non-zero, causes the callback to be invoked when
827 * the balance exceeds this level. Specified as a percentage [of the limit].
828 */
829 kern_return_t
830 ledger_set_limit(ledger_t ledger, int entry, ledger_amount_t limit,
831 uint8_t warn_level_percentage)
832 {
833 struct ledger_entry *le;
834
835 if (!ENTRY_VALID(ledger, entry))
836 return (KERN_INVALID_VALUE);
837
838 lprintf(("ledger_set_limit: %lld\n", limit));
839 le = &ledger->l_entries[entry];
840
841 if (limit == LEDGER_LIMIT_INFINITY) {
842 /*
843 * Caller wishes to disable the limit. This will implicitly
844 * disable automatic refill, as refills implicitly depend
845 * on the limit.
846 */
847 ledger_disable_refill(ledger, entry);
848 }
849
850 le->le_limit = limit;
851 le->_le.le_refill.le_last_refill = 0;
852 flag_clear(&le->le_flags, LF_CALLED_BACK);
853 flag_clear(&le->le_flags, LF_WARNED);
854 ledger_limit_entry_wakeup(le);
855
856 if (warn_level_percentage != 0) {
857 assert(warn_level_percentage <= 100);
858 assert(limit > 0); /* no negative limit support for warnings */
859 assert(limit != LEDGER_LIMIT_INFINITY); /* warn % without limit makes no sense */
860 le->le_warn_level = (le->le_limit * warn_level_percentage) / 100;
861 } else {
862 le->le_warn_level = LEDGER_LIMIT_INFINITY;
863 }
864
865 return (KERN_SUCCESS);
866 }
867
868 kern_return_t
869 ledger_get_maximum(ledger_t ledger, int entry,
870 ledger_amount_t *max_observed_balance)
871 {
872 struct ledger_entry *le;
873 uint32_t now = CURRENT_TOCKSTAMP();
874 int i;
875
876 le = &ledger->l_entries[entry];
877
878 if (!ENTRY_VALID(ledger, entry) || !(le->le_flags & LF_TRACKING_MAX)) {
879 return (KERN_INVALID_VALUE);
880 }
881
882 /*
883 * Start with the current balance; if neither of the recorded peaks are
884 * within recent history, we use this.
885 */
886 *max_observed_balance = le->le_credit - le->le_debit;
887
888 for (i = 0; i < NTOCKS; i++) {
889 if (!TOCKSTAMP_IS_STALE(now, le->_le.le_peaks[i].le_time) &&
890 (le->_le.le_peaks[i].le_max > *max_observed_balance)) {
891 /*
892 * The peak for this time block isn't stale, and it
893 * is greater than the current balance -- so use it.
894 */
895 *max_observed_balance = le->_le.le_peaks[i].le_max;
896 }
897 }
898
899 lprintf(("ledger_get_maximum: %lld\n", *max_observed_balance));
900
901 return (KERN_SUCCESS);
902 }
903
904 /*
905 * Enable tracking of periodic maximums for this ledger entry.
906 */
907 kern_return_t
908 ledger_track_maximum(ledger_template_t template, int entry,
909 __unused int period_in_secs)
910 {
911 template_lock(template);
912
913 if ((entry < 0) || (entry >= template->lt_cnt)) {
914 template_unlock(template);
915 return (KERN_INVALID_VALUE);
916 }
917
918 template->lt_entries[entry].et_flags |= LF_TRACKING_MAX;
919 template_unlock(template);
920
921 return (KERN_SUCCESS);
922 }
923
924 /*
925 * Add a callback to be executed when the resource goes into deficit.
926 */
927 kern_return_t
928 ledger_set_callback(ledger_template_t template, int entry,
929 ledger_callback_t func, const void *param0, const void *param1)
930 {
931 struct entry_template *et;
932 struct ledger_callback *old_cb, *new_cb;
933
934 if ((entry < 0) || (entry >= template->lt_cnt))
935 return (KERN_INVALID_VALUE);
936
937 if (func) {
938 new_cb = (struct ledger_callback *)kalloc(sizeof (*new_cb));
939 new_cb->lc_func = func;
940 new_cb->lc_param0 = param0;
941 new_cb->lc_param1 = param1;
942 } else {
943 new_cb = NULL;
944 }
945
946 template_lock(template);
947 et = &template->lt_entries[entry];
948 old_cb = et->et_callback;
949 et->et_callback = new_cb;
950 template_unlock(template);
951 if (old_cb)
952 kfree(old_cb, sizeof (*old_cb));
953
954 return (KERN_SUCCESS);
955 }
956
957 /*
958 * Disable callback notification for a specific ledger entry.
959 *
960 * Otherwise, if using a ledger template which specified a
961 * callback function (ledger_set_callback()), it will be invoked when
962 * the resource goes into deficit.
963 */
964 kern_return_t
965 ledger_disable_callback(ledger_t ledger, int entry)
966 {
967 if (!ENTRY_VALID(ledger, entry))
968 return (KERN_INVALID_VALUE);
969
970 /*
971 * le_warn_level is used to indicate *if* this ledger has a warning configured,
972 * in addition to what that warning level is set to.
973 * This means a side-effect of ledger_disable_callback() is that the
974 * warning level is forgotten.
975 */
976 ledger->l_entries[entry].le_warn_level = LEDGER_LIMIT_INFINITY;
977 flag_clear(&ledger->l_entries[entry].le_flags, LEDGER_ACTION_CALLBACK);
978 return (KERN_SUCCESS);
979 }
980
981 /*
982 * Enable callback notification for a specific ledger entry.
983 *
984 * This is only needed if ledger_disable_callback() has previously
985 * been invoked against an entry; there must already be a callback
986 * configured.
987 */
988 kern_return_t
989 ledger_enable_callback(ledger_t ledger, int entry)
990 {
991 if (!ENTRY_VALID(ledger, entry))
992 return (KERN_INVALID_VALUE);
993
994 assert(entry_get_callback(ledger, entry) != NULL);
995
996 flag_set(&ledger->l_entries[entry].le_flags, LEDGER_ACTION_CALLBACK);
997 return (KERN_SUCCESS);
998 }
999
1000 /*
1001 * Query the automatic refill period for this ledger entry.
1002 *
1003 * A period of 0 means this entry has none configured.
1004 */
1005 kern_return_t
1006 ledger_get_period(ledger_t ledger, int entry, uint64_t *period)
1007 {
1008 struct ledger_entry *le;
1009
1010 if (!ENTRY_VALID(ledger, entry))
1011 return (KERN_INVALID_VALUE);
1012
1013 le = &ledger->l_entries[entry];
1014 *period = abstime_to_nsecs(le->_le.le_refill.le_refill_period);
1015 lprintf(("ledger_get_period: %llx\n", *period));
1016 return (KERN_SUCCESS);
1017 }
1018
1019 /*
1020 * Adjust the automatic refill period.
1021 */
1022 kern_return_t
1023 ledger_set_period(ledger_t ledger, int entry, uint64_t period)
1024 {
1025 struct ledger_entry *le;
1026
1027 lprintf(("ledger_set_period: %llx\n", period));
1028 if (!ENTRY_VALID(ledger, entry))
1029 return (KERN_INVALID_VALUE);
1030
1031 le = &ledger->l_entries[entry];
1032
1033 /*
1034 * A refill period refills the ledger in multiples of the limit,
1035 * so if you haven't set one yet, you need a lesson on ledgers.
1036 */
1037 assert(le->le_limit != LEDGER_LIMIT_INFINITY);
1038
1039 if (le->le_flags & LF_TRACKING_MAX) {
1040 /*
1041 * Refill is incompatible with rolling max tracking.
1042 */
1043 return (KERN_INVALID_VALUE);
1044 }
1045
1046 le->_le.le_refill.le_refill_period = nsecs_to_abstime(period);
1047
1048 /*
1049 * Set the 'starting time' for the next refill to now. Since
1050 * we're resetting the balance to zero here, we consider this
1051 * moment the starting time for accumulating a balance that
1052 * counts towards the limit.
1053 */
1054 le->_le.le_refill.le_last_refill = mach_absolute_time();
1055 ledger_zero_balance(ledger, entry);
1056
1057 flag_set(&le->le_flags, LF_REFILL_SCHEDULED);
1058
1059 return (KERN_SUCCESS);
1060 }
1061
1062 /*
1063 * Disable automatic refill.
1064 */
1065 kern_return_t
1066 ledger_disable_refill(ledger_t ledger, int entry)
1067 {
1068 struct ledger_entry *le;
1069
1070 if (!ENTRY_VALID(ledger, entry))
1071 return (KERN_INVALID_VALUE);
1072
1073 le = &ledger->l_entries[entry];
1074
1075 flag_clear(&le->le_flags, LF_REFILL_SCHEDULED);
1076
1077 return (KERN_SUCCESS);
1078 }
1079
1080 kern_return_t
1081 ledger_get_actions(ledger_t ledger, int entry, int *actions)
1082 {
1083 if (!ENTRY_VALID(ledger, entry))
1084 return (KERN_INVALID_VALUE);
1085
1086 *actions = ledger->l_entries[entry].le_flags & LEDGER_ACTION_MASK;
1087 lprintf(("ledger_get_actions: %#x\n", *actions));
1088 return (KERN_SUCCESS);
1089 }
1090
1091 kern_return_t
1092 ledger_set_action(ledger_t ledger, int entry, int action)
1093 {
1094 lprintf(("ledger_set_action: %#x\n", action));
1095 if (!ENTRY_VALID(ledger, entry))
1096 return (KERN_INVALID_VALUE);
1097
1098 flag_set(&ledger->l_entries[entry].le_flags, action);
1099 return (KERN_SUCCESS);
1100 }
1101
1102 void
1103 set_astledger(thread_t thread)
1104 {
1105 spl_t s = splsched();
1106
1107 if (thread == current_thread()) {
1108 thread_ast_set(thread, AST_LEDGER);
1109 ast_propagate(thread->ast);
1110 } else {
1111 processor_t p;
1112
1113 thread_lock(thread);
1114 thread_ast_set(thread, AST_LEDGER);
1115 p = thread->last_processor;
1116 if ((p != PROCESSOR_NULL) && (p->state == PROCESSOR_RUNNING) &&
1117 (p->active_thread == thread))
1118 cause_ast_check(p);
1119 thread_unlock(thread);
1120 }
1121
1122 splx(s);
1123 }
1124
1125 kern_return_t
1126 ledger_debit(ledger_t ledger, int entry, ledger_amount_t amount)
1127 {
1128 struct ledger_entry *le;
1129 ledger_amount_t old, new;
1130
1131 if (!ENTRY_VALID(ledger, entry) || (amount < 0))
1132 return (KERN_INVALID_ARGUMENT);
1133
1134 if (amount == 0)
1135 return (KERN_SUCCESS);
1136
1137 le = &ledger->l_entries[entry];
1138
1139 old = OSAddAtomic64(amount, &le->le_debit);
1140 new = old + amount;
1141
1142 lprintf(("%p Debit %lld->%lld\n", thread, old, new));
1143 ledger_check_new_balance(ledger, entry);
1144 return (KERN_SUCCESS);
1145
1146 }
1147
1148 void
1149 ledger_ast(thread_t thread)
1150 {
1151 struct ledger *l = thread->t_ledger;
1152 struct ledger *thl;
1153 uint32_t block;
1154 uint64_t now;
1155 uint8_t task_flags;
1156 uint8_t task_percentage;
1157 uint64_t task_interval;
1158
1159 kern_return_t ret;
1160 task_t task = thread->task;
1161
1162 lprintf(("Ledger AST for %p\n", thread));
1163
1164 ASSERT(task != NULL);
1165 ASSERT(thread == current_thread());
1166
1167 top:
1168 /*
1169 * Take a self-consistent snapshot of the CPU usage monitor parameters. The task
1170 * can change them at any point (with the task locked).
1171 */
1172 task_lock(task);
1173 task_flags = task->rusage_cpu_flags;
1174 task_percentage = task->rusage_cpu_perthr_percentage;
1175 task_interval = task->rusage_cpu_perthr_interval;
1176 task_unlock(task);
1177
1178 /*
1179 * Make sure this thread is up to date with regards to any task-wide per-thread
1180 * CPU limit, but only if it doesn't have a thread-private blocking CPU limit.
1181 */
1182 if (((task_flags & TASK_RUSECPU_FLAGS_PERTHR_LIMIT) != 0) &&
1183 ((thread->options & TH_OPT_PRVT_CPULIMIT) == 0)) {
1184 uint8_t percentage;
1185 uint64_t interval;
1186 int action;
1187
1188 thread_get_cpulimit(&action, &percentage, &interval);
1189
1190 /*
1191 * If the thread's CPU limits no longer match the task's, or the
1192 * task has a limit but the thread doesn't, update the limit.
1193 */
1194 if (((thread->options & TH_OPT_PROC_CPULIMIT) == 0) ||
1195 (interval != task_interval) || (percentage != task_percentage)) {
1196 thread_set_cpulimit(THREAD_CPULIMIT_EXCEPTION, task_percentage, task_interval);
1197 assert((thread->options & TH_OPT_PROC_CPULIMIT) != 0);
1198 }
1199 } else if (((task_flags & TASK_RUSECPU_FLAGS_PERTHR_LIMIT) == 0) &&
1200 (thread->options & TH_OPT_PROC_CPULIMIT)) {
1201 assert((thread->options & TH_OPT_PRVT_CPULIMIT) == 0);
1202
1203 /*
1204 * Task no longer has a per-thread CPU limit; remove this thread's
1205 * corresponding CPU limit.
1206 */
1207 thread_set_cpulimit(THREAD_CPULIMIT_DISABLE, 0, 0);
1208 assert((thread->options & TH_OPT_PROC_CPULIMIT) == 0);
1209 }
1210
1211 /*
1212 * If the task or thread is being terminated, let's just get on with it
1213 */
1214 if ((l == NULL) || !task->active || task->halting || !thread->active)
1215 return;
1216
1217 /*
1218 * Examine all entries in deficit to see which might be eligble for
1219 * an automatic refill, which require callbacks to be issued, and
1220 * which require blocking.
1221 */
1222 block = 0;
1223 now = mach_absolute_time();
1224
1225 /*
1226 * Note that thread->t_threadledger may have been changed by the
1227 * thread_set_cpulimit() call above - so don't examine it until afterwards.
1228 */
1229 thl = thread->t_threadledger;
1230 if (LEDGER_VALID(thl)) {
1231 block |= ledger_check_needblock(thl, now);
1232 }
1233 block |= ledger_check_needblock(l, now);
1234
1235 /*
1236 * If we are supposed to block on the availability of one or more
1237 * resources, find the first entry in deficit for which we should wait.
1238 * Schedule a refill if necessary and then sleep until the resource
1239 * becomes available.
1240 */
1241 if (block) {
1242 if (LEDGER_VALID(thl)) {
1243 ret = ledger_perform_blocking(thl);
1244 if (ret != KERN_SUCCESS)
1245 goto top;
1246 }
1247 ret = ledger_perform_blocking(l);
1248 if (ret != KERN_SUCCESS)
1249 goto top;
1250 } /* block */
1251 }
1252
1253 static uint32_t
1254 ledger_check_needblock(ledger_t l, uint64_t now)
1255 {
1256 int i;
1257 uint32_t flags, block = 0;
1258 struct ledger_entry *le;
1259 struct ledger_callback *lc;
1260
1261
1262 for (i = 0; i < l->l_size; i++) {
1263 le = &l->l_entries[i];
1264
1265 lc = entry_get_callback(l, i);
1266
1267 if (limit_exceeded(le) == FALSE) {
1268 if (le->le_flags & LEDGER_ACTION_CALLBACK) {
1269 /*
1270 * If needed, invoke the callback as a warning.
1271 * This needs to happen both when the balance rises above
1272 * the warning level, and also when it dips back below it.
1273 */
1274 assert(lc != NULL);
1275 /*
1276 * See comments for matching logic in ledger_check_new_balance().
1277 */
1278 if (warn_level_exceeded(le)) {
1279 flags = flag_set(&le->le_flags, LF_WARNED);
1280 if ((flags & LF_WARNED) == 0) {
1281 lc->lc_func(LEDGER_WARNING_ROSE_ABOVE, lc->lc_param0, lc->lc_param1);
1282 }
1283 } else {
1284 flags = flag_clear(&le->le_flags, LF_WARNED);
1285 if (flags & LF_WARNED) {
1286 lc->lc_func(LEDGER_WARNING_DIPPED_BELOW, lc->lc_param0, lc->lc_param1);
1287 }
1288 }
1289 }
1290
1291 continue;
1292 }
1293
1294 /* We're over the limit, so refill if we are eligible and past due. */
1295 if (le->le_flags & LF_REFILL_SCHEDULED) {
1296 if ((le->_le.le_refill.le_last_refill + le->_le.le_refill.le_refill_period) > now) {
1297 ledger_refill(now, l, i);
1298 if (limit_exceeded(le) == FALSE)
1299 continue;
1300 }
1301 }
1302
1303 if (le->le_flags & LEDGER_ACTION_BLOCK)
1304 block = 1;
1305 if ((le->le_flags & LEDGER_ACTION_CALLBACK) == 0)
1306 continue;
1307
1308 /*
1309 * If the LEDGER_ACTION_CALLBACK flag is on, we expect there to
1310 * be a registered callback.
1311 */
1312 assert(lc != NULL);
1313 flags = flag_set(&le->le_flags, LF_CALLED_BACK);
1314 /* Callback has already been called */
1315 if (flags & LF_CALLED_BACK)
1316 continue;
1317 lc->lc_func(FALSE, lc->lc_param0, lc->lc_param1);
1318 }
1319 return(block);
1320 }
1321
1322
1323 /* return KERN_SUCCESS to continue, KERN_FAILURE to restart */
1324 static kern_return_t
1325 ledger_perform_blocking(ledger_t l)
1326 {
1327 int i;
1328 kern_return_t ret;
1329 struct ledger_entry *le;
1330
1331 for (i = 0; i < l->l_size; i++) {
1332 le = &l->l_entries[i];
1333 if ((!limit_exceeded(le)) ||
1334 ((le->le_flags & LEDGER_ACTION_BLOCK) == 0))
1335 continue;
1336
1337 /* Prepare to sleep until the resource is refilled */
1338 ret = assert_wait_deadline(le, TRUE,
1339 le->_le.le_refill.le_last_refill + le->_le.le_refill.le_refill_period);
1340 if (ret != THREAD_WAITING)
1341 return(KERN_SUCCESS);
1342
1343 /* Mark that somebody is waiting on this entry */
1344 flag_set(&le->le_flags, LF_WAKE_NEEDED);
1345
1346 ret = thread_block_reason(THREAD_CONTINUE_NULL, NULL,
1347 AST_LEDGER);
1348 if (ret != THREAD_AWAKENED)
1349 return(KERN_SUCCESS);
1350
1351 /*
1352 * The world may have changed while we were asleep.
1353 * Some other resource we need may have gone into
1354 * deficit. Or maybe we're supposed to die now.
1355 * Go back to the top and reevaluate.
1356 */
1357 return(KERN_FAILURE);
1358 }
1359 return(KERN_SUCCESS);
1360 }
1361
1362
1363 kern_return_t
1364 ledger_get_entries(ledger_t ledger, int entry, ledger_amount_t *credit,
1365 ledger_amount_t *debit)
1366 {
1367 struct ledger_entry *le;
1368
1369 if (!ENTRY_VALID(ledger, entry))
1370 return (KERN_INVALID_ARGUMENT);
1371
1372 le = &ledger->l_entries[entry];
1373
1374 *credit = le->le_credit;
1375 *debit = le->le_debit;
1376
1377 return (KERN_SUCCESS);
1378 }
1379
1380 kern_return_t
1381 ledger_get_balance(ledger_t ledger, int entry, ledger_amount_t *balance)
1382 {
1383 struct ledger_entry *le;
1384
1385 if (!ENTRY_VALID(ledger, entry))
1386 return (KERN_INVALID_ARGUMENT);
1387
1388 le = &ledger->l_entries[entry];
1389
1390 assert((le->le_credit >= 0) && (le->le_debit >= 0));
1391
1392 *balance = le->le_credit - le->le_debit;
1393
1394 return (KERN_SUCCESS);
1395 }
1396
1397 int
1398 ledger_template_info(void **buf, int *len)
1399 {
1400 struct ledger_template_info *lti;
1401 struct entry_template *et;
1402 int i;
1403 ledger_t l;
1404
1405 /*
1406 * Since all tasks share a ledger template, we'll just use the
1407 * caller's as the source.
1408 */
1409 l = current_task()->ledger;
1410 if ((*len < 0) || (l == NULL))
1411 return (EINVAL);
1412
1413 if (*len > l->l_size)
1414 *len = l->l_size;
1415 lti = kalloc((*len) * sizeof (struct ledger_template_info));
1416 if (lti == NULL)
1417 return (ENOMEM);
1418 *buf = lti;
1419
1420 template_lock(l->l_template);
1421 et = l->l_template->lt_entries;
1422
1423 for (i = 0; i < *len; i++) {
1424 memset(lti, 0, sizeof (*lti));
1425 strlcpy(lti->lti_name, et->et_key, LEDGER_NAME_MAX);
1426 strlcpy(lti->lti_group, et->et_group, LEDGER_NAME_MAX);
1427 strlcpy(lti->lti_units, et->et_units, LEDGER_NAME_MAX);
1428 et++;
1429 lti++;
1430 }
1431 template_unlock(l->l_template);
1432
1433 return (0);
1434 }
1435
1436 static void
1437 ledger_fill_entry_info(struct ledger_entry *le,
1438 struct ledger_entry_info *lei,
1439 uint64_t now)
1440 {
1441 assert(le != NULL);
1442 assert(lei != NULL);
1443
1444 memset(lei, 0, sizeof (*lei));
1445
1446 lei->lei_limit = le->le_limit;
1447 lei->lei_credit = le->le_credit;
1448 lei->lei_debit = le->le_debit;
1449 lei->lei_balance = lei->lei_credit - lei->lei_debit;
1450 lei->lei_refill_period = (le->le_flags & LF_REFILL_SCHEDULED) ?
1451 abstime_to_nsecs(le->_le.le_refill.le_refill_period) : 0;
1452 lei->lei_last_refill = abstime_to_nsecs(now - le->_le.le_refill.le_last_refill);
1453 }
1454
1455 int
1456 ledger_get_task_entry_info_multiple(task_t task, void **buf, int *len)
1457 {
1458 struct ledger_entry_info *lei;
1459 struct ledger_entry *le;
1460 uint64_t now = mach_absolute_time();
1461 int i;
1462 ledger_t l;
1463
1464 if ((*len < 0) || ((l = task->ledger) == NULL))
1465 return (EINVAL);
1466
1467 if (*len > l->l_size)
1468 *len = l->l_size;
1469 lei = kalloc((*len) * sizeof (struct ledger_entry_info));
1470 if (lei == NULL)
1471 return (ENOMEM);
1472 *buf = lei;
1473
1474 le = l->l_entries;
1475
1476 for (i = 0; i < *len; i++) {
1477 ledger_fill_entry_info(le, lei, now);
1478 le++;
1479 lei++;
1480 }
1481
1482 return (0);
1483 }
1484
1485 void
1486 ledger_get_entry_info(ledger_t ledger,
1487 int entry,
1488 struct ledger_entry_info *lei)
1489 {
1490 uint64_t now = mach_absolute_time();
1491
1492 assert(ledger != NULL);
1493 assert(lei != NULL);
1494 assert(entry < ledger->l_size);
1495
1496 struct ledger_entry *le = &ledger->l_entries[entry];
1497
1498 ledger_fill_entry_info(le, lei, now);
1499 }
1500
1501 int
1502 ledger_info(task_t task, struct ledger_info *info)
1503 {
1504 ledger_t l;
1505
1506 if ((l = task->ledger) == NULL)
1507 return (ENOENT);
1508
1509 memset(info, 0, sizeof (*info));
1510
1511 strlcpy(info->li_name, l->l_template->lt_name, LEDGER_NAME_MAX);
1512 info->li_id = l->l_id;
1513 info->li_entries = l->l_size;
1514 return (0);
1515 }
1516
1517 #ifdef LEDGER_DEBUG
1518 int
1519 ledger_limit(task_t task, struct ledger_limit_args *args)
1520 {
1521 ledger_t l;
1522 int64_t limit;
1523 int idx;
1524
1525 if ((l = task->ledger) == NULL)
1526 return (EINVAL);
1527
1528 idx = ledger_key_lookup(l->l_template, args->lla_name);
1529 if ((idx < 0) || (idx >= l->l_size))
1530 return (EINVAL);
1531
1532 /*
1533 * XXX - this doesn't really seem like the right place to have
1534 * a context-sensitive conversion of userspace units into kernel
1535 * units. For now I'll handwave and say that the ledger() system
1536 * call isn't meant for civilians to use - they should be using
1537 * the process policy interfaces.
1538 */
1539 if (idx == task_ledgers.cpu_time) {
1540 int64_t nsecs;
1541
1542 if (args->lla_refill_period) {
1543 /*
1544 * If a refill is scheduled, then the limit is
1545 * specified as a percentage of one CPU. The
1546 * syscall specifies the refill period in terms of
1547 * milliseconds, so we need to convert to nsecs.
1548 */
1549 args->lla_refill_period *= 1000000;
1550 nsecs = args->lla_limit *
1551 (args->lla_refill_period / 100);
1552 lprintf(("CPU limited to %lld nsecs per second\n",
1553 nsecs));
1554 } else {
1555 /*
1556 * If no refill is scheduled, then this is a
1557 * fixed amount of CPU time (in nsecs) that can
1558 * be consumed.
1559 */
1560 nsecs = args->lla_limit;
1561 lprintf(("CPU limited to %lld nsecs\n", nsecs));
1562 }
1563 limit = nsecs_to_abstime(nsecs);
1564 } else {
1565 limit = args->lla_limit;
1566 lprintf(("%s limited to %lld\n", args->lla_name, limit));
1567 }
1568
1569 if (args->lla_refill_period > 0)
1570 ledger_set_period(l, idx, args->lla_refill_period);
1571
1572 ledger_set_limit(l, idx, limit);
1573 flag_set(&l->l_entries[idx].le_flags, LEDGER_ACTION_BLOCK);
1574 return (0);
1575 }
1576 #endif