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