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