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