2 * Copyright (c) 2010 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
32 #include <kern/lock.h>
33 #include <kern/ledger.h>
34 #include <kern/kalloc.h>
35 #include <kern/task.h>
37 #include <kern/processor.h>
38 #include <kern/machine.h>
39 #include <kern/queue.h>
40 #include <sys/errno.h>
42 #include <libkern/OSAtomic.h>
43 #include <mach/mach_types.h>
46 * Ledger entry flags. Bits in second nibble (masked by 0xF0) are used for
47 * ledger actions (LEDGER_ACTION_BLOCK, etc).
49 #define LF_ENTRY_ACTIVE 0x0001 /* entry is active if set */
50 #define LF_WAKE_NEEDED 0x0100 /* one or more threads are asleep */
51 #define LF_WAKE_INPROGRESS 0x0200 /* the wait queue is being processed */
52 #define LF_REFILL_SCHEDULED 0x0400 /* a refill timer has been set */
53 #define LF_REFILL_INPROGRESS 0x0800 /* the ledger is being refilled */
54 #define LF_CALLED_BACK 0x1000 /* callback was called for balance in deficit */
55 #define LF_WARNED 0x2000 /* callback was called for balance warning */
56 #define LF_TRACKING_MAX 0x4000 /* track max balance over user-specfied time */
58 /* Determine whether a ledger entry exists and has been initialized and active */
59 #define ENTRY_VALID(l, e) \
60 (((l) != NULL) && ((e) >= 0) && ((e) < (l)->l_size) && \
61 (((l)->l_entries[e].le_flags & LF_ENTRY_ACTIVE) == LF_ENTRY_ACTIVE))
66 #define ASSERT(a) assert(a)
67 #define lprintf(a) if (ledger_debug) { \
68 printf("%lld ", abstime_to_nsecs(mach_absolute_time() / 1000000)); \
76 struct ledger_callback
{
77 ledger_callback_t lc_func
;
78 const void *lc_param0
;
79 const void *lc_param1
;
82 struct entry_template
{
83 char et_key
[LEDGER_NAME_MAX
];
84 char et_group
[LEDGER_NAME_MAX
];
85 char et_units
[LEDGER_NAME_MAX
];
87 struct ledger_callback
*et_callback
;
90 lck_grp_t ledger_lck_grp
;
93 * Modifying the reference count, table size, or table contents requires
94 * holding the lt_lock. Modfying the table address requires both lt_lock
95 * and setting the inuse bit. This means that the lt_entries field can be
96 * safely dereferenced if you hold either the lock or the inuse bit. The
97 * inuse bit exists solely to allow us to swap in a new, larger entries
98 * table without requiring a full lock to be acquired on each lookup.
99 * Accordingly, the inuse bit should never be held for longer than it takes
100 * to extract a value from the table - i.e., 2 or 3 memory references.
102 struct ledger_template
{
107 volatile uint32_t lt_inuse
;
109 struct entry_template
*lt_entries
;
112 #define template_lock(template) lck_mtx_lock(&(template)->lt_lock)
113 #define template_unlock(template) lck_mtx_unlock(&(template)->lt_lock)
115 #define TEMPLATE_INUSE(s, t) { \
117 while (OSCompareAndSwap(0, 1, &((t)->lt_inuse))) \
121 #define TEMPLATE_IDLE(s, t) { \
127 * Use 2 "tocks" to track the rolling maximum balance of a ledger entry.
131 * The explicit alignment is to ensure that atomic operations don't panic
134 struct ledger_entry
{
135 volatile uint32_t le_flags
;
136 ledger_amount_t le_limit
;
137 ledger_amount_t le_warn_level
;
138 volatile ledger_amount_t le_credit
__attribute__((aligned(8)));
139 volatile ledger_amount_t le_debit
__attribute__((aligned(8)));
143 * XXX - the following two fields can go away if we move all of
144 * the refill logic into process policy
146 uint64_t le_refill_period
;
147 uint64_t le_last_refill
;
150 uint32_t le_max
; /* Lower 32-bits of observed max balance */
151 uint32_t le_time
; /* time when this peak was observed */
154 } __attribute__((aligned(8)));
158 struct ledger_template
*l_template
;
161 struct ledger_entry
*l_entries
;
164 static int ledger_cnt
= 0;
165 /* ledger ast helper functions */
166 static uint32_t ledger_check_needblock(ledger_t l
, uint64_t now
);
167 static kern_return_t
ledger_perform_blocking(ledger_t l
);
168 static uint32_t flag_set(volatile uint32_t *flags
, uint32_t bit
);
169 static uint32_t flag_clear(volatile uint32_t *flags
, uint32_t bit
);
173 debug_callback(const void *p0
, __unused
const void *p1
)
175 printf("ledger: resource exhausted [%s] for task %p\n",
176 (const char *)p0
, p1
);
180 /************************************/
183 abstime_to_nsecs(uint64_t abstime
)
187 absolutetime_to_nanoseconds(abstime
, &nsecs
);
192 nsecs_to_abstime(uint64_t nsecs
)
196 nanoseconds_to_absolutetime(nsecs
, &abstime
);
203 lck_grp_init(&ledger_lck_grp
, "ledger", LCK_GRP_ATTR_NULL
);
207 ledger_template_create(const char *name
)
209 ledger_template_t
template;
211 template = (ledger_template_t
)kalloc(sizeof (*template));
212 if (template == NULL
)
215 template->lt_name
= name
;
216 template->lt_refs
= 1;
217 template->lt_cnt
= 0;
218 template->lt_table_size
= 1;
219 template->lt_inuse
= 0;
220 lck_mtx_init(&template->lt_lock
, &ledger_lck_grp
, LCK_ATTR_NULL
);
222 template->lt_entries
= (struct entry_template
*)
223 kalloc(sizeof (struct entry_template
) * template->lt_table_size
);
224 if (template->lt_entries
== NULL
) {
225 kfree(template, sizeof (*template));
233 ledger_template_dereference(ledger_template_t
template)
235 template_lock(template);
237 template_unlock(template);
239 if (template->lt_refs
== 0)
240 kfree(template, sizeof (*template));
244 * Add a new entry to the list of entries in a ledger template. There is
245 * currently no mechanism to remove an entry. Implementing such a mechanism
246 * would require us to maintain per-entry reference counts, which we would
247 * prefer to avoid if possible.
250 ledger_entry_add(ledger_template_t
template, const char *key
,
251 const char *group
, const char *units
)
254 struct entry_template
*et
;
256 if ((key
== NULL
) || (strlen(key
) >= LEDGER_NAME_MAX
))
259 template_lock(template);
261 /* If the table is full, attempt to double its size */
262 if (template->lt_cnt
== template->lt_table_size
) {
263 struct entry_template
*new_entries
, *old_entries
;
267 old_cnt
= template->lt_table_size
;
268 old_sz
= (int)(old_cnt
* sizeof (struct entry_template
));
269 new_entries
= kalloc(old_sz
* 2);
270 if (new_entries
== NULL
) {
271 template_unlock(template);
274 memcpy(new_entries
, template->lt_entries
, old_sz
);
275 memset(((char *)new_entries
) + old_sz
, 0, old_sz
);
276 template->lt_table_size
= old_cnt
* 2;
278 old_entries
= template->lt_entries
;
280 TEMPLATE_INUSE(s
, template);
281 template->lt_entries
= new_entries
;
282 TEMPLATE_IDLE(s
, template);
284 kfree(old_entries
, old_sz
);
287 et
= &template->lt_entries
[template->lt_cnt
];
288 strlcpy(et
->et_key
, key
, LEDGER_NAME_MAX
);
289 strlcpy(et
->et_group
, group
, LEDGER_NAME_MAX
);
290 strlcpy(et
->et_units
, units
, LEDGER_NAME_MAX
);
291 et
->et_flags
= LF_ENTRY_ACTIVE
;
292 et
->et_callback
= NULL
;
294 idx
= template->lt_cnt
++;
295 template_unlock(template);
302 ledger_entry_setactive(ledger_t ledger
, int entry
)
304 struct ledger_entry
*le
;
306 if ((ledger
== NULL
) || (entry
< 0) || (entry
>= ledger
->l_size
))
307 return (KERN_INVALID_ARGUMENT
);
309 le
= &ledger
->l_entries
[entry
];
310 if ((le
->le_flags
& LF_ENTRY_ACTIVE
) == 0) {
311 flag_set(&le
->le_flags
, LF_ENTRY_ACTIVE
);
313 return (KERN_SUCCESS
);
318 ledger_key_lookup(ledger_template_t
template, const char *key
)
322 template_lock(template);
323 for (idx
= 0; idx
< template->lt_cnt
; idx
++)
324 if (template->lt_entries
[idx
].et_key
&&
325 (strcmp(key
, template->lt_entries
[idx
].et_key
) == 0))
328 if (idx
>= template->lt_cnt
)
330 template_unlock(template);
336 * Create a new ledger based on the specified template. As part of the
337 * ledger creation we need to allocate space for a table of ledger entries.
338 * The size of the table is based on the size of the template at the time
339 * the ledger is created. If additional entries are added to the template
340 * after the ledger is created, they will not be tracked in this ledger.
343 ledger_instantiate(ledger_template_t
template, int entry_type
)
349 ledger
= (ledger_t
)kalloc(sizeof (struct ledger
));
351 return (LEDGER_NULL
);
353 ledger
->l_template
= template;
354 ledger
->l_id
= ledger_cnt
++;
357 template_lock(template);
359 ledger
->l_size
= template->lt_cnt
;
360 template_unlock(template);
362 sz
= ledger
->l_size
* sizeof (struct ledger_entry
);
363 ledger
->l_entries
= kalloc(sz
);
364 if (sz
&& (ledger
->l_entries
== NULL
)) {
365 ledger_template_dereference(template);
366 kfree(ledger
, sizeof(struct ledger
));
367 return (LEDGER_NULL
);
370 template_lock(template);
371 assert(ledger
->l_size
<= template->lt_cnt
);
372 for (i
= 0; i
< ledger
->l_size
; i
++) {
373 struct ledger_entry
*le
= &ledger
->l_entries
[i
];
374 struct entry_template
*et
= &template->lt_entries
[i
];
376 le
->le_flags
= et
->et_flags
;
377 /* make entry inactive by removing active bit */
378 if (entry_type
== LEDGER_CREATE_INACTIVE_ENTRIES
)
379 flag_clear(&le
->le_flags
, LF_ENTRY_ACTIVE
);
381 * If template has a callback, this entry is opted-in,
384 if (et
->et_callback
!= NULL
)
385 flag_set(&le
->le_flags
, LEDGER_ACTION_CALLBACK
);
388 le
->le_limit
= LEDGER_LIMIT_INFINITY
;
389 le
->le_warn_level
= LEDGER_LIMIT_INFINITY
;
390 le
->_le
.le_refill
.le_refill_period
= 0;
391 le
->_le
.le_refill
.le_last_refill
= 0;
393 template_unlock(template);
399 flag_set(volatile uint32_t *flags
, uint32_t bit
)
401 return (OSBitOrAtomic(bit
, flags
));
405 flag_clear(volatile uint32_t *flags
, uint32_t bit
)
407 return (OSBitAndAtomic(~bit
, flags
));
411 * Take a reference on a ledger
414 ledger_reference(ledger_t ledger
)
416 if (!LEDGER_VALID(ledger
))
417 return (KERN_INVALID_ARGUMENT
);
418 OSIncrementAtomic(&ledger
->l_refs
);
419 return (KERN_SUCCESS
);
423 ledger_reference_count(ledger_t ledger
)
425 if (!LEDGER_VALID(ledger
))
428 return (ledger
->l_refs
);
432 * Remove a reference on a ledger. If this is the last reference,
433 * deallocate the unused ledger.
436 ledger_dereference(ledger_t ledger
)
440 if (!LEDGER_VALID(ledger
))
441 return (KERN_INVALID_ARGUMENT
);
443 v
= OSDecrementAtomic(&ledger
->l_refs
);
446 /* Just released the last reference. Free it. */
448 kfree(ledger
->l_entries
,
449 ledger
->l_size
* sizeof (struct ledger_entry
));
450 kfree(ledger
, sizeof (*ledger
));
453 return (KERN_SUCCESS
);
457 * Determine whether an entry has exceeded its warning level.
460 warn_level_exceeded(struct ledger_entry
*le
)
462 ledger_amount_t balance
;
464 assert((le
->le_credit
>= 0) && (le
->le_debit
>= 0));
467 * XXX - Currently, we only support warnings for ledgers which
468 * use positive limits.
470 balance
= le
->le_credit
- le
->le_debit
;
471 if ((le
->le_warn_level
!= LEDGER_LIMIT_INFINITY
) && (balance
> le
->le_warn_level
))
477 * Determine whether an entry has exceeded its limit.
480 limit_exceeded(struct ledger_entry
*le
)
482 ledger_amount_t balance
;
484 assert((le
->le_credit
>= 0) && (le
->le_debit
>= 0));
486 balance
= le
->le_credit
- le
->le_debit
;
487 if ((le
->le_limit
<= 0) && (balance
< le
->le_limit
))
490 if ((le
->le_limit
> 0) && (balance
> le
->le_limit
))
495 static inline struct ledger_callback
*
496 entry_get_callback(ledger_t ledger
, int entry
)
498 struct ledger_callback
*callback
;
501 TEMPLATE_INUSE(s
, ledger
->l_template
);
502 callback
= ledger
->l_template
->lt_entries
[entry
].et_callback
;
503 TEMPLATE_IDLE(s
, ledger
->l_template
);
509 * If the ledger value is positive, wake up anybody waiting on it.
512 ledger_limit_entry_wakeup(struct ledger_entry
*le
)
516 if (!limit_exceeded(le
)) {
517 flags
= flag_clear(&le
->le_flags
, LF_CALLED_BACK
);
519 while (le
->le_flags
& LF_WAKE_NEEDED
) {
520 flag_clear(&le
->le_flags
, LF_WAKE_NEEDED
);
521 thread_wakeup((event_t
)le
);
527 * Refill the coffers.
530 ledger_refill(uint64_t now
, ledger_t ledger
, int entry
)
532 uint64_t elapsed
, period
, periods
;
533 struct ledger_entry
*le
;
534 ledger_amount_t balance
, due
;
536 le
= &ledger
->l_entries
[entry
];
538 assert(le
->le_limit
!= LEDGER_LIMIT_INFINITY
);
541 * If another thread is handling the refill already, we're not
544 if (flag_set(&le
->le_flags
, LF_REFILL_INPROGRESS
) & LF_REFILL_INPROGRESS
) {
549 * If the timestamp we're about to use to refill is older than the
550 * last refill, then someone else has already refilled this ledger
551 * and there's nothing for us to do here.
553 if (now
<= le
->_le
.le_refill
.le_last_refill
) {
554 flag_clear(&le
->le_flags
, LF_REFILL_INPROGRESS
);
559 * See how many refill periods have passed since we last
562 period
= le
->_le
.le_refill
.le_refill_period
;
563 elapsed
= now
- le
->_le
.le_refill
.le_last_refill
;
564 if ((period
== 0) || (elapsed
< period
)) {
565 flag_clear(&le
->le_flags
, LF_REFILL_INPROGRESS
);
570 * Optimize for the most common case of only one or two
574 while ((periods
< 2) && (elapsed
> 0)) {
580 * OK, it's been a long time. Do a divide to figure out
584 periods
= (now
- le
->_le
.le_refill
.le_last_refill
) / period
;
586 balance
= le
->le_credit
- le
->le_debit
;
587 due
= periods
* le
->le_limit
;
588 if (balance
- due
< 0)
593 OSAddAtomic64(due
, &le
->le_debit
);
595 assert(le
->le_debit
>= 0);
598 * If we've completely refilled the pool, set the refill time to now.
599 * Otherwise set it to the time at which it last should have been
603 le
->_le
.le_refill
.le_last_refill
= now
;
605 le
->_le
.le_refill
.le_last_refill
+= (le
->_le
.le_refill
.le_refill_period
* periods
);
607 flag_clear(&le
->le_flags
, LF_REFILL_INPROGRESS
);
609 lprintf(("Refill %lld %lld->%lld\n", periods
, balance
, balance
- due
));
610 if (!limit_exceeded(le
))
611 ledger_limit_entry_wakeup(le
);
615 * In tenths of a second, the length of one lookback period (a "tock") for
616 * ledger rolling maximum calculations. The effective lookback window will be this times
619 * Use a tock length of 2.5 seconds to get a total lookback period of 5 seconds.
621 * XXX Could make this caller-definable, at the point that rolling max tracking
622 * is enabled for the entry.
627 * How many sched_tick's are there in one tock (one of our lookback periods)?
629 * X sched_ticks 2.5 sec N sched_ticks
630 * --------------- = ---------- * -------------
633 * where N sched_ticks/sec is calculated via 1 << SCHED_TICK_SHIFT (see sched_prim.h)
635 * This should give us 20 sched_tick's in one 2.5 second-long tock.
637 #define SCHED_TICKS_PER_TOCK ((TOCKLEN * (1 << SCHED_TICK_SHIFT)) / 10)
640 * Rolling max timestamps use their own unit (let's call this a "tock"). One tock is the
641 * length of one lookback period that we use for our rolling max calculation.
643 * Calculate the current time in tocks from sched_tick (which runs at a some
646 #define CURRENT_TOCKSTAMP() (sched_tick / SCHED_TICKS_PER_TOCK)
649 * Does the given tockstamp fall in either the current or the previous tocks?
651 #define TOCKSTAMP_IS_STALE(now, tock) ((((now) - (tock)) < NTOCKS) ? FALSE : TRUE)
654 ledger_check_new_balance(ledger_t ledger
, int entry
)
656 struct ledger_entry
*le
;
658 le
= &ledger
->l_entries
[entry
];
660 if (le
->le_flags
& LF_TRACKING_MAX
) {
661 ledger_amount_t balance
= le
->le_credit
- le
->le_debit
;
662 uint32_t now
= CURRENT_TOCKSTAMP();
663 struct _le_peak
*p
= &le
->_le
.le_peaks
[now
% NTOCKS
];
665 if (!TOCKSTAMP_IS_STALE(now
, p
->le_time
) || (balance
> p
->le_max
)) {
667 * The current balance is greater than the previously
668 * observed peak for the current time block, *or* we
669 * haven't yet recorded a peak for the current time block --
670 * so this is our new peak.
672 * (We only track the lower 32-bits of a balance for rolling
675 p
->le_max
= (uint32_t)balance
;
680 /* Check to see whether we're due a refill */
681 if (le
->le_flags
& LF_REFILL_SCHEDULED
) {
682 uint64_t now
= mach_absolute_time();
683 if ((now
- le
->_le
.le_refill
.le_last_refill
) > le
->_le
.le_refill
.le_refill_period
)
684 ledger_refill(now
, ledger
, entry
);
687 if (limit_exceeded(le
)) {
689 * We've exceeded the limit for this entry. There
690 * are several possible ways to handle it. We can block,
691 * we can execute a callback, or we can ignore it. In
692 * either of the first two cases, we want to set the AST
693 * flag so we can take the appropriate action just before
694 * leaving the kernel. The one caveat is that if we have
695 * already called the callback, we don't want to do it
696 * again until it gets rearmed.
698 if ((le
->le_flags
& LEDGER_ACTION_BLOCK
) ||
699 (!(le
->le_flags
& LF_CALLED_BACK
) &&
700 entry_get_callback(ledger
, entry
))) {
701 set_astledger(current_thread());
705 * The balance on the account is below the limit.
707 * If there are any threads blocked on this entry, now would
708 * be a good time to wake them up.
710 if (le
->le_flags
& LF_WAKE_NEEDED
)
711 ledger_limit_entry_wakeup(le
);
713 if (le
->le_flags
& LEDGER_ACTION_CALLBACK
) {
715 * Client has requested that a callback be invoked whenever
716 * the ledger's balance crosses into or out of the warning
719 if (warn_level_exceeded(le
)) {
721 * This ledger's balance is above the warning level.
723 if ((le
->le_flags
& LF_WARNED
) == 0) {
725 * If we are above the warning level and
726 * have not yet invoked the callback,
727 * set the AST so it can be done before returning
730 set_astledger(current_thread());
734 * This ledger's balance is below the warning level.
736 if (le
->le_flags
& LF_WARNED
) {
738 * If we are below the warning level and
739 * the LF_WARNED flag is still set, we need
740 * to invoke the callback to let the client
741 * know the ledger balance is now back below
744 set_astledger(current_thread());
752 * Add value to an entry in a ledger.
755 ledger_credit(ledger_t ledger
, int entry
, ledger_amount_t amount
)
757 ledger_amount_t old
, new;
758 struct ledger_entry
*le
;
760 if (!ENTRY_VALID(ledger
, entry
) || (amount
< 0))
761 return (KERN_INVALID_VALUE
);
764 return (KERN_SUCCESS
);
766 le
= &ledger
->l_entries
[entry
];
768 old
= OSAddAtomic64(amount
, &le
->le_credit
);
770 lprintf(("%p Credit %lld->%lld\n", current_thread(), old
, new));
771 ledger_check_new_balance(ledger
, entry
);
773 return (KERN_SUCCESS
);
777 * Zero the balance of a ledger by adding to its credit or debit, whichever is smaller.
778 * Note that some clients of ledgers (notably, task wakeup statistics) require that
779 * le_credit only ever increase as a function of ledger_credit().
782 ledger_zero_balance(ledger_t ledger
, int entry
)
784 struct ledger_entry
*le
;
786 if (!ENTRY_VALID(ledger
, entry
))
787 return (KERN_INVALID_VALUE
);
789 le
= &ledger
->l_entries
[entry
];
792 if (le
->le_credit
> le
->le_debit
) {
793 if (!OSCompareAndSwap64(le
->le_debit
, le
->le_credit
, &le
->le_debit
))
795 lprintf(("%p zeroed %lld->%lld\n", current_thread(), le
->le_debit
, le
->le_credit
));
796 } else if (le
->le_credit
< le
->le_debit
) {
797 if (!OSCompareAndSwap64(le
->le_credit
, le
->le_debit
, &le
->le_credit
))
799 lprintf(("%p zeroed %lld->%lld\n", current_thread(), le
->le_credit
, le
->le_debit
));
802 return (KERN_SUCCESS
);
806 ledger_get_limit(ledger_t ledger
, int entry
, ledger_amount_t
*limit
)
808 struct ledger_entry
*le
;
810 if (!ENTRY_VALID(ledger
, entry
))
811 return (KERN_INVALID_VALUE
);
813 le
= &ledger
->l_entries
[entry
];
814 *limit
= le
->le_limit
;
816 lprintf(("ledger_get_limit: %lld\n", *limit
));
818 return (KERN_SUCCESS
);
822 * Adjust the limit of a limited resource. This does not affect the
823 * current balance, so the change doesn't affect the thread until the
826 * warn_level: If non-zero, causes the callback to be invoked when
827 * the balance exceeds this level. Specified as a percentage [of the limit].
830 ledger_set_limit(ledger_t ledger
, int entry
, ledger_amount_t limit
,
831 uint8_t warn_level_percentage
)
833 struct ledger_entry
*le
;
835 if (!ENTRY_VALID(ledger
, entry
))
836 return (KERN_INVALID_VALUE
);
838 lprintf(("ledger_set_limit: %lld\n", limit
));
839 le
= &ledger
->l_entries
[entry
];
841 if (limit
== LEDGER_LIMIT_INFINITY
) {
843 * Caller wishes to disable the limit. This will implicitly
844 * disable automatic refill, as refills implicitly depend
847 ledger_disable_refill(ledger
, entry
);
850 le
->le_limit
= limit
;
851 le
->_le
.le_refill
.le_last_refill
= 0;
852 flag_clear(&le
->le_flags
, LF_CALLED_BACK
);
853 flag_clear(&le
->le_flags
, LF_WARNED
);
854 ledger_limit_entry_wakeup(le
);
856 if (warn_level_percentage
!= 0) {
857 assert(warn_level_percentage
<= 100);
858 assert(limit
> 0); /* no negative limit support for warnings */
859 assert(limit
!= LEDGER_LIMIT_INFINITY
); /* warn % without limit makes no sense */
860 le
->le_warn_level
= (le
->le_limit
* warn_level_percentage
) / 100;
862 le
->le_warn_level
= LEDGER_LIMIT_INFINITY
;
865 return (KERN_SUCCESS
);
869 ledger_get_maximum(ledger_t ledger
, int entry
,
870 ledger_amount_t
*max_observed_balance
)
872 struct ledger_entry
*le
;
873 uint32_t now
= CURRENT_TOCKSTAMP();
876 le
= &ledger
->l_entries
[entry
];
878 if (!ENTRY_VALID(ledger
, entry
) || !(le
->le_flags
& LF_TRACKING_MAX
)) {
879 return (KERN_INVALID_VALUE
);
883 * Start with the current balance; if neither of the recorded peaks are
884 * within recent history, we use this.
886 *max_observed_balance
= le
->le_credit
- le
->le_debit
;
888 for (i
= 0; i
< NTOCKS
; i
++) {
889 if (!TOCKSTAMP_IS_STALE(now
, le
->_le
.le_peaks
[i
].le_time
) &&
890 (le
->_le
.le_peaks
[i
].le_max
> *max_observed_balance
)) {
892 * The peak for this time block isn't stale, and it
893 * is greater than the current balance -- so use it.
895 *max_observed_balance
= le
->_le
.le_peaks
[i
].le_max
;
899 lprintf(("ledger_get_maximum: %lld\n", *max_observed_balance
));
901 return (KERN_SUCCESS
);
905 * Enable tracking of periodic maximums for this ledger entry.
908 ledger_track_maximum(ledger_template_t
template, int entry
,
909 __unused
int period_in_secs
)
911 template_lock(template);
913 if ((entry
< 0) || (entry
>= template->lt_cnt
)) {
914 template_unlock(template);
915 return (KERN_INVALID_VALUE
);
918 template->lt_entries
[entry
].et_flags
|= LF_TRACKING_MAX
;
919 template_unlock(template);
921 return (KERN_SUCCESS
);
925 * Add a callback to be executed when the resource goes into deficit.
928 ledger_set_callback(ledger_template_t
template, int entry
,
929 ledger_callback_t func
, const void *param0
, const void *param1
)
931 struct entry_template
*et
;
932 struct ledger_callback
*old_cb
, *new_cb
;
934 if ((entry
< 0) || (entry
>= template->lt_cnt
))
935 return (KERN_INVALID_VALUE
);
938 new_cb
= (struct ledger_callback
*)kalloc(sizeof (*new_cb
));
939 new_cb
->lc_func
= func
;
940 new_cb
->lc_param0
= param0
;
941 new_cb
->lc_param1
= param1
;
946 template_lock(template);
947 et
= &template->lt_entries
[entry
];
948 old_cb
= et
->et_callback
;
949 et
->et_callback
= new_cb
;
950 template_unlock(template);
952 kfree(old_cb
, sizeof (*old_cb
));
954 return (KERN_SUCCESS
);
958 * Disable callback notification for a specific ledger entry.
960 * Otherwise, if using a ledger template which specified a
961 * callback function (ledger_set_callback()), it will be invoked when
962 * the resource goes into deficit.
965 ledger_disable_callback(ledger_t ledger
, int entry
)
967 if (!ENTRY_VALID(ledger
, entry
))
968 return (KERN_INVALID_VALUE
);
971 * le_warn_level is used to indicate *if* this ledger has a warning configured,
972 * in addition to what that warning level is set to.
973 * This means a side-effect of ledger_disable_callback() is that the
974 * warning level is forgotten.
976 ledger
->l_entries
[entry
].le_warn_level
= LEDGER_LIMIT_INFINITY
;
977 flag_clear(&ledger
->l_entries
[entry
].le_flags
, LEDGER_ACTION_CALLBACK
);
978 return (KERN_SUCCESS
);
982 * Enable callback notification for a specific ledger entry.
984 * This is only needed if ledger_disable_callback() has previously
985 * been invoked against an entry; there must already be a callback
989 ledger_enable_callback(ledger_t ledger
, int entry
)
991 if (!ENTRY_VALID(ledger
, entry
))
992 return (KERN_INVALID_VALUE
);
994 assert(entry_get_callback(ledger
, entry
) != NULL
);
996 flag_set(&ledger
->l_entries
[entry
].le_flags
, LEDGER_ACTION_CALLBACK
);
997 return (KERN_SUCCESS
);
1001 * Query the automatic refill period for this ledger entry.
1003 * A period of 0 means this entry has none configured.
1006 ledger_get_period(ledger_t ledger
, int entry
, uint64_t *period
)
1008 struct ledger_entry
*le
;
1010 if (!ENTRY_VALID(ledger
, entry
))
1011 return (KERN_INVALID_VALUE
);
1013 le
= &ledger
->l_entries
[entry
];
1014 *period
= abstime_to_nsecs(le
->_le
.le_refill
.le_refill_period
);
1015 lprintf(("ledger_get_period: %llx\n", *period
));
1016 return (KERN_SUCCESS
);
1020 * Adjust the automatic refill period.
1023 ledger_set_period(ledger_t ledger
, int entry
, uint64_t period
)
1025 struct ledger_entry
*le
;
1027 lprintf(("ledger_set_period: %llx\n", period
));
1028 if (!ENTRY_VALID(ledger
, entry
))
1029 return (KERN_INVALID_VALUE
);
1031 le
= &ledger
->l_entries
[entry
];
1034 * A refill period refills the ledger in multiples of the limit,
1035 * so if you haven't set one yet, you need a lesson on ledgers.
1037 assert(le
->le_limit
!= LEDGER_LIMIT_INFINITY
);
1039 if (le
->le_flags
& LF_TRACKING_MAX
) {
1041 * Refill is incompatible with rolling max tracking.
1043 return (KERN_INVALID_VALUE
);
1046 le
->_le
.le_refill
.le_refill_period
= nsecs_to_abstime(period
);
1049 * Set the 'starting time' for the next refill to now. Since
1050 * we're resetting the balance to zero here, we consider this
1051 * moment the starting time for accumulating a balance that
1052 * counts towards the limit.
1054 le
->_le
.le_refill
.le_last_refill
= mach_absolute_time();
1055 ledger_zero_balance(ledger
, entry
);
1057 flag_set(&le
->le_flags
, LF_REFILL_SCHEDULED
);
1059 return (KERN_SUCCESS
);
1063 * Disable automatic refill.
1066 ledger_disable_refill(ledger_t ledger
, int entry
)
1068 struct ledger_entry
*le
;
1070 if (!ENTRY_VALID(ledger
, entry
))
1071 return (KERN_INVALID_VALUE
);
1073 le
= &ledger
->l_entries
[entry
];
1075 flag_clear(&le
->le_flags
, LF_REFILL_SCHEDULED
);
1077 return (KERN_SUCCESS
);
1081 ledger_get_actions(ledger_t ledger
, int entry
, int *actions
)
1083 if (!ENTRY_VALID(ledger
, entry
))
1084 return (KERN_INVALID_VALUE
);
1086 *actions
= ledger
->l_entries
[entry
].le_flags
& LEDGER_ACTION_MASK
;
1087 lprintf(("ledger_get_actions: %#x\n", *actions
));
1088 return (KERN_SUCCESS
);
1092 ledger_set_action(ledger_t ledger
, int entry
, int action
)
1094 lprintf(("ledger_set_action: %#x\n", action
));
1095 if (!ENTRY_VALID(ledger
, entry
))
1096 return (KERN_INVALID_VALUE
);
1098 flag_set(&ledger
->l_entries
[entry
].le_flags
, action
);
1099 return (KERN_SUCCESS
);
1103 set_astledger(thread_t thread
)
1105 spl_t s
= splsched();
1107 if (thread
== current_thread()) {
1108 thread_ast_set(thread
, AST_LEDGER
);
1109 ast_propagate(thread
->ast
);
1113 thread_lock(thread
);
1114 thread_ast_set(thread
, AST_LEDGER
);
1115 p
= thread
->last_processor
;
1116 if ((p
!= PROCESSOR_NULL
) && (p
->state
== PROCESSOR_RUNNING
) &&
1117 (p
->active_thread
== thread
))
1119 thread_unlock(thread
);
1126 ledger_debit(ledger_t ledger
, int entry
, ledger_amount_t amount
)
1128 struct ledger_entry
*le
;
1129 ledger_amount_t old
, new;
1131 if (!ENTRY_VALID(ledger
, entry
) || (amount
< 0))
1132 return (KERN_INVALID_ARGUMENT
);
1135 return (KERN_SUCCESS
);
1137 le
= &ledger
->l_entries
[entry
];
1139 old
= OSAddAtomic64(amount
, &le
->le_debit
);
1142 lprintf(("%p Debit %lld->%lld\n", thread
, old
, new));
1143 ledger_check_new_balance(ledger
, entry
);
1144 return (KERN_SUCCESS
);
1149 ledger_ast(thread_t thread
)
1151 struct ledger
*l
= thread
->t_ledger
;
1156 uint8_t task_percentage
;
1157 uint64_t task_interval
;
1160 task_t task
= thread
->task
;
1162 lprintf(("Ledger AST for %p\n", thread
));
1164 ASSERT(task
!= NULL
);
1165 ASSERT(thread
== current_thread());
1169 * Take a self-consistent snapshot of the CPU usage monitor parameters. The task
1170 * can change them at any point (with the task locked).
1173 task_flags
= task
->rusage_cpu_flags
;
1174 task_percentage
= task
->rusage_cpu_perthr_percentage
;
1175 task_interval
= task
->rusage_cpu_perthr_interval
;
1179 * Make sure this thread is up to date with regards to any task-wide per-thread
1180 * CPU limit, but only if it doesn't have a thread-private blocking CPU limit.
1182 if (((task_flags
& TASK_RUSECPU_FLAGS_PERTHR_LIMIT
) != 0) &&
1183 ((thread
->options
& TH_OPT_PRVT_CPULIMIT
) == 0)) {
1188 thread_get_cpulimit(&action
, &percentage
, &interval
);
1191 * If the thread's CPU limits no longer match the task's, or the
1192 * task has a limit but the thread doesn't, update the limit.
1194 if (((thread
->options
& TH_OPT_PROC_CPULIMIT
) == 0) ||
1195 (interval
!= task_interval
) || (percentage
!= task_percentage
)) {
1196 thread_set_cpulimit(THREAD_CPULIMIT_EXCEPTION
, task_percentage
, task_interval
);
1197 assert((thread
->options
& TH_OPT_PROC_CPULIMIT
) != 0);
1199 } else if (((task_flags
& TASK_RUSECPU_FLAGS_PERTHR_LIMIT
) == 0) &&
1200 (thread
->options
& TH_OPT_PROC_CPULIMIT
)) {
1201 assert((thread
->options
& TH_OPT_PRVT_CPULIMIT
) == 0);
1204 * Task no longer has a per-thread CPU limit; remove this thread's
1205 * corresponding CPU limit.
1207 thread_set_cpulimit(THREAD_CPULIMIT_DISABLE
, 0, 0);
1208 assert((thread
->options
& TH_OPT_PROC_CPULIMIT
) == 0);
1212 * If the task or thread is being terminated, let's just get on with it
1214 if ((l
== NULL
) || !task
->active
|| task
->halting
|| !thread
->active
)
1218 * Examine all entries in deficit to see which might be eligble for
1219 * an automatic refill, which require callbacks to be issued, and
1220 * which require blocking.
1223 now
= mach_absolute_time();
1226 * Note that thread->t_threadledger may have been changed by the
1227 * thread_set_cpulimit() call above - so don't examine it until afterwards.
1229 thl
= thread
->t_threadledger
;
1230 if (LEDGER_VALID(thl
)) {
1231 block
|= ledger_check_needblock(thl
, now
);
1233 block
|= ledger_check_needblock(l
, now
);
1236 * If we are supposed to block on the availability of one or more
1237 * resources, find the first entry in deficit for which we should wait.
1238 * Schedule a refill if necessary and then sleep until the resource
1239 * becomes available.
1242 if (LEDGER_VALID(thl
)) {
1243 ret
= ledger_perform_blocking(thl
);
1244 if (ret
!= KERN_SUCCESS
)
1247 ret
= ledger_perform_blocking(l
);
1248 if (ret
!= KERN_SUCCESS
)
1254 ledger_check_needblock(ledger_t l
, uint64_t now
)
1257 uint32_t flags
, block
= 0;
1258 struct ledger_entry
*le
;
1259 struct ledger_callback
*lc
;
1262 for (i
= 0; i
< l
->l_size
; i
++) {
1263 le
= &l
->l_entries
[i
];
1265 lc
= entry_get_callback(l
, i
);
1267 if (limit_exceeded(le
) == FALSE
) {
1268 if (le
->le_flags
& LEDGER_ACTION_CALLBACK
) {
1270 * If needed, invoke the callback as a warning.
1271 * This needs to happen both when the balance rises above
1272 * the warning level, and also when it dips back below it.
1276 * See comments for matching logic in ledger_check_new_balance().
1278 if (warn_level_exceeded(le
)) {
1279 flags
= flag_set(&le
->le_flags
, LF_WARNED
);
1280 if ((flags
& LF_WARNED
) == 0) {
1281 lc
->lc_func(LEDGER_WARNING_ROSE_ABOVE
, lc
->lc_param0
, lc
->lc_param1
);
1284 flags
= flag_clear(&le
->le_flags
, LF_WARNED
);
1285 if (flags
& LF_WARNED
) {
1286 lc
->lc_func(LEDGER_WARNING_DIPPED_BELOW
, lc
->lc_param0
, lc
->lc_param1
);
1294 /* We're over the limit, so refill if we are eligible and past due. */
1295 if (le
->le_flags
& LF_REFILL_SCHEDULED
) {
1296 if ((le
->_le
.le_refill
.le_last_refill
+ le
->_le
.le_refill
.le_refill_period
) > now
) {
1297 ledger_refill(now
, l
, i
);
1298 if (limit_exceeded(le
) == FALSE
)
1303 if (le
->le_flags
& LEDGER_ACTION_BLOCK
)
1305 if ((le
->le_flags
& LEDGER_ACTION_CALLBACK
) == 0)
1309 * If the LEDGER_ACTION_CALLBACK flag is on, we expect there to
1310 * be a registered callback.
1313 flags
= flag_set(&le
->le_flags
, LF_CALLED_BACK
);
1314 /* Callback has already been called */
1315 if (flags
& LF_CALLED_BACK
)
1317 lc
->lc_func(FALSE
, lc
->lc_param0
, lc
->lc_param1
);
1323 /* return KERN_SUCCESS to continue, KERN_FAILURE to restart */
1324 static kern_return_t
1325 ledger_perform_blocking(ledger_t l
)
1329 struct ledger_entry
*le
;
1331 for (i
= 0; i
< l
->l_size
; i
++) {
1332 le
= &l
->l_entries
[i
];
1333 if ((!limit_exceeded(le
)) ||
1334 ((le
->le_flags
& LEDGER_ACTION_BLOCK
) == 0))
1337 /* Prepare to sleep until the resource is refilled */
1338 ret
= assert_wait_deadline(le
, TRUE
,
1339 le
->_le
.le_refill
.le_last_refill
+ le
->_le
.le_refill
.le_refill_period
);
1340 if (ret
!= THREAD_WAITING
)
1341 return(KERN_SUCCESS
);
1343 /* Mark that somebody is waiting on this entry */
1344 flag_set(&le
->le_flags
, LF_WAKE_NEEDED
);
1346 ret
= thread_block_reason(THREAD_CONTINUE_NULL
, NULL
,
1348 if (ret
!= THREAD_AWAKENED
)
1349 return(KERN_SUCCESS
);
1352 * The world may have changed while we were asleep.
1353 * Some other resource we need may have gone into
1354 * deficit. Or maybe we're supposed to die now.
1355 * Go back to the top and reevaluate.
1357 return(KERN_FAILURE
);
1359 return(KERN_SUCCESS
);
1364 ledger_get_entries(ledger_t ledger
, int entry
, ledger_amount_t
*credit
,
1365 ledger_amount_t
*debit
)
1367 struct ledger_entry
*le
;
1369 if (!ENTRY_VALID(ledger
, entry
))
1370 return (KERN_INVALID_ARGUMENT
);
1372 le
= &ledger
->l_entries
[entry
];
1374 *credit
= le
->le_credit
;
1375 *debit
= le
->le_debit
;
1377 return (KERN_SUCCESS
);
1381 ledger_get_balance(ledger_t ledger
, int entry
, ledger_amount_t
*balance
)
1383 struct ledger_entry
*le
;
1385 if (!ENTRY_VALID(ledger
, entry
))
1386 return (KERN_INVALID_ARGUMENT
);
1388 le
= &ledger
->l_entries
[entry
];
1390 assert((le
->le_credit
>= 0) && (le
->le_debit
>= 0));
1392 *balance
= le
->le_credit
- le
->le_debit
;
1394 return (KERN_SUCCESS
);
1398 ledger_template_info(void **buf
, int *len
)
1400 struct ledger_template_info
*lti
;
1401 struct entry_template
*et
;
1406 * Since all tasks share a ledger template, we'll just use the
1407 * caller's as the source.
1409 l
= current_task()->ledger
;
1410 if ((*len
< 0) || (l
== NULL
))
1413 if (*len
> l
->l_size
)
1415 lti
= kalloc((*len
) * sizeof (struct ledger_template_info
));
1420 template_lock(l
->l_template
);
1421 et
= l
->l_template
->lt_entries
;
1423 for (i
= 0; i
< *len
; i
++) {
1424 memset(lti
, 0, sizeof (*lti
));
1425 strlcpy(lti
->lti_name
, et
->et_key
, LEDGER_NAME_MAX
);
1426 strlcpy(lti
->lti_group
, et
->et_group
, LEDGER_NAME_MAX
);
1427 strlcpy(lti
->lti_units
, et
->et_units
, LEDGER_NAME_MAX
);
1431 template_unlock(l
->l_template
);
1437 ledger_fill_entry_info(struct ledger_entry
*le
,
1438 struct ledger_entry_info
*lei
,
1442 assert(lei
!= NULL
);
1444 memset(lei
, 0, sizeof (*lei
));
1446 lei
->lei_limit
= le
->le_limit
;
1447 lei
->lei_credit
= le
->le_credit
;
1448 lei
->lei_debit
= le
->le_debit
;
1449 lei
->lei_balance
= lei
->lei_credit
- lei
->lei_debit
;
1450 lei
->lei_refill_period
= (le
->le_flags
& LF_REFILL_SCHEDULED
) ?
1451 abstime_to_nsecs(le
->_le
.le_refill
.le_refill_period
) : 0;
1452 lei
->lei_last_refill
= abstime_to_nsecs(now
- le
->_le
.le_refill
.le_last_refill
);
1456 ledger_get_task_entry_info_multiple(task_t task
, void **buf
, int *len
)
1458 struct ledger_entry_info
*lei
;
1459 struct ledger_entry
*le
;
1460 uint64_t now
= mach_absolute_time();
1464 if ((*len
< 0) || ((l
= task
->ledger
) == NULL
))
1467 if (*len
> l
->l_size
)
1469 lei
= kalloc((*len
) * sizeof (struct ledger_entry_info
));
1476 for (i
= 0; i
< *len
; i
++) {
1477 ledger_fill_entry_info(le
, lei
, now
);
1486 ledger_get_entry_info(ledger_t ledger
,
1488 struct ledger_entry_info
*lei
)
1490 uint64_t now
= mach_absolute_time();
1492 assert(ledger
!= NULL
);
1493 assert(lei
!= NULL
);
1494 assert(entry
< ledger
->l_size
);
1496 struct ledger_entry
*le
= &ledger
->l_entries
[entry
];
1498 ledger_fill_entry_info(le
, lei
, now
);
1502 ledger_info(task_t task
, struct ledger_info
*info
)
1506 if ((l
= task
->ledger
) == NULL
)
1509 memset(info
, 0, sizeof (*info
));
1511 strlcpy(info
->li_name
, l
->l_template
->lt_name
, LEDGER_NAME_MAX
);
1512 info
->li_id
= l
->l_id
;
1513 info
->li_entries
= l
->l_size
;
1519 ledger_limit(task_t task
, struct ledger_limit_args
*args
)
1525 if ((l
= task
->ledger
) == NULL
)
1528 idx
= ledger_key_lookup(l
->l_template
, args
->lla_name
);
1529 if ((idx
< 0) || (idx
>= l
->l_size
))
1533 * XXX - this doesn't really seem like the right place to have
1534 * a context-sensitive conversion of userspace units into kernel
1535 * units. For now I'll handwave and say that the ledger() system
1536 * call isn't meant for civilians to use - they should be using
1537 * the process policy interfaces.
1539 if (idx
== task_ledgers
.cpu_time
) {
1542 if (args
->lla_refill_period
) {
1544 * If a refill is scheduled, then the limit is
1545 * specified as a percentage of one CPU. The
1546 * syscall specifies the refill period in terms of
1547 * milliseconds, so we need to convert to nsecs.
1549 args
->lla_refill_period
*= 1000000;
1550 nsecs
= args
->lla_limit
*
1551 (args
->lla_refill_period
/ 100);
1552 lprintf(("CPU limited to %lld nsecs per second\n",
1556 * If no refill is scheduled, then this is a
1557 * fixed amount of CPU time (in nsecs) that can
1560 nsecs
= args
->lla_limit
;
1561 lprintf(("CPU limited to %lld nsecs\n", nsecs
));
1563 limit
= nsecs_to_abstime(nsecs
);
1565 limit
= args
->lla_limit
;
1566 lprintf(("%s limited to %lld\n", args
->lla_name
, limit
));
1569 if (args
->lla_refill_period
> 0)
1570 ledger_set_period(l
, idx
, args
->lla_refill_period
);
1572 ledger_set_limit(l
, idx
, limit
);
1573 flag_set(&l
->l_entries
[idx
].le_flags
, LEDGER_ACTION_BLOCK
);