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