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