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/kern_types.h>
33 #include <kern/ledger.h>
34 #include <kern/kalloc.h>
35 #include <kern/task.h>
36 #include <kern/thread.h>
38 #include <kern/processor.h>
39 #include <kern/machine.h>
40 #include <kern/queue.h>
41 #include <kern/policy_internal.h>
43 #include <sys/errno.h>
45 #include <libkern/OSAtomic.h>
46 #include <mach/mach_types.h>
47 #include <os/overflow.h>
50 * Ledger entry flags. Bits in second nibble (masked by 0xF0) are used for
51 * ledger actions (LEDGER_ACTION_BLOCK, etc).
53 #define LF_ENTRY_ACTIVE 0x0001 /* entry is active if set */
54 #define LF_WAKE_NEEDED 0x0100 /* one or more threads are asleep */
55 #define LF_WAKE_INPROGRESS 0x0200 /* the wait queue is being processed */
56 #define LF_REFILL_SCHEDULED 0x0400 /* a refill timer has been set */
57 #define LF_REFILL_INPROGRESS 0x0800 /* the ledger is being refilled */
58 #define LF_CALLED_BACK 0x1000 /* callback was called for balance in deficit */
59 #define LF_WARNED 0x2000 /* callback was called for balance warning */
60 #define LF_TRACKING_MAX 0x4000 /* track max balance. Exclusive w.r.t refill */
61 #define LF_PANIC_ON_NEGATIVE 0x8000 /* panic if it goes negative */
62 #define LF_TRACK_CREDIT_ONLY 0x10000 /* only update "credit" */
64 /* Determine whether a ledger entry exists and has been initialized and active */
65 #define ENTRY_VALID(l, e) \
66 (((l) != NULL) && ((e) >= 0) && ((e) < (l)->l_size) && \
67 (((l)->l_entries[e].le_flags & LF_ENTRY_ACTIVE) == LF_ENTRY_ACTIVE))
69 #define ASSERT(a) assert(a)
74 #define lprintf(a) if (ledger_debug) { \
75 printf("%lld ", abstime_to_nsecs(mach_absolute_time() / 1000000)); \
82 struct ledger_callback
{
83 ledger_callback_t lc_func
;
84 const void *lc_param0
;
85 const void *lc_param1
;
88 struct entry_template
{
89 char et_key
[LEDGER_NAME_MAX
];
90 char et_group
[LEDGER_NAME_MAX
];
91 char et_units
[LEDGER_NAME_MAX
];
93 struct ledger_callback
*et_callback
;
96 lck_grp_t ledger_lck_grp
;
99 * Modifying the reference count, table size, or table contents requires
100 * holding the lt_lock. Modfying the table address requires both lt_lock
101 * and setting the inuse bit. This means that the lt_entries field can be
102 * safely dereferenced if you hold either the lock or the inuse bit. The
103 * inuse bit exists solely to allow us to swap in a new, larger entries
104 * table without requiring a full lock to be acquired on each lookup.
105 * Accordingly, the inuse bit should never be held for longer than it takes
106 * to extract a value from the table - i.e., 2 or 3 memory references.
108 struct ledger_template
{
113 volatile uint32_t lt_inuse
;
116 struct entry_template
*lt_entries
;
119 #define template_lock(template) lck_mtx_lock(&(template)->lt_lock)
120 #define template_unlock(template) lck_mtx_unlock(&(template)->lt_lock)
122 #define TEMPLATE_INUSE(s, t) { \
124 while (OSCompareAndSwap(0, 1, &((t)->lt_inuse))) \
128 #define TEMPLATE_IDLE(s, t) { \
134 * Use NTOCKS "tocks" to track the rolling maximum balance of a ledger entry.
138 * The explicit alignment is to ensure that atomic operations don't panic
141 struct ledger_entry
{
142 volatile uint32_t le_flags
;
143 ledger_amount_t le_limit
;
144 ledger_amount_t le_warn_level
;
145 volatile ledger_amount_t le_credit
__attribute__((aligned(8)));
146 volatile ledger_amount_t le_debit
__attribute__((aligned(8)));
150 * XXX - the following two fields can go away if we move all of
151 * the refill logic into process policy
153 uint64_t le_refill_period
;
154 uint64_t le_last_refill
;
156 struct _le_maxtracking
{
158 uint32_t le_max
; /* Lower 32-bits of observed max balance */
159 uint32_t le_time
; /* time when this peak was observed */
161 ledger_amount_t le_lifetime_max
; /* greatest peak ever observed */
164 } __attribute__((aligned(8)));
170 struct ledger_template
*l_template
;
171 struct ledger_entry l_entries
[0] __attribute__((aligned(8)));
174 static int ledger_cnt
= 0;
175 /* ledger ast helper functions */
176 static uint32_t ledger_check_needblock(ledger_t l
, uint64_t now
);
177 static kern_return_t
ledger_perform_blocking(ledger_t l
);
178 static uint32_t flag_set(volatile uint32_t *flags
, uint32_t bit
);
179 static uint32_t flag_clear(volatile uint32_t *flags
, uint32_t bit
);
181 static void ledger_entry_check_new_balance(ledger_t ledger
, int entry
,
182 struct ledger_entry
*le
);
186 debug_callback(const void *p0
, __unused
const void *p1
)
188 printf("ledger: resource exhausted [%s] for task %p\n",
189 (const char *)p0
, p1
);
193 /************************************/
196 abstime_to_nsecs(uint64_t abstime
)
200 absolutetime_to_nanoseconds(abstime
, &nsecs
);
205 nsecs_to_abstime(uint64_t nsecs
)
209 nanoseconds_to_absolutetime(nsecs
, &abstime
);
216 lck_grp_init(&ledger_lck_grp
, "ledger", LCK_GRP_ATTR_NULL
);
220 ledger_template_create(const char *name
)
222 ledger_template_t
template;
224 template = (ledger_template_t
)kalloc(sizeof (*template));
225 if (template == NULL
)
228 template->lt_name
= name
;
229 template->lt_refs
= 1;
230 template->lt_cnt
= 0;
231 template->lt_table_size
= 1;
232 template->lt_inuse
= 0;
233 template->lt_zone
= NULL
;
234 lck_mtx_init(&template->lt_lock
, &ledger_lck_grp
, LCK_ATTR_NULL
);
236 template->lt_entries
= (struct entry_template
*)
237 kalloc(sizeof (struct entry_template
) * template->lt_table_size
);
238 if (template->lt_entries
== NULL
) {
239 kfree(template, sizeof (*template));
247 ledger_template_dereference(ledger_template_t
template)
249 template_lock(template);
251 template_unlock(template);
253 if (template->lt_refs
== 0)
254 kfree(template, sizeof (*template));
258 * Add a new entry to the list of entries in a ledger template. There is
259 * currently no mechanism to remove an entry. Implementing such a mechanism
260 * would require us to maintain per-entry reference counts, which we would
261 * prefer to avoid if possible.
264 ledger_entry_add(ledger_template_t
template, const char *key
,
265 const char *group
, const char *units
)
268 struct entry_template
*et
;
270 if ((key
== NULL
) || (strlen(key
) >= LEDGER_NAME_MAX
) || (template->lt_zone
!= NULL
))
273 template_lock(template);
275 /* If the table is full, attempt to double its size */
276 if (template->lt_cnt
== template->lt_table_size
) {
277 struct entry_template
*new_entries
, *old_entries
;
278 int old_cnt
, old_sz
, new_sz
= 0;
281 old_cnt
= template->lt_table_size
;
282 old_sz
= old_cnt
* (int)(sizeof(struct entry_template
));
283 /* double old_sz allocation, but check for overflow */
284 if (os_mul_overflow(old_sz
, 2, &new_sz
)) {
285 template_unlock(template);
288 new_entries
= kalloc(new_sz
);
289 if (new_entries
== NULL
) {
290 template_unlock(template);
293 memcpy(new_entries
, template->lt_entries
, old_sz
);
294 memset(((char *)new_entries
) + old_sz
, 0, old_sz
);
295 /* assume: if the sz didn't overflow, neither will the count */
296 template->lt_table_size
= old_cnt
* 2;
298 old_entries
= template->lt_entries
;
300 TEMPLATE_INUSE(s
, template);
301 template->lt_entries
= new_entries
;
302 TEMPLATE_IDLE(s
, template);
304 kfree(old_entries
, old_sz
);
307 et
= &template->lt_entries
[template->lt_cnt
];
308 strlcpy(et
->et_key
, key
, LEDGER_NAME_MAX
);
309 strlcpy(et
->et_group
, group
, LEDGER_NAME_MAX
);
310 strlcpy(et
->et_units
, units
, LEDGER_NAME_MAX
);
311 et
->et_flags
= LF_ENTRY_ACTIVE
;
312 et
->et_callback
= NULL
;
314 idx
= template->lt_cnt
++;
315 template_unlock(template);
322 ledger_entry_setactive(ledger_t ledger
, int entry
)
324 struct ledger_entry
*le
;
326 if ((ledger
== NULL
) || (entry
< 0) || (entry
>= ledger
->l_size
))
327 return (KERN_INVALID_ARGUMENT
);
329 le
= &ledger
->l_entries
[entry
];
330 if ((le
->le_flags
& LF_ENTRY_ACTIVE
) == 0) {
331 flag_set(&le
->le_flags
, LF_ENTRY_ACTIVE
);
333 return (KERN_SUCCESS
);
338 ledger_key_lookup(ledger_template_t
template, const char *key
)
342 template_lock(template);
343 for (idx
= 0; idx
< template->lt_cnt
; idx
++)
344 if (template->lt_entries
!= NULL
&&
345 (strcmp(key
, template->lt_entries
[idx
].et_key
) == 0))
348 if (idx
>= template->lt_cnt
)
350 template_unlock(template);
356 * Complete the initialization of ledger template
357 * by initializing ledger zone. After initializing
358 * the ledger zone, adding an entry in the ledger
359 * template would fail.
362 ledger_template_complete(ledger_template_t
template)
365 ledger_size
= sizeof(struct ledger
) + (template->lt_cnt
* sizeof(struct ledger_entry
));
366 template->lt_zone
= zinit(ledger_size
, CONFIG_TASK_MAX
* ledger_size
,
372 * Create a new ledger based on the specified template. As part of the
373 * ledger creation we need to allocate space for a table of ledger entries.
374 * The size of the table is based on the size of the template at the time
375 * the ledger is created. If additional entries are added to the template
376 * after the ledger is created, they will not be tracked in this ledger.
379 ledger_instantiate(ledger_template_t
template, int entry_type
)
385 template_lock(template);
387 cnt
= template->lt_cnt
;
388 assert(template->lt_zone
);
389 template_unlock(template);
391 ledger
= (ledger_t
)zalloc(template->lt_zone
);
392 if (ledger
== NULL
) {
393 ledger_template_dereference(template);
397 ledger
->l_template
= template;
398 ledger
->l_id
= ledger_cnt
++;
400 ledger
->l_size
= (int32_t)cnt
;
402 template_lock(template);
403 assert(ledger
->l_size
<= template->lt_cnt
);
404 for (i
= 0; i
< ledger
->l_size
; i
++) {
405 struct ledger_entry
*le
= &ledger
->l_entries
[i
];
406 struct entry_template
*et
= &template->lt_entries
[i
];
408 le
->le_flags
= et
->et_flags
;
409 /* make entry inactive by removing active bit */
410 if (entry_type
== LEDGER_CREATE_INACTIVE_ENTRIES
)
411 flag_clear(&le
->le_flags
, LF_ENTRY_ACTIVE
);
413 * If template has a callback, this entry is opted-in,
416 if (et
->et_callback
!= NULL
)
417 flag_set(&le
->le_flags
, LEDGER_ACTION_CALLBACK
);
420 le
->le_limit
= LEDGER_LIMIT_INFINITY
;
421 le
->le_warn_level
= LEDGER_LIMIT_INFINITY
;
422 le
->_le
.le_refill
.le_refill_period
= 0;
423 le
->_le
.le_refill
.le_last_refill
= 0;
425 template_unlock(template);
431 flag_set(volatile uint32_t *flags
, uint32_t bit
)
433 return (OSBitOrAtomic(bit
, flags
));
437 flag_clear(volatile uint32_t *flags
, uint32_t bit
)
439 return (OSBitAndAtomic(~bit
, flags
));
443 * Take a reference on a ledger
446 ledger_reference(ledger_t ledger
)
448 if (!LEDGER_VALID(ledger
))
449 return (KERN_INVALID_ARGUMENT
);
450 OSIncrementAtomic(&ledger
->l_refs
);
451 return (KERN_SUCCESS
);
455 ledger_reference_count(ledger_t ledger
)
457 if (!LEDGER_VALID(ledger
))
460 return (ledger
->l_refs
);
464 * Remove a reference on a ledger. If this is the last reference,
465 * deallocate the unused ledger.
468 ledger_dereference(ledger_t ledger
)
472 if (!LEDGER_VALID(ledger
))
473 return (KERN_INVALID_ARGUMENT
);
475 v
= OSDecrementAtomic(&ledger
->l_refs
);
478 /* Just released the last reference. Free it. */
480 zfree(ledger
->l_template
->lt_zone
, ledger
);
483 return (KERN_SUCCESS
);
487 * Determine whether an entry has exceeded its warning level.
490 warn_level_exceeded(struct ledger_entry
*le
)
492 ledger_amount_t balance
;
494 if (le
->le_flags
& LF_TRACK_CREDIT_ONLY
) {
495 assert(le
->le_debit
== 0);
497 assert((le
->le_credit
>= 0) && (le
->le_debit
>= 0));
501 * XXX - Currently, we only support warnings for ledgers which
502 * use positive limits.
504 balance
= le
->le_credit
- le
->le_debit
;
505 if ((le
->le_warn_level
!= LEDGER_LIMIT_INFINITY
) && (balance
> le
->le_warn_level
))
511 * Determine whether an entry has exceeded its limit.
514 limit_exceeded(struct ledger_entry
*le
)
516 ledger_amount_t balance
;
518 if (le
->le_flags
& LF_TRACK_CREDIT_ONLY
) {
519 assert(le
->le_debit
== 0);
521 assert((le
->le_credit
>= 0) && (le
->le_debit
>= 0));
524 balance
= le
->le_credit
- le
->le_debit
;
525 if ((le
->le_limit
<= 0) && (balance
< le
->le_limit
))
528 if ((le
->le_limit
> 0) && (balance
> le
->le_limit
))
533 static inline struct ledger_callback
*
534 entry_get_callback(ledger_t ledger
, int entry
)
536 struct ledger_callback
*callback
;
539 TEMPLATE_INUSE(s
, ledger
->l_template
);
540 callback
= ledger
->l_template
->lt_entries
[entry
].et_callback
;
541 TEMPLATE_IDLE(s
, ledger
->l_template
);
547 * If the ledger value is positive, wake up anybody waiting on it.
550 ledger_limit_entry_wakeup(struct ledger_entry
*le
)
554 if (!limit_exceeded(le
)) {
555 flags
= flag_clear(&le
->le_flags
, LF_CALLED_BACK
);
557 while (le
->le_flags
& LF_WAKE_NEEDED
) {
558 flag_clear(&le
->le_flags
, LF_WAKE_NEEDED
);
559 thread_wakeup((event_t
)le
);
565 * Refill the coffers.
568 ledger_refill(uint64_t now
, ledger_t ledger
, int entry
)
570 uint64_t elapsed
, period
, periods
;
571 struct ledger_entry
*le
;
572 ledger_amount_t balance
, due
;
574 assert(entry
>= 0 && entry
< ledger
->l_size
);
576 le
= &ledger
->l_entries
[entry
];
578 assert(le
->le_limit
!= LEDGER_LIMIT_INFINITY
);
580 if (le
->le_flags
& LF_TRACK_CREDIT_ONLY
) {
581 assert(le
->le_debit
== 0);
586 * If another thread is handling the refill already, we're not
589 if (flag_set(&le
->le_flags
, LF_REFILL_INPROGRESS
) & LF_REFILL_INPROGRESS
) {
594 * If the timestamp we're about to use to refill is older than the
595 * last refill, then someone else has already refilled this ledger
596 * and there's nothing for us to do here.
598 if (now
<= le
->_le
.le_refill
.le_last_refill
) {
599 flag_clear(&le
->le_flags
, LF_REFILL_INPROGRESS
);
604 * See how many refill periods have passed since we last
607 period
= le
->_le
.le_refill
.le_refill_period
;
608 elapsed
= now
- le
->_le
.le_refill
.le_last_refill
;
609 if ((period
== 0) || (elapsed
< period
)) {
610 flag_clear(&le
->le_flags
, LF_REFILL_INPROGRESS
);
615 * Optimize for the most common case of only one or two
619 while ((periods
< 2) && (elapsed
> 0)) {
625 * OK, it's been a long time. Do a divide to figure out
629 periods
= (now
- le
->_le
.le_refill
.le_last_refill
) / period
;
631 balance
= le
->le_credit
- le
->le_debit
;
632 due
= periods
* le
->le_limit
;
634 if (balance
- due
< 0)
637 assertf(due
>= 0,"now=%llu, ledger=%p, entry=%d, balance=%lld, due=%lld", now
, ledger
, entry
, balance
, due
);
639 OSAddAtomic64(due
, &le
->le_debit
);
641 assert(le
->le_debit
>= 0);
644 * If we've completely refilled the pool, set the refill time to now.
645 * Otherwise set it to the time at which it last should have been
649 le
->_le
.le_refill
.le_last_refill
= now
;
651 le
->_le
.le_refill
.le_last_refill
+= (le
->_le
.le_refill
.le_refill_period
* periods
);
653 flag_clear(&le
->le_flags
, LF_REFILL_INPROGRESS
);
655 lprintf(("Refill %lld %lld->%lld\n", periods
, balance
, balance
- due
));
656 if (!limit_exceeded(le
))
657 ledger_limit_entry_wakeup(le
);
661 * In tenths of a second, the length of one lookback period (a "tock") for
662 * ledger rolling maximum calculations. The effective lookback window will be this times
665 * Use a tock length of 2.5 seconds to get a total lookback period of 5 seconds.
667 * XXX Could make this caller-definable, at the point that rolling max tracking
668 * is enabled for the entry.
673 * How many sched_tick's are there in one tock (one of our lookback periods)?
675 * X sched_ticks 2.5 sec N sched_ticks
676 * --------------- = ---------- * -------------
679 * where N sched_ticks/sec is calculated via 1 << SCHED_TICK_SHIFT (see sched_prim.h)
681 * This should give us 20 sched_tick's in one 2.5 second-long tock.
683 #define SCHED_TICKS_PER_TOCK ((TOCKLEN * (1 << SCHED_TICK_SHIFT)) / 10)
686 * Rolling max timestamps use their own unit (let's call this a "tock"). One tock is the
687 * length of one lookback period that we use for our rolling max calculation.
689 * Calculate the current time in tocks from sched_tick (which runs at a some
692 #define CURRENT_TOCKSTAMP() (sched_tick / SCHED_TICKS_PER_TOCK)
695 * Does the given tockstamp fall in either the current or the previous tocks?
697 #define TOCKSTAMP_IS_STALE(now, tock) ((((now) - (tock)) < NTOCKS) ? FALSE : TRUE)
700 ledger_entry_check_new_balance(ledger_t ledger
, int entry
, struct ledger_entry
*le
)
702 ledger_amount_t credit
, debit
;
704 if (le
->le_flags
& LF_TRACKING_MAX
) {
705 ledger_amount_t balance
= le
->le_credit
- le
->le_debit
;
706 uint32_t now
= CURRENT_TOCKSTAMP();
707 struct _le_peak
*p
= &le
->_le
.le_maxtracking
.le_peaks
[now
% NTOCKS
];
709 if (!TOCKSTAMP_IS_STALE(now
, p
->le_time
) || (balance
> p
->le_max
)) {
711 * The current balance is greater than the previously
712 * observed peak for the current time block, *or* we
713 * haven't yet recorded a peak for the current time block --
714 * so this is our new peak.
716 * (We only track the lower 32-bits of a balance for rolling
719 p
->le_max
= (uint32_t)balance
;
723 struct _le_maxtracking
*m
= &le
->_le
.le_maxtracking
;
724 if(balance
> m
->le_lifetime_max
){
725 m
->le_lifetime_max
= balance
;
729 /* Check to see whether we're due a refill */
730 if (le
->le_flags
& LF_REFILL_SCHEDULED
) {
731 assert(!(le
->le_flags
& LF_TRACKING_MAX
));
733 uint64_t now
= mach_absolute_time();
734 if ((now
- le
->_le
.le_refill
.le_last_refill
) > le
->_le
.le_refill
.le_refill_period
)
735 ledger_refill(now
, ledger
, entry
);
738 if (limit_exceeded(le
)) {
740 * We've exceeded the limit for this entry. There
741 * are several possible ways to handle it. We can block,
742 * we can execute a callback, or we can ignore it. In
743 * either of the first two cases, we want to set the AST
744 * flag so we can take the appropriate action just before
745 * leaving the kernel. The one caveat is that if we have
746 * already called the callback, we don't want to do it
747 * again until it gets rearmed.
749 if ((le
->le_flags
& LEDGER_ACTION_BLOCK
) ||
750 (!(le
->le_flags
& LF_CALLED_BACK
) &&
751 entry_get_callback(ledger
, entry
))) {
752 set_astledger(current_thread());
756 * The balance on the account is below the limit.
758 * If there are any threads blocked on this entry, now would
759 * be a good time to wake them up.
761 if (le
->le_flags
& LF_WAKE_NEEDED
)
762 ledger_limit_entry_wakeup(le
);
764 if (le
->le_flags
& LEDGER_ACTION_CALLBACK
) {
766 * Client has requested that a callback be invoked whenever
767 * the ledger's balance crosses into or out of the warning
770 if (warn_level_exceeded(le
)) {
772 * This ledger's balance is above the warning level.
774 if ((le
->le_flags
& LF_WARNED
) == 0) {
776 * If we are above the warning level and
777 * have not yet invoked the callback,
778 * set the AST so it can be done before returning
781 set_astledger(current_thread());
785 * This ledger's balance is below the warning level.
787 if (le
->le_flags
& LF_WARNED
) {
789 * If we are below the warning level and
790 * the LF_WARNED flag is still set, we need
791 * to invoke the callback to let the client
792 * know the ledger balance is now back below
795 set_astledger(current_thread());
801 credit
= le
->le_credit
;
802 debit
= le
->le_debit
;
803 if ((le
->le_flags
& LF_PANIC_ON_NEGATIVE
) &&
805 (le
->le_credit
< le
->le_debit
))) {
806 panic("ledger_entry_check_new_balance(%p,%d): negative ledger %p credit:%lld/%lld debit:%lld/%lld balance:%lld/%lld\n",
808 credit
, le
->le_credit
,
810 credit
- debit
, le
->le_credit
- le
->le_debit
);
815 ledger_check_new_balance(ledger_t ledger
, int entry
)
817 struct ledger_entry
*le
;
818 assert(entry
> 0 && entry
<= ledger
->l_size
);
819 le
= &ledger
->l_entries
[entry
];
820 ledger_entry_check_new_balance(ledger
, entry
, le
);
825 * Add value to an entry in a ledger.
828 ledger_credit(ledger_t ledger
, int entry
, ledger_amount_t amount
)
830 ledger_amount_t old
, new;
831 struct ledger_entry
*le
;
833 if (!ENTRY_VALID(ledger
, entry
) || (amount
< 0))
834 return (KERN_INVALID_VALUE
);
837 return (KERN_SUCCESS
);
839 le
= &ledger
->l_entries
[entry
];
841 old
= OSAddAtomic64(amount
, &le
->le_credit
);
843 lprintf(("%p Credit %lld->%lld\n", current_thread(), old
, new));
844 ledger_entry_check_new_balance(ledger
, entry
, le
);
846 return (KERN_SUCCESS
);
849 /* Add all of one ledger's values into another.
850 * They must have been created from the same template.
851 * This is not done atomically. Another thread (if not otherwise synchronized)
852 * may see bogus values when comparing one entry to another.
853 * As each entry's credit & debit are modified one at a time, the warning/limit
854 * may spuriously trip, or spuriously fail to trip, or another thread (if not
855 * otherwise synchronized) may see a bogus balance.
858 ledger_rollup(ledger_t to_ledger
, ledger_t from_ledger
)
862 assert(to_ledger
->l_template
== from_ledger
->l_template
);
864 for (i
= 0; i
< to_ledger
->l_size
; i
++) {
865 ledger_rollup_entry(to_ledger
, from_ledger
, i
);
868 return (KERN_SUCCESS
);
871 /* Add one ledger entry value to another.
872 * They must have been created from the same template.
873 * Since the credit and debit values are added one
874 * at a time, other thread might read the a bogus value.
877 ledger_rollup_entry(ledger_t to_ledger
, ledger_t from_ledger
, int entry
)
879 struct ledger_entry
*from_le
, *to_le
;
881 assert(to_ledger
->l_template
== from_ledger
->l_template
);
882 if (ENTRY_VALID(from_ledger
, entry
) && ENTRY_VALID(to_ledger
, entry
)) {
883 from_le
= &from_ledger
->l_entries
[entry
];
884 to_le
= &to_ledger
->l_entries
[entry
];
885 OSAddAtomic64(from_le
->le_credit
, &to_le
->le_credit
);
886 OSAddAtomic64(from_le
->le_debit
, &to_le
->le_debit
);
889 return (KERN_SUCCESS
);
893 * Zero the balance of a ledger by adding to its credit or debit, whichever is smaller.
894 * Note that some clients of ledgers (notably, task wakeup statistics) require that
895 * le_credit only ever increase as a function of ledger_credit().
898 ledger_zero_balance(ledger_t ledger
, int entry
)
900 struct ledger_entry
*le
;
901 ledger_amount_t debit
, credit
;
903 if (!ENTRY_VALID(ledger
, entry
))
904 return (KERN_INVALID_VALUE
);
906 le
= &ledger
->l_entries
[entry
];
909 debit
= le
->le_debit
;
910 credit
= le
->le_credit
;
912 if (le
->le_flags
& LF_TRACK_CREDIT_ONLY
) {
913 assert(le
->le_debit
== 0);
914 if (!OSCompareAndSwap64(credit
, 0, &le
->le_credit
)) {
917 lprintf(("%p zeroed %lld->%lld\n", current_thread(), le
->le_credit
, 0));
918 } else if (credit
> debit
) {
919 if (!OSCompareAndSwap64(debit
, credit
, &le
->le_debit
))
921 lprintf(("%p zeroed %lld->%lld\n", current_thread(), le
->le_debit
, le
->le_credit
));
922 } else if (credit
< debit
) {
923 if (!OSCompareAndSwap64(credit
, debit
, &le
->le_credit
))
925 lprintf(("%p zeroed %lld->%lld\n", current_thread(), le
->le_credit
, le
->le_debit
));
928 return (KERN_SUCCESS
);
932 ledger_get_limit(ledger_t ledger
, int entry
, ledger_amount_t
*limit
)
934 struct ledger_entry
*le
;
936 if (!ENTRY_VALID(ledger
, entry
))
937 return (KERN_INVALID_VALUE
);
939 le
= &ledger
->l_entries
[entry
];
940 *limit
= le
->le_limit
;
942 lprintf(("ledger_get_limit: %lld\n", *limit
));
944 return (KERN_SUCCESS
);
948 * Adjust the limit of a limited resource. This does not affect the
949 * current balance, so the change doesn't affect the thread until the
952 * warn_level: If non-zero, causes the callback to be invoked when
953 * the balance exceeds this level. Specified as a percentage [of the limit].
956 ledger_set_limit(ledger_t ledger
, int entry
, ledger_amount_t limit
,
957 uint8_t warn_level_percentage
)
959 struct ledger_entry
*le
;
961 if (!ENTRY_VALID(ledger
, entry
))
962 return (KERN_INVALID_VALUE
);
964 lprintf(("ledger_set_limit: %lld\n", limit
));
965 le
= &ledger
->l_entries
[entry
];
967 if (limit
== LEDGER_LIMIT_INFINITY
) {
969 * Caller wishes to disable the limit. This will implicitly
970 * disable automatic refill, as refills implicitly depend
973 ledger_disable_refill(ledger
, entry
);
976 le
->le_limit
= limit
;
977 if (le
->le_flags
& LF_REFILL_SCHEDULED
) {
978 assert(!(le
->le_flags
& LF_TRACKING_MAX
));
979 le
->_le
.le_refill
.le_last_refill
= 0;
981 flag_clear(&le
->le_flags
, LF_CALLED_BACK
);
982 flag_clear(&le
->le_flags
, LF_WARNED
);
983 ledger_limit_entry_wakeup(le
);
985 if (warn_level_percentage
!= 0) {
986 assert(warn_level_percentage
<= 100);
987 assert(limit
> 0); /* no negative limit support for warnings */
988 assert(limit
!= LEDGER_LIMIT_INFINITY
); /* warn % without limit makes no sense */
989 le
->le_warn_level
= (le
->le_limit
* warn_level_percentage
) / 100;
991 le
->le_warn_level
= LEDGER_LIMIT_INFINITY
;
994 return (KERN_SUCCESS
);
998 ledger_get_recent_max(ledger_t ledger
, int entry
,
999 ledger_amount_t
*max_observed_balance
)
1001 struct ledger_entry
*le
;
1002 uint32_t now
= CURRENT_TOCKSTAMP();
1005 le
= &ledger
->l_entries
[entry
];
1007 if (!ENTRY_VALID(ledger
, entry
) || !(le
->le_flags
& LF_TRACKING_MAX
)) {
1008 return (KERN_INVALID_VALUE
);
1012 * Start with the current balance; if neither of the recorded peaks are
1013 * within recent history, we use this.
1015 *max_observed_balance
= le
->le_credit
- le
->le_debit
;
1017 for (i
= 0; i
< NTOCKS
; i
++) {
1018 if (!TOCKSTAMP_IS_STALE(now
, le
->_le
.le_maxtracking
.le_peaks
[i
].le_time
) &&
1019 (le
->_le
.le_maxtracking
.le_peaks
[i
].le_max
> *max_observed_balance
)) {
1021 * The peak for this time block isn't stale, and it
1022 * is greater than the current balance -- so use it.
1024 *max_observed_balance
= le
->_le
.le_maxtracking
.le_peaks
[i
].le_max
;
1028 lprintf(("ledger_get_maximum: %lld\n", *max_observed_balance
));
1030 return (KERN_SUCCESS
);
1034 ledger_get_lifetime_max(ledger_t ledger
, int entry
,
1035 ledger_amount_t
*max_lifetime_balance
)
1037 struct ledger_entry
*le
;
1038 le
= &ledger
->l_entries
[entry
];
1040 if (!ENTRY_VALID(ledger
, entry
) || !(le
->le_flags
& LF_TRACKING_MAX
)) {
1041 return (KERN_INVALID_VALUE
);
1044 *max_lifetime_balance
= le
->_le
.le_maxtracking
.le_lifetime_max
;
1045 lprintf(("ledger_get_lifetime_max: %lld\n", *max_lifetime_balance
));
1047 return (KERN_SUCCESS
);
1051 * Enable tracking of periodic maximums for this ledger entry.
1054 ledger_track_maximum(ledger_template_t
template, int entry
,
1055 __unused
int period_in_secs
)
1057 template_lock(template);
1059 if ((entry
< 0) || (entry
>= template->lt_cnt
)) {
1060 template_unlock(template);
1061 return (KERN_INVALID_VALUE
);
1064 /* Refill is incompatible with max tracking. */
1065 if (template->lt_entries
[entry
].et_flags
& LF_REFILL_SCHEDULED
) {
1066 return (KERN_INVALID_VALUE
);
1069 template->lt_entries
[entry
].et_flags
|= LF_TRACKING_MAX
;
1070 template_unlock(template);
1072 return (KERN_SUCCESS
);
1076 ledger_panic_on_negative(ledger_template_t
template, int entry
)
1078 template_lock(template);
1080 if ((entry
< 0) || (entry
>= template->lt_cnt
)) {
1081 template_unlock(template);
1082 return (KERN_INVALID_VALUE
);
1085 template->lt_entries
[entry
].et_flags
|= LF_PANIC_ON_NEGATIVE
;
1087 template_unlock(template);
1089 return (KERN_SUCCESS
);
1093 ledger_track_credit_only(ledger_template_t
template, int entry
)
1095 template_lock(template);
1097 if ((entry
< 0) || (entry
>= template->lt_cnt
)) {
1098 template_unlock(template);
1099 return (KERN_INVALID_VALUE
);
1102 template->lt_entries
[entry
].et_flags
|= LF_TRACK_CREDIT_ONLY
;
1104 template_unlock(template);
1106 return (KERN_SUCCESS
);
1110 * Add a callback to be executed when the resource goes into deficit.
1113 ledger_set_callback(ledger_template_t
template, int entry
,
1114 ledger_callback_t func
, const void *param0
, const void *param1
)
1116 struct entry_template
*et
;
1117 struct ledger_callback
*old_cb
, *new_cb
;
1119 if ((entry
< 0) || (entry
>= template->lt_cnt
))
1120 return (KERN_INVALID_VALUE
);
1123 new_cb
= (struct ledger_callback
*)kalloc(sizeof (*new_cb
));
1124 new_cb
->lc_func
= func
;
1125 new_cb
->lc_param0
= param0
;
1126 new_cb
->lc_param1
= param1
;
1131 template_lock(template);
1132 et
= &template->lt_entries
[entry
];
1133 old_cb
= et
->et_callback
;
1134 et
->et_callback
= new_cb
;
1135 template_unlock(template);
1137 kfree(old_cb
, sizeof (*old_cb
));
1139 return (KERN_SUCCESS
);
1143 * Disable callback notification for a specific ledger entry.
1145 * Otherwise, if using a ledger template which specified a
1146 * callback function (ledger_set_callback()), it will be invoked when
1147 * the resource goes into deficit.
1150 ledger_disable_callback(ledger_t ledger
, int entry
)
1152 if (!ENTRY_VALID(ledger
, entry
))
1153 return (KERN_INVALID_VALUE
);
1156 * le_warn_level is used to indicate *if* this ledger has a warning configured,
1157 * in addition to what that warning level is set to.
1158 * This means a side-effect of ledger_disable_callback() is that the
1159 * warning level is forgotten.
1161 ledger
->l_entries
[entry
].le_warn_level
= LEDGER_LIMIT_INFINITY
;
1162 flag_clear(&ledger
->l_entries
[entry
].le_flags
, LEDGER_ACTION_CALLBACK
);
1163 return (KERN_SUCCESS
);
1167 * Enable callback notification for a specific ledger entry.
1169 * This is only needed if ledger_disable_callback() has previously
1170 * been invoked against an entry; there must already be a callback
1174 ledger_enable_callback(ledger_t ledger
, int entry
)
1176 if (!ENTRY_VALID(ledger
, entry
))
1177 return (KERN_INVALID_VALUE
);
1179 assert(entry_get_callback(ledger
, entry
) != NULL
);
1181 flag_set(&ledger
->l_entries
[entry
].le_flags
, LEDGER_ACTION_CALLBACK
);
1182 return (KERN_SUCCESS
);
1186 * Query the automatic refill period for this ledger entry.
1188 * A period of 0 means this entry has none configured.
1191 ledger_get_period(ledger_t ledger
, int entry
, uint64_t *period
)
1193 struct ledger_entry
*le
;
1195 if (!ENTRY_VALID(ledger
, entry
))
1196 return (KERN_INVALID_VALUE
);
1198 le
= &ledger
->l_entries
[entry
];
1199 *period
= abstime_to_nsecs(le
->_le
.le_refill
.le_refill_period
);
1200 lprintf(("ledger_get_period: %llx\n", *period
));
1201 return (KERN_SUCCESS
);
1205 * Adjust the automatic refill period.
1208 ledger_set_period(ledger_t ledger
, int entry
, uint64_t period
)
1210 struct ledger_entry
*le
;
1212 lprintf(("ledger_set_period: %llx\n", period
));
1213 if (!ENTRY_VALID(ledger
, entry
))
1214 return (KERN_INVALID_VALUE
);
1216 le
= &ledger
->l_entries
[entry
];
1219 * A refill period refills the ledger in multiples of the limit,
1220 * so if you haven't set one yet, you need a lesson on ledgers.
1222 assert(le
->le_limit
!= LEDGER_LIMIT_INFINITY
);
1224 if (le
->le_flags
& LF_TRACKING_MAX
) {
1226 * Refill is incompatible with rolling max tracking.
1228 return (KERN_INVALID_VALUE
);
1231 le
->_le
.le_refill
.le_refill_period
= nsecs_to_abstime(period
);
1234 * Set the 'starting time' for the next refill to now. Since
1235 * we're resetting the balance to zero here, we consider this
1236 * moment the starting time for accumulating a balance that
1237 * counts towards the limit.
1239 le
->_le
.le_refill
.le_last_refill
= mach_absolute_time();
1240 ledger_zero_balance(ledger
, entry
);
1242 flag_set(&le
->le_flags
, LF_REFILL_SCHEDULED
);
1244 return (KERN_SUCCESS
);
1248 * Disable automatic refill.
1251 ledger_disable_refill(ledger_t ledger
, int entry
)
1253 struct ledger_entry
*le
;
1255 if (!ENTRY_VALID(ledger
, entry
))
1256 return (KERN_INVALID_VALUE
);
1258 le
= &ledger
->l_entries
[entry
];
1260 flag_clear(&le
->le_flags
, LF_REFILL_SCHEDULED
);
1262 return (KERN_SUCCESS
);
1266 ledger_get_actions(ledger_t ledger
, int entry
, int *actions
)
1268 if (!ENTRY_VALID(ledger
, entry
))
1269 return (KERN_INVALID_VALUE
);
1271 *actions
= ledger
->l_entries
[entry
].le_flags
& LEDGER_ACTION_MASK
;
1272 lprintf(("ledger_get_actions: %#x\n", *actions
));
1273 return (KERN_SUCCESS
);
1277 ledger_set_action(ledger_t ledger
, int entry
, int action
)
1279 lprintf(("ledger_set_action: %#x\n", action
));
1280 if (!ENTRY_VALID(ledger
, entry
))
1281 return (KERN_INVALID_VALUE
);
1283 flag_set(&ledger
->l_entries
[entry
].le_flags
, action
);
1284 return (KERN_SUCCESS
);
1288 ledger_debit(ledger_t ledger
, int entry
, ledger_amount_t amount
)
1290 struct ledger_entry
*le
;
1291 ledger_amount_t old
, new;
1293 if (!ENTRY_VALID(ledger
, entry
) || (amount
< 0))
1294 return (KERN_INVALID_ARGUMENT
);
1297 return (KERN_SUCCESS
);
1299 le
= &ledger
->l_entries
[entry
];
1301 if (le
->le_flags
& LF_TRACK_CREDIT_ONLY
) {
1302 assert(le
->le_debit
== 0);
1303 old
= OSAddAtomic64(-amount
, &le
->le_credit
);
1306 old
= OSAddAtomic64(amount
, &le
->le_debit
);
1309 lprintf(("%p Debit %lld->%lld\n", thread
, old
, new));
1311 ledger_entry_check_new_balance(ledger
, entry
, le
);
1312 return (KERN_SUCCESS
);
1317 ledger_ast(thread_t thread
)
1319 struct ledger
*l
= thread
->t_ledger
;
1324 uint8_t task_percentage
;
1325 uint64_t task_interval
;
1328 task_t task
= thread
->task
;
1330 lprintf(("Ledger AST for %p\n", thread
));
1332 ASSERT(task
!= NULL
);
1333 ASSERT(thread
== current_thread());
1337 * Take a self-consistent snapshot of the CPU usage monitor parameters. The task
1338 * can change them at any point (with the task locked).
1341 task_flags
= task
->rusage_cpu_flags
;
1342 task_percentage
= task
->rusage_cpu_perthr_percentage
;
1343 task_interval
= task
->rusage_cpu_perthr_interval
;
1347 * Make sure this thread is up to date with regards to any task-wide per-thread
1348 * CPU limit, but only if it doesn't have a thread-private blocking CPU limit.
1350 if (((task_flags
& TASK_RUSECPU_FLAGS_PERTHR_LIMIT
) != 0) &&
1351 ((thread
->options
& TH_OPT_PRVT_CPULIMIT
) == 0)) {
1356 thread_get_cpulimit(&action
, &percentage
, &interval
);
1359 * If the thread's CPU limits no longer match the task's, or the
1360 * task has a limit but the thread doesn't, update the limit.
1362 if (((thread
->options
& TH_OPT_PROC_CPULIMIT
) == 0) ||
1363 (interval
!= task_interval
) || (percentage
!= task_percentage
)) {
1364 thread_set_cpulimit(THREAD_CPULIMIT_EXCEPTION
, task_percentage
, task_interval
);
1365 assert((thread
->options
& TH_OPT_PROC_CPULIMIT
) != 0);
1367 } else if (((task_flags
& TASK_RUSECPU_FLAGS_PERTHR_LIMIT
) == 0) &&
1368 (thread
->options
& TH_OPT_PROC_CPULIMIT
)) {
1369 assert((thread
->options
& TH_OPT_PRVT_CPULIMIT
) == 0);
1372 * Task no longer has a per-thread CPU limit; remove this thread's
1373 * corresponding CPU limit.
1375 thread_set_cpulimit(THREAD_CPULIMIT_DISABLE
, 0, 0);
1376 assert((thread
->options
& TH_OPT_PROC_CPULIMIT
) == 0);
1380 * If the task or thread is being terminated, let's just get on with it
1382 if ((l
== NULL
) || !task
->active
|| task
->halting
|| !thread
->active
)
1386 * Examine all entries in deficit to see which might be eligble for
1387 * an automatic refill, which require callbacks to be issued, and
1388 * which require blocking.
1391 now
= mach_absolute_time();
1394 * Note that thread->t_threadledger may have been changed by the
1395 * thread_set_cpulimit() call above - so don't examine it until afterwards.
1397 thl
= thread
->t_threadledger
;
1398 if (LEDGER_VALID(thl
)) {
1399 block
|= ledger_check_needblock(thl
, now
);
1401 block
|= ledger_check_needblock(l
, now
);
1404 * If we are supposed to block on the availability of one or more
1405 * resources, find the first entry in deficit for which we should wait.
1406 * Schedule a refill if necessary and then sleep until the resource
1407 * becomes available.
1410 if (LEDGER_VALID(thl
)) {
1411 ret
= ledger_perform_blocking(thl
);
1412 if (ret
!= KERN_SUCCESS
)
1415 ret
= ledger_perform_blocking(l
);
1416 if (ret
!= KERN_SUCCESS
)
1422 ledger_check_needblock(ledger_t l
, uint64_t now
)
1425 uint32_t flags
, block
= 0;
1426 struct ledger_entry
*le
;
1427 struct ledger_callback
*lc
;
1430 for (i
= 0; i
< l
->l_size
; i
++) {
1431 le
= &l
->l_entries
[i
];
1433 lc
= entry_get_callback(l
, i
);
1435 if (limit_exceeded(le
) == FALSE
) {
1436 if (le
->le_flags
& LEDGER_ACTION_CALLBACK
) {
1438 * If needed, invoke the callback as a warning.
1439 * This needs to happen both when the balance rises above
1440 * the warning level, and also when it dips back below it.
1444 * See comments for matching logic in ledger_check_new_balance().
1446 if (warn_level_exceeded(le
)) {
1447 flags
= flag_set(&le
->le_flags
, LF_WARNED
);
1448 if ((flags
& LF_WARNED
) == 0) {
1449 lc
->lc_func(LEDGER_WARNING_ROSE_ABOVE
, lc
->lc_param0
, lc
->lc_param1
);
1452 flags
= flag_clear(&le
->le_flags
, LF_WARNED
);
1453 if (flags
& LF_WARNED
) {
1454 lc
->lc_func(LEDGER_WARNING_DIPPED_BELOW
, lc
->lc_param0
, lc
->lc_param1
);
1462 /* We're over the limit, so refill if we are eligible and past due. */
1463 if (le
->le_flags
& LF_REFILL_SCHEDULED
) {
1464 assert(!(le
->le_flags
& LF_TRACKING_MAX
));
1466 if ((le
->_le
.le_refill
.le_last_refill
+ le
->_le
.le_refill
.le_refill_period
) > now
) {
1467 ledger_refill(now
, l
, i
);
1468 if (limit_exceeded(le
) == FALSE
)
1473 if (le
->le_flags
& LEDGER_ACTION_BLOCK
)
1475 if ((le
->le_flags
& LEDGER_ACTION_CALLBACK
) == 0)
1479 * If the LEDGER_ACTION_CALLBACK flag is on, we expect there to
1480 * be a registered callback.
1483 flags
= flag_set(&le
->le_flags
, LF_CALLED_BACK
);
1484 /* Callback has already been called */
1485 if (flags
& LF_CALLED_BACK
)
1487 lc
->lc_func(FALSE
, lc
->lc_param0
, lc
->lc_param1
);
1493 /* return KERN_SUCCESS to continue, KERN_FAILURE to restart */
1494 static kern_return_t
1495 ledger_perform_blocking(ledger_t l
)
1499 struct ledger_entry
*le
;
1501 for (i
= 0; i
< l
->l_size
; i
++) {
1502 le
= &l
->l_entries
[i
];
1503 if ((!limit_exceeded(le
)) ||
1504 ((le
->le_flags
& LEDGER_ACTION_BLOCK
) == 0))
1507 assert(!(le
->le_flags
& LF_TRACKING_MAX
));
1509 /* Prepare to sleep until the resource is refilled */
1510 ret
= assert_wait_deadline(le
, TRUE
,
1511 le
->_le
.le_refill
.le_last_refill
+ le
->_le
.le_refill
.le_refill_period
);
1512 if (ret
!= THREAD_WAITING
)
1513 return(KERN_SUCCESS
);
1515 /* Mark that somebody is waiting on this entry */
1516 flag_set(&le
->le_flags
, LF_WAKE_NEEDED
);
1518 ret
= thread_block_reason(THREAD_CONTINUE_NULL
, NULL
,
1520 if (ret
!= THREAD_AWAKENED
)
1521 return(KERN_SUCCESS
);
1524 * The world may have changed while we were asleep.
1525 * Some other resource we need may have gone into
1526 * deficit. Or maybe we're supposed to die now.
1527 * Go back to the top and reevaluate.
1529 return(KERN_FAILURE
);
1531 return(KERN_SUCCESS
);
1536 ledger_get_entries(ledger_t ledger
, int entry
, ledger_amount_t
*credit
,
1537 ledger_amount_t
*debit
)
1539 struct ledger_entry
*le
;
1541 if (!ENTRY_VALID(ledger
, entry
))
1542 return (KERN_INVALID_ARGUMENT
);
1544 le
= &ledger
->l_entries
[entry
];
1546 *credit
= le
->le_credit
;
1547 *debit
= le
->le_debit
;
1549 return (KERN_SUCCESS
);
1553 ledger_reset_callback_state(ledger_t ledger
, int entry
)
1555 struct ledger_entry
*le
;
1557 if (!ENTRY_VALID(ledger
, entry
))
1558 return (KERN_INVALID_ARGUMENT
);
1560 le
= &ledger
->l_entries
[entry
];
1562 flag_clear(&le
->le_flags
, LF_CALLED_BACK
);
1564 return (KERN_SUCCESS
);
1568 ledger_disable_panic_on_negative(ledger_t ledger
, int entry
)
1570 struct ledger_entry
*le
;
1572 if (!ENTRY_VALID(ledger
, entry
))
1573 return (KERN_INVALID_ARGUMENT
);
1575 le
= &ledger
->l_entries
[entry
];
1577 flag_clear(&le
->le_flags
, LF_PANIC_ON_NEGATIVE
);
1579 return (KERN_SUCCESS
);
1583 ledger_get_balance(ledger_t ledger
, int entry
, ledger_amount_t
*balance
)
1585 struct ledger_entry
*le
;
1587 if (!ENTRY_VALID(ledger
, entry
))
1588 return (KERN_INVALID_ARGUMENT
);
1590 le
= &ledger
->l_entries
[entry
];
1592 if (le
->le_flags
& LF_TRACK_CREDIT_ONLY
) {
1593 assert(le
->le_debit
== 0);
1595 assert((le
->le_credit
>= 0) && (le
->le_debit
>= 0));
1598 *balance
= le
->le_credit
- le
->le_debit
;
1600 return (KERN_SUCCESS
);
1604 ledger_template_info(void **buf
, int *len
)
1606 struct ledger_template_info
*lti
;
1607 struct entry_template
*et
;
1612 * Since all tasks share a ledger template, we'll just use the
1613 * caller's as the source.
1615 l
= current_task()->ledger
;
1616 if ((*len
< 0) || (l
== NULL
))
1619 if (*len
> l
->l_size
)
1621 lti
= kalloc((*len
) * sizeof (struct ledger_template_info
));
1626 template_lock(l
->l_template
);
1627 et
= l
->l_template
->lt_entries
;
1629 for (i
= 0; i
< *len
; i
++) {
1630 memset(lti
, 0, sizeof (*lti
));
1631 strlcpy(lti
->lti_name
, et
->et_key
, LEDGER_NAME_MAX
);
1632 strlcpy(lti
->lti_group
, et
->et_group
, LEDGER_NAME_MAX
);
1633 strlcpy(lti
->lti_units
, et
->et_units
, LEDGER_NAME_MAX
);
1637 template_unlock(l
->l_template
);
1643 ledger_fill_entry_info(struct ledger_entry
*le
,
1644 struct ledger_entry_info
*lei
,
1648 assert(lei
!= NULL
);
1650 memset(lei
, 0, sizeof (*lei
));
1652 lei
->lei_limit
= le
->le_limit
;
1653 lei
->lei_credit
= le
->le_credit
;
1654 lei
->lei_debit
= le
->le_debit
;
1655 lei
->lei_balance
= lei
->lei_credit
- lei
->lei_debit
;
1656 lei
->lei_refill_period
= (le
->le_flags
& LF_REFILL_SCHEDULED
) ?
1657 abstime_to_nsecs(le
->_le
.le_refill
.le_refill_period
) : 0;
1658 lei
->lei_last_refill
= abstime_to_nsecs(now
- le
->_le
.le_refill
.le_last_refill
);
1662 ledger_get_task_entry_info_multiple(task_t task
, void **buf
, int *len
)
1664 struct ledger_entry_info
*lei
;
1665 struct ledger_entry
*le
;
1666 uint64_t now
= mach_absolute_time();
1670 if ((*len
< 0) || ((l
= task
->ledger
) == NULL
))
1673 if (*len
> l
->l_size
)
1675 lei
= kalloc((*len
) * sizeof (struct ledger_entry_info
));
1682 for (i
= 0; i
< *len
; i
++) {
1683 ledger_fill_entry_info(le
, lei
, now
);
1692 ledger_get_entry_info(ledger_t ledger
,
1694 struct ledger_entry_info
*lei
)
1696 uint64_t now
= mach_absolute_time();
1698 assert(ledger
!= NULL
);
1699 assert(lei
!= NULL
);
1701 if (entry
>= 0 && entry
< ledger
->l_size
) {
1702 struct ledger_entry
*le
= &ledger
->l_entries
[entry
];
1703 ledger_fill_entry_info(le
, lei
, now
);
1708 ledger_info(task_t task
, struct ledger_info
*info
)
1712 if ((l
= task
->ledger
) == NULL
)
1715 memset(info
, 0, sizeof (*info
));
1717 strlcpy(info
->li_name
, l
->l_template
->lt_name
, LEDGER_NAME_MAX
);
1718 info
->li_id
= l
->l_id
;
1719 info
->li_entries
= l
->l_size
;
1725 ledger_limit(task_t task
, struct ledger_limit_args
*args
)
1731 if ((l
= task
->ledger
) == NULL
)
1734 idx
= ledger_key_lookup(l
->l_template
, args
->lla_name
);
1735 if ((idx
< 0) || (idx
>= l
->l_size
))
1739 * XXX - this doesn't really seem like the right place to have
1740 * a context-sensitive conversion of userspace units into kernel
1741 * units. For now I'll handwave and say that the ledger() system
1742 * call isn't meant for civilians to use - they should be using
1743 * the process policy interfaces.
1745 if (idx
== task_ledgers
.cpu_time
) {
1748 if (args
->lla_refill_period
) {
1750 * If a refill is scheduled, then the limit is
1751 * specified as a percentage of one CPU. The
1752 * syscall specifies the refill period in terms of
1753 * milliseconds, so we need to convert to nsecs.
1755 args
->lla_refill_period
*= 1000000;
1756 nsecs
= args
->lla_limit
*
1757 (args
->lla_refill_period
/ 100);
1758 lprintf(("CPU limited to %lld nsecs per second\n",
1762 * If no refill is scheduled, then this is a
1763 * fixed amount of CPU time (in nsecs) that can
1766 nsecs
= args
->lla_limit
;
1767 lprintf(("CPU limited to %lld nsecs\n", nsecs
));
1769 limit
= nsecs_to_abstime(nsecs
);
1771 limit
= args
->lla_limit
;
1772 lprintf(("%s limited to %lld\n", args
->lla_name
, limit
));
1775 if (args
->lla_refill_period
> 0)
1776 ledger_set_period(l
, idx
, args
->lla_refill_period
);
1778 ledger_set_limit(l
, idx
, limit
);
1779 flag_set(&l
->l_entries
[idx
].le_flags
, LEDGER_ACTION_BLOCK
);