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