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