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