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 ENTRY_ACTIVE 0x0001 /* entry is active if set */
50 #define WAKE_NEEDED 0x0100 /* one or more threads are asleep */
51 #define WAKE_INPROGRESS 0x0200 /* the wait queue is being processed */
52 #define REFILL_SCHEDULED 0x0400 /* a refill timer has been set */
53 #define REFILL_INPROGRESS 0x0800 /* the ledger is being refilled */
54 #define CALLED_BACK 0x1000 /* callback has already been called */
56 /* Determine whether a ledger entry exists and has been initialized and active */
57 #define ENTRY_VALID(l, e) \
58 (((l) != NULL) && ((e) >= 0) && ((e) < (l)->l_size) && \
59 (((l)->l_entries[e].le_flags & ENTRY_ACTIVE) == ENTRY_ACTIVE))
64 #define ASSERT(a) assert(a)
65 #define lprintf(a) if (ledger_debug) { \
66 printf("%lld ", abstime_to_nsecs(mach_absolute_time() / 1000000)); \
74 struct ledger_callback
{
75 ledger_callback_t lc_func
;
76 const void *lc_param0
;
77 const void *lc_param1
;
80 struct entry_template
{
81 char et_key
[LEDGER_NAME_MAX
];
82 char et_group
[LEDGER_NAME_MAX
];
83 char et_units
[LEDGER_NAME_MAX
];
85 struct ledger_callback
*et_callback
;
88 lck_grp_t ledger_lck_grp
;
91 * Modifying the reference count, table size, or table contents requires
92 * holding the lt_lock. Modfying the table address requires both lt_lock
93 * and setting the inuse bit. This means that the lt_entries field can be
94 * safely dereferenced if you hold either the lock or the inuse bit. The
95 * inuse bit exists solely to allow us to swap in a new, larger entries
96 * table without requiring a full lock to be acquired on each lookup.
97 * Accordingly, the inuse bit should never be held for longer than it takes
98 * to extract a value from the table - i.e., 2 or 3 memory references.
100 struct ledger_template
{
105 volatile uint32_t lt_inuse
;
107 struct entry_template
*lt_entries
;
110 #define template_lock(template) lck_mtx_lock(&(template)->lt_lock)
111 #define template_unlock(template) lck_mtx_unlock(&(template)->lt_lock)
113 #define TEMPLATE_INUSE(s, t) { \
115 while (OSCompareAndSwap(0, 1, &((t)->lt_inuse))) \
119 #define TEMPLATE_IDLE(s, t) { \
125 * The explicit alignment is to ensure that atomic operations don't panic
128 struct ledger_entry
{
129 volatile uint32_t le_flags
;
130 ledger_amount_t le_limit
;
131 volatile ledger_amount_t le_credit
__attribute__((aligned(8)));
132 volatile ledger_amount_t le_debit
__attribute__((aligned(8)));
134 * XXX - the following two fields can go away if we move all of
135 * the refill logic into process policy
137 uint64_t le_refill_period
;
138 uint64_t le_last_refill
;
139 } __attribute__((aligned(8)));
143 struct ledger_template
*l_template
;
146 struct ledger_entry
*l_entries
;
149 static int ledger_cnt
= 0;
150 /* ledger ast helper functions */
151 static uint32_t ledger_check_needblock(ledger_t l
, uint64_t now
);
152 static kern_return_t
ledger_perform_blocking(ledger_t l
);
153 static uint32_t flag_set(volatile uint32_t *flags
, uint32_t bit
);
154 static uint32_t flag_clear(volatile uint32_t *flags
, uint32_t bit
);
158 debug_callback(const void *p0
, __unused
const void *p1
)
160 printf("ledger: resource exhausted [%s] for task %p\n",
161 (const char *)p0
, p1
);
165 /************************************/
168 abstime_to_nsecs(uint64_t abstime
)
172 absolutetime_to_nanoseconds(abstime
, &nsecs
);
177 nsecs_to_abstime(uint64_t nsecs
)
181 nanoseconds_to_absolutetime(nsecs
, &abstime
);
188 lck_grp_init(&ledger_lck_grp
, "ledger", LCK_GRP_ATTR_NULL
);
192 ledger_template_create(const char *name
)
194 ledger_template_t
template;
196 template = (ledger_template_t
)kalloc(sizeof (*template));
197 if (template == NULL
)
200 template->lt_name
= name
;
201 template->lt_refs
= 1;
202 template->lt_cnt
= 0;
203 template->lt_table_size
= 1;
204 template->lt_inuse
= 0;
205 lck_mtx_init(&template->lt_lock
, &ledger_lck_grp
, LCK_ATTR_NULL
);
207 template->lt_entries
= (struct entry_template
*)
208 kalloc(sizeof (struct entry_template
) * template->lt_table_size
);
209 if (template->lt_entries
== NULL
) {
210 kfree(template, sizeof (*template));
218 ledger_template_dereference(ledger_template_t
template)
220 template_lock(template);
222 template_unlock(template);
224 if (template->lt_refs
== 0)
225 kfree(template, sizeof (*template));
229 * Add a new entry to the list of entries in a ledger template. There is
230 * currently no mechanism to remove an entry. Implementing such a mechanism
231 * would require us to maintain per-entry reference counts, which we would
232 * prefer to avoid if possible.
235 ledger_entry_add(ledger_template_t
template, const char *key
,
236 const char *group
, const char *units
)
239 struct entry_template
*et
;
241 if ((key
== NULL
) || (strlen(key
) >= LEDGER_NAME_MAX
))
244 template_lock(template);
246 /* If the table is full, attempt to double its size */
247 if (template->lt_cnt
== template->lt_table_size
) {
248 struct entry_template
*new_entries
, *old_entries
;
252 old_cnt
= template->lt_table_size
;
253 old_sz
= (int)(old_cnt
* sizeof (struct entry_template
));
254 new_entries
= kalloc(old_sz
* 2);
255 if (new_entries
== NULL
) {
256 template_unlock(template);
259 memcpy(new_entries
, template->lt_entries
, old_sz
);
260 memset(((char *)new_entries
) + old_sz
, 0, old_sz
);
261 template->lt_table_size
= old_cnt
* 2;
263 old_entries
= template->lt_entries
;
265 TEMPLATE_INUSE(s
, template);
266 template->lt_entries
= new_entries
;
267 TEMPLATE_IDLE(s
, template);
269 kfree(old_entries
, old_sz
);
272 et
= &template->lt_entries
[template->lt_cnt
];
273 strlcpy(et
->et_key
, key
, LEDGER_NAME_MAX
);
274 strlcpy(et
->et_group
, group
, LEDGER_NAME_MAX
);
275 strlcpy(et
->et_units
, units
, LEDGER_NAME_MAX
);
276 et
->et_flags
= ENTRY_ACTIVE
;
277 et
->et_callback
= NULL
;
279 idx
= template->lt_cnt
++;
280 template_unlock(template);
287 ledger_entry_setactive(ledger_t ledger
, int entry
)
289 struct ledger_entry
*le
;
291 if ((ledger
== NULL
) || (entry
< 0) || (entry
>= ledger
->l_size
))
292 return (KERN_INVALID_ARGUMENT
);
294 le
= &ledger
->l_entries
[entry
];
295 if ((le
->le_flags
& ENTRY_ACTIVE
) == 0) {
296 flag_set(&le
->le_flags
, ENTRY_ACTIVE
);
298 return (KERN_SUCCESS
);
303 ledger_key_lookup(ledger_template_t
template, const char *key
)
307 template_lock(template);
308 for (idx
= 0; idx
< template->lt_cnt
; idx
++)
309 if (template->lt_entries
[idx
].et_key
&&
310 (strcmp(key
, template->lt_entries
[idx
].et_key
) == 0))
313 if (idx
>= template->lt_cnt
)
315 template_unlock(template);
321 * Create a new ledger based on the specified template. As part of the
322 * ledger creation we need to allocate space for a table of ledger entries.
323 * The size of the table is based on the size of the template at the time
324 * the ledger is created. If additional entries are added to the template
325 * after the ledger is created, they will not be tracked in this ledger.
328 ledger_instantiate(ledger_template_t
template, int entry_type
)
334 ledger
= (ledger_t
)kalloc(sizeof (struct ledger
));
336 return (LEDGER_NULL
);
338 ledger
->l_template
= template;
339 ledger
->l_id
= ledger_cnt
++;
342 template_lock(template);
344 ledger
->l_size
= template->lt_cnt
;
345 template_unlock(template);
347 sz
= ledger
->l_size
* sizeof (struct ledger_entry
);
348 ledger
->l_entries
= kalloc(sz
);
349 if (sz
&& (ledger
->l_entries
== NULL
)) {
350 ledger_template_dereference(template);
351 kfree(ledger
, sizeof(struct ledger
));
352 return (LEDGER_NULL
);
355 template_lock(template);
356 assert(ledger
->l_size
<= template->lt_cnt
);
357 for (i
= 0; i
< ledger
->l_size
; i
++) {
358 struct ledger_entry
*le
= &ledger
->l_entries
[i
];
359 struct entry_template
*et
= &template->lt_entries
[i
];
361 le
->le_flags
= et
->et_flags
;
362 /* make entry inactive by removing active bit */
363 if (entry_type
== LEDGER_CREATE_INACTIVE_ENTRIES
)
364 flag_clear(&le
->le_flags
, ENTRY_ACTIVE
);
366 * If template has a callback, this entry is opted-in,
369 if (et
->et_callback
!= NULL
)
370 flag_set(&le
->le_flags
, LEDGER_ACTION_CALLBACK
);
373 le
->le_limit
= LEDGER_LIMIT_INFINITY
;
374 le
->le_refill_period
= 0;
376 template_unlock(template);
382 flag_set(volatile uint32_t *flags
, uint32_t bit
)
384 return (OSBitOrAtomic(bit
, flags
));
388 flag_clear(volatile uint32_t *flags
, uint32_t bit
)
390 return (OSBitAndAtomic(~bit
, flags
));
394 * Take a reference on a ledger
397 ledger_reference(ledger_t ledger
)
399 if (!LEDGER_VALID(ledger
))
400 return (KERN_INVALID_ARGUMENT
);
401 OSIncrementAtomic(&ledger
->l_refs
);
402 return (KERN_SUCCESS
);
406 ledger_reference_count(ledger_t ledger
)
408 if (!LEDGER_VALID(ledger
))
411 return (ledger
->l_refs
);
415 * Remove a reference on a ledger. If this is the last reference,
416 * deallocate the unused ledger.
419 ledger_dereference(ledger_t ledger
)
423 if (!LEDGER_VALID(ledger
))
424 return (KERN_INVALID_ARGUMENT
);
426 v
= OSDecrementAtomic(&ledger
->l_refs
);
429 /* Just released the last reference. Free it. */
431 kfree(ledger
->l_entries
,
432 ledger
->l_size
* sizeof (struct ledger_entry
));
433 kfree(ledger
, sizeof (*ledger
));
436 return (KERN_SUCCESS
);
440 * Determine whether an entry has exceeded its limit.
443 limit_exceeded(struct ledger_entry
*le
)
445 ledger_amount_t balance
;
447 balance
= le
->le_credit
- le
->le_debit
;
448 if ((le
->le_limit
<= 0) && (balance
< le
->le_limit
))
451 if ((le
->le_limit
> 0) && (balance
> le
->le_limit
))
456 static inline struct ledger_callback
*
457 entry_get_callback(ledger_t ledger
, int entry
)
459 struct ledger_callback
*callback
;
462 TEMPLATE_INUSE(s
, ledger
->l_template
);
463 callback
= ledger
->l_template
->lt_entries
[entry
].et_callback
;
464 TEMPLATE_IDLE(s
, ledger
->l_template
);
470 * If the ledger value is positive, wake up anybody waiting on it.
473 ledger_limit_entry_wakeup(struct ledger_entry
*le
)
477 if (!limit_exceeded(le
)) {
478 flags
= flag_clear(&le
->le_flags
, CALLED_BACK
);
480 while (le
->le_flags
& WAKE_NEEDED
) {
481 flag_clear(&le
->le_flags
, WAKE_NEEDED
);
482 thread_wakeup((event_t
)le
);
488 * Refill the coffers.
491 ledger_refill(uint64_t now
, ledger_t ledger
, int entry
)
493 uint64_t elapsed
, period
, periods
;
494 struct ledger_entry
*le
;
495 ledger_amount_t balance
, due
;
498 le
= &ledger
->l_entries
[entry
];
501 * If another thread is handling the refill already, we're not
502 * needed. Just sit here for a few cycles while the other thread
503 * finishes updating the balance. If it takes too long, just return
504 * and we'll block again.
506 if (flag_set(&le
->le_flags
, REFILL_INPROGRESS
) & REFILL_INPROGRESS
) {
508 while (cnt
++ < 100 && (le
->le_flags
& REFILL_INPROGRESS
))
514 * See how many refill periods have passed since we last
517 period
= le
->le_refill_period
;
518 elapsed
= now
- le
->le_last_refill
;
519 if ((period
== 0) || (elapsed
< period
)) {
520 flag_clear(&le
->le_flags
, REFILL_INPROGRESS
);
525 * Optimize for the most common case of only one or two
529 while ((periods
< 2) && (elapsed
> 0)) {
535 * OK, it's been a long time. Do a divide to figure out
539 periods
= (now
- le
->le_last_refill
) / period
;
541 balance
= le
->le_credit
- le
->le_debit
;
542 due
= periods
* le
->le_limit
;
543 if (balance
- due
< 0)
545 OSAddAtomic64(due
, &le
->le_debit
);
548 * If we've completely refilled the pool, set the refill time to now.
549 * Otherwise set it to the time at which it last should have been
553 le
->le_last_refill
= now
;
555 le
->le_last_refill
+= (le
->le_refill_period
* periods
);
557 flag_clear(&le
->le_flags
, REFILL_INPROGRESS
);
559 lprintf(("Refill %lld %lld->%lld\n", periods
, balance
, balance
- due
));
560 if (!limit_exceeded(le
))
561 ledger_limit_entry_wakeup(le
);
565 ledger_check_new_balance(ledger_t ledger
, int entry
)
567 struct ledger_entry
*le
;
570 le
= &ledger
->l_entries
[entry
];
572 /* Check to see whether we're due a refill */
573 if (le
->le_refill_period
) {
574 now
= mach_absolute_time();
575 if ((now
- le
->le_last_refill
) > le
->le_refill_period
)
576 ledger_refill(now
, ledger
, entry
);
579 if (limit_exceeded(le
)) {
581 * We've exceeded the limit for this entry. There
582 * are several possible ways to handle it. We can block,
583 * we can execute a callback, or we can ignore it. In
584 * either of the first two cases, we want to set the AST
585 * flag so we can take the appropriate action just before
586 * leaving the kernel. The one caveat is that if we have
587 * already called the callback, we don't want to do it
588 * again until it gets rearmed.
590 if ((le
->le_flags
& LEDGER_ACTION_BLOCK
) ||
591 (!(le
->le_flags
& CALLED_BACK
) &&
592 entry_get_callback(ledger
, entry
))) {
593 set_astledger(current_thread());
597 * The balance on the account is below the limit. If
598 * there are any threads blocked on this entry, now would
599 * be a good time to wake them up.
601 if (le
->le_flags
& WAKE_NEEDED
)
602 ledger_limit_entry_wakeup(le
);
607 * Add value to an entry in a ledger.
610 ledger_credit(ledger_t ledger
, int entry
, ledger_amount_t amount
)
612 ledger_amount_t old
, new;
613 struct ledger_entry
*le
;
615 if (!ENTRY_VALID(ledger
, entry
) || (amount
< 0))
616 return (KERN_INVALID_VALUE
);
619 return (KERN_SUCCESS
);
621 le
= &ledger
->l_entries
[entry
];
623 old
= OSAddAtomic64(amount
, &le
->le_credit
);
625 lprintf(("%p Credit %lld->%lld\n", current_thread(), old
, new));
626 ledger_check_new_balance(ledger
, entry
);
628 return (KERN_SUCCESS
);
633 * Adjust the limit of a limited resource. This does not affect the
634 * current balance, so the change doesn't affect the thread until the
638 ledger_set_limit(ledger_t ledger
, int entry
, ledger_amount_t limit
)
640 struct ledger_entry
*le
;
642 if (!ENTRY_VALID(ledger
, entry
))
643 return (KERN_INVALID_VALUE
);
645 lprintf(("ledger_set_limit: %x\n", (uint32_t)limit
));
646 le
= &ledger
->l_entries
[entry
];
647 le
->le_limit
= limit
;
648 le
->le_last_refill
= 0;
649 flag_clear(&le
->le_flags
, CALLED_BACK
);
650 ledger_limit_entry_wakeup(le
);
652 return (KERN_SUCCESS
);
656 * Add a callback to be executed when the resource goes into deficit
659 ledger_set_callback(ledger_template_t
template, int entry
,
660 ledger_callback_t func
, const void *param0
, const void *param1
)
662 struct entry_template
*et
;
663 struct ledger_callback
*old_cb
, *new_cb
;
665 if ((entry
< 0) || (entry
>= template->lt_cnt
))
666 return (KERN_INVALID_VALUE
);
669 new_cb
= (struct ledger_callback
*)kalloc(sizeof (*new_cb
));
670 new_cb
->lc_func
= func
;
671 new_cb
->lc_param0
= param0
;
672 new_cb
->lc_param1
= param1
;
677 template_lock(template);
678 et
= &template->lt_entries
[entry
];
679 old_cb
= et
->et_callback
;
680 et
->et_callback
= new_cb
;
681 template_unlock(template);
683 kfree(old_cb
, sizeof (*old_cb
));
685 return (KERN_SUCCESS
);
689 * Disable callback notification for a specific ledger entry.
691 * Otherwise, if using a ledger template which specified a
692 * callback function (ledger_set_callback()), it will be invoked when
693 * the resource goes into deficit.
696 ledger_disable_callback(ledger_t ledger
, int entry
)
698 if (!ENTRY_VALID(ledger
, entry
))
699 return (KERN_INVALID_VALUE
);
701 flag_clear(&ledger
->l_entries
[entry
].le_flags
, LEDGER_ACTION_CALLBACK
);
702 return (KERN_SUCCESS
);
706 * Clear the called_back flag, indicating that we want to be notified
707 * again when the limit is next exceeded.
710 ledger_reset_callback(ledger_t ledger
, int entry
)
712 if (!ENTRY_VALID(ledger
, entry
))
713 return (KERN_INVALID_VALUE
);
715 flag_clear(&ledger
->l_entries
[entry
].le_flags
, CALLED_BACK
);
716 return (KERN_SUCCESS
);
720 * Adjust the automatic refill period.
723 ledger_set_period(ledger_t ledger
, int entry
, uint64_t period
)
725 struct ledger_entry
*le
;
727 lprintf(("ledger_set_period: %llx\n", period
));
728 if (!ENTRY_VALID(ledger
, entry
))
729 return (KERN_INVALID_VALUE
);
731 le
= &ledger
->l_entries
[entry
];
732 le
->le_refill_period
= nsecs_to_abstime(period
);
734 return (KERN_SUCCESS
);
738 ledger_set_action(ledger_t ledger
, int entry
, int action
)
740 lprintf(("ledger_set_action: %d\n", action
));
741 if (!ENTRY_VALID(ledger
, entry
))
742 return (KERN_INVALID_VALUE
);
744 flag_set(&ledger
->l_entries
[entry
].le_flags
, action
);
745 return (KERN_SUCCESS
);
749 set_astledger(thread_t thread
)
751 spl_t s
= splsched();
753 if (thread
== current_thread()) {
754 thread_ast_set(thread
, AST_LEDGER
);
755 ast_propagate(thread
->ast
);
760 thread_ast_set(thread
, AST_LEDGER
);
761 p
= thread
->last_processor
;
762 if ((p
!= PROCESSOR_NULL
) && (p
->state
== PROCESSOR_RUNNING
) &&
763 (p
->active_thread
== thread
))
765 thread_unlock(thread
);
772 ledger_debit(ledger_t ledger
, int entry
, ledger_amount_t amount
)
774 struct ledger_entry
*le
;
775 ledger_amount_t old
, new;
777 if (!ENTRY_VALID(ledger
, entry
) || (amount
< 0))
778 return (KERN_INVALID_ARGUMENT
);
781 return (KERN_SUCCESS
);
783 le
= &ledger
->l_entries
[entry
];
785 old
= OSAddAtomic64(amount
, &le
->le_debit
);
788 lprintf(("%p Debit %lld->%lld\n", thread
, old
, new));
789 ledger_check_new_balance(ledger
, entry
);
790 return (KERN_SUCCESS
);
795 ledger_ast(thread_t thread
)
797 struct ledger
*l
= thread
->t_ledger
;
798 struct ledger
*thl
= thread
->t_threadledger
;
802 task_t task
= thread
->task
;
804 lprintf(("Ledger AST for %p\n", thread
));
806 ASSERT(task
!= NULL
);
807 ASSERT(thread
== current_thread());
811 * Make sure this thread is up to date with regards to any task-wide per-thread
814 if ((task
->rusage_cpu_flags
& TASK_RUSECPU_FLAGS_PERTHR_LIMIT
) &&
815 ((thread
->options
& TH_OPT_PROC_CPULIMIT
) == 0) ) {
817 * Task has a per-thread CPU limit on it, and this thread
820 thread_set_cpulimit(THREAD_CPULIMIT_EXCEPTION
, task
->rusage_cpu_perthr_percentage
,
821 task
->rusage_cpu_perthr_interval
);
822 assert((thread
->options
& TH_OPT_PROC_CPULIMIT
) != 0);
823 } else if (((task
->rusage_cpu_flags
& TASK_RUSECPU_FLAGS_PERTHR_LIMIT
) == 0) &&
824 (thread
->options
& TH_OPT_PROC_CPULIMIT
)) {
826 * Task no longer has a per-thread CPU limit; remove this thread's
827 * corresponding CPU limit.
829 thread_set_cpulimit(THREAD_CPULIMIT_EXCEPTION
, 0, 0);
830 assert((thread
->options
& TH_OPT_PROC_CPULIMIT
) == 0);
834 * If the task or thread is being terminated, let's just get on with it
836 if ((l
== NULL
) || !task
->active
|| task
->halting
|| !thread
->active
)
840 * Examine all entries in deficit to see which might be eligble for
841 * an automatic refill, which require callbacks to be issued, and
842 * which require blocking.
845 now
= mach_absolute_time();
847 if (LEDGER_VALID(thl
)) {
848 block
|= ledger_check_needblock(thl
, now
);
850 block
|= ledger_check_needblock(l
, now
);
853 * If we are supposed to block on the availability of one or more
854 * resources, find the first entry in deficit for which we should wait.
855 * Schedule a refill if necessary and then sleep until the resource
859 if (LEDGER_VALID(thl
)) {
860 ret
= ledger_perform_blocking(thl
);
861 if (ret
!= KERN_SUCCESS
)
864 ret
= ledger_perform_blocking(l
);
865 if (ret
!= KERN_SUCCESS
)
871 ledger_check_needblock(ledger_t l
, uint64_t now
)
874 uint32_t flags
, block
= 0;
875 struct ledger_entry
*le
;
876 struct ledger_callback
*lc
;
879 for (i
= 0; i
< l
->l_size
; i
++) {
880 le
= &l
->l_entries
[i
];
881 if (limit_exceeded(le
) == FALSE
)
884 /* Check for refill eligibility */
885 if (le
->le_refill_period
) {
886 if ((le
->le_last_refill
+ le
->le_refill_period
) > now
) {
887 ledger_refill(now
, l
, i
);
888 if (limit_exceeded(le
) == FALSE
)
893 if (le
->le_flags
& LEDGER_ACTION_BLOCK
)
895 if ((le
->le_flags
& LEDGER_ACTION_CALLBACK
) == 0)
897 lc
= entry_get_callback(l
, i
);
899 flags
= flag_set(&le
->le_flags
, CALLED_BACK
);
900 /* Callback has already been called */
901 if (flags
& CALLED_BACK
)
903 lc
->lc_func(lc
->lc_param0
, lc
->lc_param1
);
909 /* return KERN_SUCCESS to continue, KERN_FAILURE to restart */
911 ledger_perform_blocking(ledger_t l
)
915 struct ledger_entry
*le
;
917 for (i
= 0; i
< l
->l_size
; i
++) {
918 le
= &l
->l_entries
[i
];
919 if ((!limit_exceeded(le
)) ||
920 ((le
->le_flags
& LEDGER_ACTION_BLOCK
) == 0))
923 /* Prepare to sleep until the resource is refilled */
924 ret
= assert_wait_deadline(le
, TRUE
,
925 le
->le_last_refill
+ le
->le_refill_period
);
926 if (ret
!= THREAD_WAITING
)
927 return(KERN_SUCCESS
);
929 /* Mark that somebody is waiting on this entry */
930 flag_set(&le
->le_flags
, WAKE_NEEDED
);
932 ret
= thread_block_reason(THREAD_CONTINUE_NULL
, NULL
,
934 if (ret
!= THREAD_AWAKENED
)
935 return(KERN_SUCCESS
);
938 * The world may have changed while we were asleep.
939 * Some other resource we need may have gone into
940 * deficit. Or maybe we're supposed to die now.
941 * Go back to the top and reevaluate.
943 return(KERN_FAILURE
);
945 return(KERN_SUCCESS
);
950 ledger_get_entries(ledger_t ledger
, int entry
, ledger_amount_t
*credit
,
951 ledger_amount_t
*debit
)
953 struct ledger_entry
*le
;
955 if (!ENTRY_VALID(ledger
, entry
))
956 return (KERN_INVALID_ARGUMENT
);
958 le
= &ledger
->l_entries
[entry
];
960 *credit
= le
->le_credit
;
961 *debit
= le
->le_debit
;
963 return (KERN_SUCCESS
);
967 ledger_template_info(void **buf
, int *len
)
969 struct ledger_template_info
*lti
;
970 struct entry_template
*et
;
975 * Since all tasks share a ledger template, we'll just use the
976 * caller's as the source.
978 l
= current_task()->ledger
;
979 if ((*len
< 0) || (l
== NULL
))
982 if (*len
> l
->l_size
)
984 lti
= kalloc((*len
) * sizeof (struct ledger_template_info
));
989 template_lock(l
->l_template
);
990 et
= l
->l_template
->lt_entries
;
992 for (i
= 0; i
< *len
; i
++) {
993 memset(lti
, 0, sizeof (*lti
));
994 strlcpy(lti
->lti_name
, et
->et_key
, LEDGER_NAME_MAX
);
995 strlcpy(lti
->lti_group
, et
->et_group
, LEDGER_NAME_MAX
);
996 strlcpy(lti
->lti_units
, et
->et_units
, LEDGER_NAME_MAX
);
1000 template_unlock(l
->l_template
);
1006 ledger_entry_info(task_t task
, void **buf
, int *len
)
1008 struct ledger_entry_info
*lei
;
1009 struct ledger_entry
*le
;
1010 uint64_t now
= mach_absolute_time();
1014 if ((*len
< 0) || ((l
= task
->ledger
) == NULL
))
1017 if (*len
> l
->l_size
)
1019 lei
= kalloc((*len
) * sizeof (struct ledger_entry_info
));
1026 for (i
= 0; i
< *len
; i
++) {
1027 memset(lei
, 0, sizeof (*lei
));
1028 lei
->lei_limit
= le
->le_limit
;
1029 lei
->lei_credit
= le
->le_credit
;
1030 lei
->lei_debit
= le
->le_debit
;
1031 lei
->lei_balance
= lei
->lei_credit
- lei
->lei_debit
;
1032 lei
->lei_refill_period
=
1033 abstime_to_nsecs(le
->le_refill_period
);
1034 lei
->lei_last_refill
=
1035 abstime_to_nsecs(now
- le
->le_last_refill
);
1044 ledger_info(task_t task
, struct ledger_info
*info
)
1048 if ((l
= task
->ledger
) == NULL
)
1051 memset(info
, 0, sizeof (*info
));
1053 strlcpy(info
->li_name
, l
->l_template
->lt_name
, LEDGER_NAME_MAX
);
1054 info
->li_id
= l
->l_id
;
1055 info
->li_entries
= l
->l_size
;
1061 ledger_limit(task_t task
, struct ledger_limit_args
*args
)
1067 if ((l
= task
->ledger
) == NULL
)
1070 idx
= ledger_key_lookup(l
->l_template
, args
->lla_name
);
1071 if ((idx
< 0) || (idx
>= l
->l_size
))
1075 * XXX - this doesn't really seem like the right place to have
1076 * a context-sensitive conversion of userspace units into kernel
1077 * units. For now I'll handwave and say that the ledger() system
1078 * call isn't meant for civilians to use - they should be using
1079 * the process policy interfaces.
1081 if (idx
== task_ledgers
.cpu_time
) {
1084 if (args
->lla_refill_period
) {
1086 * If a refill is scheduled, then the limit is
1087 * specified as a percentage of one CPU. The
1088 * syscall specifies the refill period in terms of
1089 * milliseconds, so we need to convert to nsecs.
1091 args
->lla_refill_period
*= 1000000;
1092 nsecs
= args
->lla_limit
*
1093 (args
->lla_refill_period
/ 100);
1094 lprintf(("CPU limited to %lld nsecs per second\n",
1098 * If no refill is scheduled, then this is a
1099 * fixed amount of CPU time (in nsecs) that can
1102 nsecs
= args
->lla_limit
;
1103 lprintf(("CPU limited to %lld nsecs\n", nsecs
));
1105 limit
= nsecs_to_abstime(nsecs
);
1107 limit
= args
->lla_limit
;
1108 lprintf(("%s limited to %lld\n", args
->lla_name
, limit
));
1111 if (args
->lla_refill_period
> 0)
1112 ledger_set_period(l
, idx
, args
->lla_refill_period
);
1114 ledger_set_limit(l
, idx
, limit
);
1115 flag_set(&l
->l_entries
[idx
].le_flags
, LEDGER_ACTION_BLOCK
);