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