]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/ledger.c
cf1a7aa02763bee878f4576f2de1d954ec85d5e4
[apple/xnu.git] / osfmk / kern / ledger.c
1 /*
2 * Copyright (c) 2010 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * @OSF_COPYRIGHT@
30 */
31
32 #include <kern/lock.h>
33 #include <kern/ledger.h>
34 #include <kern/kalloc.h>
35 #include <kern/task.h>
36
37 #include <kern/processor.h>
38 #include <kern/machine.h>
39 #include <kern/queue.h>
40 #include <sys/errno.h>
41
42 #include <libkern/OSAtomic.h>
43 #include <mach/mach_types.h>
44
45 /*
46 * Ledger entry flags. Bits in second nibble (masked by 0xF0) are used for
47 * ledger actions (LEDGER_ACTION_BLOCK, etc).
48 */
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 */
55
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))
60
61 #ifdef LEDGER_DEBUG
62 int ledger_debug = 0;
63
64 #define ASSERT(a) assert(a)
65 #define lprintf(a) if (ledger_debug) { \
66 printf("%lld ", abstime_to_nsecs(mach_absolute_time() / 1000000)); \
67 printf a ; \
68 }
69 #else
70 #define lprintf(a)
71 #define ASSERT(a)
72 #endif
73
74 struct ledger_callback {
75 ledger_callback_t lc_func;
76 const void *lc_param0;
77 const void *lc_param1;
78 };
79
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];
84 uint32_t et_flags;
85 struct ledger_callback *et_callback;
86 };
87
88 lck_grp_t ledger_lck_grp;
89
90 /*
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.
99 */
100 struct ledger_template {
101 const char *lt_name;
102 int lt_refs;
103 int lt_cnt;
104 int lt_table_size;
105 volatile uint32_t lt_inuse;
106 lck_mtx_t lt_lock;
107 struct entry_template *lt_entries;
108 };
109
110 #define template_lock(template) lck_mtx_lock(&(template)->lt_lock)
111 #define template_unlock(template) lck_mtx_unlock(&(template)->lt_lock)
112
113 #define TEMPLATE_INUSE(s, t) { \
114 s = splsched(); \
115 while (OSCompareAndSwap(0, 1, &((t)->lt_inuse))) \
116 ; \
117 }
118
119 #define TEMPLATE_IDLE(s, t) { \
120 (t)->lt_inuse = 0; \
121 splx(s); \
122 }
123
124 /*
125 * The explicit alignment is to ensure that atomic operations don't panic
126 * on ARM.
127 */
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)));
133 /*
134 * XXX - the following two fields can go away if we move all of
135 * the refill logic into process policy
136 */
137 uint64_t le_refill_period;
138 uint64_t le_last_refill;
139 } __attribute__((aligned(8)));
140
141 struct ledger {
142 int l_id;
143 struct ledger_template *l_template;
144 int l_refs;
145 int l_size;
146 struct ledger_entry *l_entries;
147 };
148
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);
155
156 #if 0
157 static void
158 debug_callback(const void *p0, __unused const void *p1)
159 {
160 printf("ledger: resource exhausted [%s] for task %p\n",
161 (const char *)p0, p1);
162 }
163 #endif
164
165 /************************************/
166
167 static uint64_t
168 abstime_to_nsecs(uint64_t abstime)
169 {
170 uint64_t nsecs;
171
172 absolutetime_to_nanoseconds(abstime, &nsecs);
173 return (nsecs);
174 }
175
176 static uint64_t
177 nsecs_to_abstime(uint64_t nsecs)
178 {
179 uint64_t abstime;
180
181 nanoseconds_to_absolutetime(nsecs, &abstime);
182 return (abstime);
183 }
184
185 void
186 ledger_init(void)
187 {
188 lck_grp_init(&ledger_lck_grp, "ledger", LCK_GRP_ATTR_NULL);
189 }
190
191 ledger_template_t
192 ledger_template_create(const char *name)
193 {
194 ledger_template_t template;
195
196 template = (ledger_template_t)kalloc(sizeof (*template));
197 if (template == NULL)
198 return (NULL);
199
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);
206
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));
211 template = NULL;
212 }
213
214 return (template);
215 }
216
217 void
218 ledger_template_dereference(ledger_template_t template)
219 {
220 template_lock(template);
221 template->lt_refs--;
222 template_unlock(template);
223
224 if (template->lt_refs == 0)
225 kfree(template, sizeof (*template));
226 }
227
228 /*
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.
233 */
234 int
235 ledger_entry_add(ledger_template_t template, const char *key,
236 const char *group, const char *units)
237 {
238 int idx;
239 struct entry_template *et;
240
241 if ((key == NULL) || (strlen(key) >= LEDGER_NAME_MAX))
242 return (-1);
243
244 template_lock(template);
245
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;
249 int old_cnt, old_sz;
250 spl_t s;
251
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);
257 return (-1);
258 }
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;
262
263 old_entries = template->lt_entries;
264
265 TEMPLATE_INUSE(s, template);
266 template->lt_entries = new_entries;
267 TEMPLATE_IDLE(s, template);
268
269 kfree(old_entries, old_sz);
270 }
271
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;
278
279 idx = template->lt_cnt++;
280 template_unlock(template);
281
282 return (idx);
283 }
284
285
286 kern_return_t
287 ledger_entry_setactive(ledger_t ledger, int entry)
288 {
289 struct ledger_entry *le;
290
291 if ((ledger == NULL) || (entry < 0) || (entry >= ledger->l_size))
292 return (KERN_INVALID_ARGUMENT);
293
294 le = &ledger->l_entries[entry];
295 if ((le->le_flags & ENTRY_ACTIVE) == 0) {
296 flag_set(&le->le_flags, ENTRY_ACTIVE);
297 }
298 return (KERN_SUCCESS);
299 }
300
301
302 int
303 ledger_key_lookup(ledger_template_t template, const char *key)
304 {
305 int idx;
306
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))
311 break;
312
313 if (idx >= template->lt_cnt)
314 idx = -1;
315 template_unlock(template);
316
317 return (idx);
318 }
319
320 /*
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.
326 */
327 ledger_t
328 ledger_instantiate(ledger_template_t template, int entry_type)
329 {
330 ledger_t ledger;
331 size_t sz;
332 int i;
333
334 ledger = (ledger_t)kalloc(sizeof (struct ledger));
335 if (ledger == NULL)
336 return (LEDGER_NULL);
337
338 ledger->l_template = template;
339 ledger->l_id = ledger_cnt++;
340 ledger->l_refs = 1;
341
342 template_lock(template);
343 template->lt_refs++;
344 ledger->l_size = template->lt_cnt;
345 template_unlock(template);
346
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);
353 }
354
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];
360
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);
365 /*
366 * If template has a callback, this entry is opted-in,
367 * by default.
368 */
369 if (et->et_callback != NULL)
370 flag_set(&le->le_flags, LEDGER_ACTION_CALLBACK);
371 le->le_credit = 0;
372 le->le_debit = 0;
373 le->le_limit = LEDGER_LIMIT_INFINITY;
374 le->le_refill_period = 0;
375 }
376 template_unlock(template);
377
378 return (ledger);
379 }
380
381 static uint32_t
382 flag_set(volatile uint32_t *flags, uint32_t bit)
383 {
384 return (OSBitOrAtomic(bit, flags));
385 }
386
387 static uint32_t
388 flag_clear(volatile uint32_t *flags, uint32_t bit)
389 {
390 return (OSBitAndAtomic(~bit, flags));
391 }
392
393 /*
394 * Take a reference on a ledger
395 */
396 kern_return_t
397 ledger_reference(ledger_t ledger)
398 {
399 if (!LEDGER_VALID(ledger))
400 return (KERN_INVALID_ARGUMENT);
401 OSIncrementAtomic(&ledger->l_refs);
402 return (KERN_SUCCESS);
403 }
404
405 int
406 ledger_reference_count(ledger_t ledger)
407 {
408 if (!LEDGER_VALID(ledger))
409 return (-1);
410
411 return (ledger->l_refs);
412 }
413
414 /*
415 * Remove a reference on a ledger. If this is the last reference,
416 * deallocate the unused ledger.
417 */
418 kern_return_t
419 ledger_dereference(ledger_t ledger)
420 {
421 int v;
422
423 if (!LEDGER_VALID(ledger))
424 return (KERN_INVALID_ARGUMENT);
425
426 v = OSDecrementAtomic(&ledger->l_refs);
427 ASSERT(v >= 1);
428
429 /* Just released the last reference. Free it. */
430 if (v == 1) {
431 kfree(ledger->l_entries,
432 ledger->l_size * sizeof (struct ledger_entry));
433 kfree(ledger, sizeof (*ledger));
434 }
435
436 return (KERN_SUCCESS);
437 }
438
439 /*
440 * Determine whether an entry has exceeded its limit.
441 */
442 static inline int
443 limit_exceeded(struct ledger_entry *le)
444 {
445 ledger_amount_t balance;
446
447 balance = le->le_credit - le->le_debit;
448 if ((le->le_limit <= 0) && (balance < le->le_limit))
449 return (1);
450
451 if ((le->le_limit > 0) && (balance > le->le_limit))
452 return (1);
453 return (0);
454 }
455
456 static inline struct ledger_callback *
457 entry_get_callback(ledger_t ledger, int entry)
458 {
459 struct ledger_callback *callback;
460 spl_t s;
461
462 TEMPLATE_INUSE(s, ledger->l_template);
463 callback = ledger->l_template->lt_entries[entry].et_callback;
464 TEMPLATE_IDLE(s, ledger->l_template);
465
466 return (callback);
467 }
468
469 /*
470 * If the ledger value is positive, wake up anybody waiting on it.
471 */
472 static inline void
473 ledger_limit_entry_wakeup(struct ledger_entry *le)
474 {
475 uint32_t flags;
476
477 if (!limit_exceeded(le)) {
478 flags = flag_clear(&le->le_flags, CALLED_BACK);
479
480 while (le->le_flags & WAKE_NEEDED) {
481 flag_clear(&le->le_flags, WAKE_NEEDED);
482 thread_wakeup((event_t)le);
483 }
484 }
485 }
486
487 /*
488 * Refill the coffers.
489 */
490 static void
491 ledger_refill(uint64_t now, ledger_t ledger, int entry)
492 {
493 uint64_t elapsed, period, periods;
494 struct ledger_entry *le;
495 ledger_amount_t balance, due;
496 int cnt;
497
498 le = &ledger->l_entries[entry];
499
500 /*
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.
505 */
506 if (flag_set(&le->le_flags, REFILL_INPROGRESS) & REFILL_INPROGRESS) {
507 cnt = 0;
508 while (cnt++ < 100 && (le->le_flags & REFILL_INPROGRESS))
509 ;
510 return;
511 }
512
513 /*
514 * See how many refill periods have passed since we last
515 * did a refill.
516 */
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);
521 return;
522 }
523
524 /*
525 * Optimize for the most common case of only one or two
526 * periods elapsing.
527 */
528 periods = 0;
529 while ((periods < 2) && (elapsed > 0)) {
530 periods++;
531 elapsed -= period;
532 }
533
534 /*
535 * OK, it's been a long time. Do a divide to figure out
536 * how long.
537 */
538 if (elapsed > 0)
539 periods = (now - le->le_last_refill) / period;
540
541 balance = le->le_credit - le->le_debit;
542 due = periods * le->le_limit;
543 if (balance - due < 0)
544 due = balance;
545 OSAddAtomic64(due, &le->le_debit);
546
547 /*
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
550 * fully refilled.
551 */
552 if (balance == due)
553 le->le_last_refill = now;
554 else
555 le->le_last_refill += (le->le_refill_period * periods);
556
557 flag_clear(&le->le_flags, REFILL_INPROGRESS);
558
559 lprintf(("Refill %lld %lld->%lld\n", periods, balance, balance - due));
560 if (!limit_exceeded(le))
561 ledger_limit_entry_wakeup(le);
562 }
563
564 static void
565 ledger_check_new_balance(ledger_t ledger, int entry)
566 {
567 struct ledger_entry *le;
568 uint64_t now;
569
570 le = &ledger->l_entries[entry];
571
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);
577 }
578
579 if (limit_exceeded(le)) {
580 /*
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.
589 */
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());
594 }
595 } else {
596 /*
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.
600 */
601 if (le->le_flags & WAKE_NEEDED)
602 ledger_limit_entry_wakeup(le);
603 }
604 }
605
606 /*
607 * Add value to an entry in a ledger.
608 */
609 kern_return_t
610 ledger_credit(ledger_t ledger, int entry, ledger_amount_t amount)
611 {
612 ledger_amount_t old, new;
613 struct ledger_entry *le;
614
615 if (!ENTRY_VALID(ledger, entry) || (amount < 0))
616 return (KERN_INVALID_VALUE);
617
618 if (amount == 0)
619 return (KERN_SUCCESS);
620
621 le = &ledger->l_entries[entry];
622
623 old = OSAddAtomic64(amount, &le->le_credit);
624 new = old + amount;
625 lprintf(("%p Credit %lld->%lld\n", current_thread(), old, new));
626 ledger_check_new_balance(ledger, entry);
627
628 return (KERN_SUCCESS);
629 }
630
631
632 /*
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
635 * next refill.
636 */
637 kern_return_t
638 ledger_set_limit(ledger_t ledger, int entry, ledger_amount_t limit)
639 {
640 struct ledger_entry *le;
641
642 if (!ENTRY_VALID(ledger, entry))
643 return (KERN_INVALID_VALUE);
644
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);
651
652 return (KERN_SUCCESS);
653 }
654
655 /*
656 * Add a callback to be executed when the resource goes into deficit
657 */
658 kern_return_t
659 ledger_set_callback(ledger_template_t template, int entry,
660 ledger_callback_t func, const void *param0, const void *param1)
661 {
662 struct entry_template *et;
663 struct ledger_callback *old_cb, *new_cb;
664
665 if ((entry < 0) || (entry >= template->lt_cnt))
666 return (KERN_INVALID_VALUE);
667
668 if (func) {
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;
673 } else {
674 new_cb = NULL;
675 }
676
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);
682 if (old_cb)
683 kfree(old_cb, sizeof (*old_cb));
684
685 return (KERN_SUCCESS);
686 }
687
688 /*
689 * Disable callback notification for a specific ledger entry.
690 *
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.
694 */
695 kern_return_t
696 ledger_disable_callback(ledger_t ledger, int entry)
697 {
698 if (!ENTRY_VALID(ledger, entry))
699 return (KERN_INVALID_VALUE);
700
701 flag_clear(&ledger->l_entries[entry].le_flags, LEDGER_ACTION_CALLBACK);
702 return (KERN_SUCCESS);
703 }
704
705 /*
706 * Clear the called_back flag, indicating that we want to be notified
707 * again when the limit is next exceeded.
708 */
709 kern_return_t
710 ledger_reset_callback(ledger_t ledger, int entry)
711 {
712 if (!ENTRY_VALID(ledger, entry))
713 return (KERN_INVALID_VALUE);
714
715 flag_clear(&ledger->l_entries[entry].le_flags, CALLED_BACK);
716 return (KERN_SUCCESS);
717 }
718
719 /*
720 * Adjust the automatic refill period.
721 */
722 kern_return_t
723 ledger_set_period(ledger_t ledger, int entry, uint64_t period)
724 {
725 struct ledger_entry *le;
726
727 lprintf(("ledger_set_period: %llx\n", period));
728 if (!ENTRY_VALID(ledger, entry))
729 return (KERN_INVALID_VALUE);
730
731 le = &ledger->l_entries[entry];
732 le->le_refill_period = nsecs_to_abstime(period);
733
734 return (KERN_SUCCESS);
735 }
736
737 kern_return_t
738 ledger_set_action(ledger_t ledger, int entry, int action)
739 {
740 lprintf(("ledger_set_action: %d\n", action));
741 if (!ENTRY_VALID(ledger, entry))
742 return (KERN_INVALID_VALUE);
743
744 flag_set(&ledger->l_entries[entry].le_flags, action);
745 return (KERN_SUCCESS);
746 }
747
748 void
749 set_astledger(thread_t thread)
750 {
751 spl_t s = splsched();
752
753 if (thread == current_thread()) {
754 thread_ast_set(thread, AST_LEDGER);
755 ast_propagate(thread->ast);
756 } else {
757 processor_t p;
758
759 thread_lock(thread);
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))
764 cause_ast_check(p);
765 thread_unlock(thread);
766 }
767
768 splx(s);
769 }
770
771 kern_return_t
772 ledger_debit(ledger_t ledger, int entry, ledger_amount_t amount)
773 {
774 struct ledger_entry *le;
775 ledger_amount_t old, new;
776
777 if (!ENTRY_VALID(ledger, entry) || (amount < 0))
778 return (KERN_INVALID_ARGUMENT);
779
780 if (amount == 0)
781 return (KERN_SUCCESS);
782
783 le = &ledger->l_entries[entry];
784
785 old = OSAddAtomic64(amount, &le->le_debit);
786 new = old + amount;
787
788 lprintf(("%p Debit %lld->%lld\n", thread, old, new));
789 ledger_check_new_balance(ledger, entry);
790 return (KERN_SUCCESS);
791
792 }
793
794 void
795 ledger_ast(thread_t thread)
796 {
797 struct ledger *l = thread->t_ledger;
798 struct ledger *thl = thread->t_threadledger;
799 uint32_t block;
800 uint64_t now;
801 kern_return_t ret;
802 task_t task = thread->task;
803
804 lprintf(("Ledger AST for %p\n", thread));
805
806 ASSERT(task != NULL);
807 ASSERT(thread == current_thread());
808
809 top:
810 /*
811 * Make sure this thread is up to date with regards to any task-wide per-thread
812 * CPU limit.
813 */
814 if ((task->rusage_cpu_flags & TASK_RUSECPU_FLAGS_PERTHR_LIMIT) &&
815 ((thread->options & TH_OPT_PROC_CPULIMIT) == 0) ) {
816 /*
817 * Task has a per-thread CPU limit on it, and this thread
818 * needs it applied.
819 */
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)) {
825 /*
826 * Task no longer has a per-thread CPU limit; remove this thread's
827 * corresponding CPU limit.
828 */
829 thread_set_cpulimit(THREAD_CPULIMIT_EXCEPTION, 0, 0);
830 assert((thread->options & TH_OPT_PROC_CPULIMIT) == 0);
831 }
832
833 /*
834 * If the task or thread is being terminated, let's just get on with it
835 */
836 if ((l == NULL) || !task->active || task->halting || !thread->active)
837 return;
838
839 /*
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.
843 */
844 block = 0;
845 now = mach_absolute_time();
846
847 if (LEDGER_VALID(thl)) {
848 block |= ledger_check_needblock(thl, now);
849 }
850 block |= ledger_check_needblock(l, now);
851
852 /*
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
856 * becomes available.
857 */
858 if (block) {
859 if (LEDGER_VALID(thl)) {
860 ret = ledger_perform_blocking(thl);
861 if (ret != KERN_SUCCESS)
862 goto top;
863 }
864 ret = ledger_perform_blocking(l);
865 if (ret != KERN_SUCCESS)
866 goto top;
867 } /* block */
868 }
869
870 static uint32_t
871 ledger_check_needblock(ledger_t l, uint64_t now)
872 {
873 int i;
874 uint32_t flags, block = 0;
875 struct ledger_entry *le;
876 struct ledger_callback *lc;
877
878
879 for (i = 0; i < l->l_size; i++) {
880 le = &l->l_entries[i];
881 if (limit_exceeded(le) == FALSE)
882 continue;
883
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)
889 continue;
890 }
891 }
892
893 if (le->le_flags & LEDGER_ACTION_BLOCK)
894 block = 1;
895 if ((le->le_flags & LEDGER_ACTION_CALLBACK) == 0)
896 continue;
897 lc = entry_get_callback(l, i);
898 assert(lc != NULL);
899 flags = flag_set(&le->le_flags, CALLED_BACK);
900 /* Callback has already been called */
901 if (flags & CALLED_BACK)
902 continue;
903 lc->lc_func(lc->lc_param0, lc->lc_param1);
904 }
905 return(block);
906 }
907
908
909 /* return KERN_SUCCESS to continue, KERN_FAILURE to restart */
910 static kern_return_t
911 ledger_perform_blocking(ledger_t l)
912 {
913 int i;
914 kern_return_t ret;
915 struct ledger_entry *le;
916
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))
921 continue;
922
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);
928
929 /* Mark that somebody is waiting on this entry */
930 flag_set(&le->le_flags, WAKE_NEEDED);
931
932 ret = thread_block_reason(THREAD_CONTINUE_NULL, NULL,
933 AST_LEDGER);
934 if (ret != THREAD_AWAKENED)
935 return(KERN_SUCCESS);
936
937 /*
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.
942 */
943 return(KERN_FAILURE);
944 }
945 return(KERN_SUCCESS);
946 }
947
948
949 kern_return_t
950 ledger_get_entries(ledger_t ledger, int entry, ledger_amount_t *credit,
951 ledger_amount_t *debit)
952 {
953 struct ledger_entry *le;
954
955 if (!ENTRY_VALID(ledger, entry))
956 return (KERN_INVALID_ARGUMENT);
957
958 le = &ledger->l_entries[entry];
959
960 *credit = le->le_credit;
961 *debit = le->le_debit;
962
963 return (KERN_SUCCESS);
964 }
965
966 int
967 ledger_template_info(void **buf, int *len)
968 {
969 struct ledger_template_info *lti;
970 struct entry_template *et;
971 int i;
972 ledger_t l;
973
974 /*
975 * Since all tasks share a ledger template, we'll just use the
976 * caller's as the source.
977 */
978 l = current_task()->ledger;
979 if ((*len < 0) || (l == NULL))
980 return (EINVAL);
981
982 if (*len > l->l_size)
983 *len = l->l_size;
984 lti = kalloc((*len) * sizeof (struct ledger_template_info));
985 if (lti == NULL)
986 return (ENOMEM);
987 *buf = lti;
988
989 template_lock(l->l_template);
990 et = l->l_template->lt_entries;
991
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);
997 et++;
998 lti++;
999 }
1000 template_unlock(l->l_template);
1001
1002 return (0);
1003 }
1004
1005 int
1006 ledger_entry_info(task_t task, void **buf, int *len)
1007 {
1008 struct ledger_entry_info *lei;
1009 struct ledger_entry *le;
1010 uint64_t now = mach_absolute_time();
1011 int i;
1012 ledger_t l;
1013
1014 if ((*len < 0) || ((l = task->ledger) == NULL))
1015 return (EINVAL);
1016
1017 if (*len > l->l_size)
1018 *len = l->l_size;
1019 lei = kalloc((*len) * sizeof (struct ledger_entry_info));
1020 if (lei == NULL)
1021 return (ENOMEM);
1022 *buf = lei;
1023
1024 le = l->l_entries;
1025
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);
1036 le++;
1037 lei++;
1038 }
1039
1040 return (0);
1041 }
1042
1043 int
1044 ledger_info(task_t task, struct ledger_info *info)
1045 {
1046 ledger_t l;
1047
1048 if ((l = task->ledger) == NULL)
1049 return (ENOENT);
1050
1051 memset(info, 0, sizeof (*info));
1052
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;
1056 return (0);
1057 }
1058
1059 #ifdef LEDGER_DEBUG
1060 int
1061 ledger_limit(task_t task, struct ledger_limit_args *args)
1062 {
1063 ledger_t l;
1064 int64_t limit;
1065 int idx;
1066
1067 if ((l = task->ledger) == NULL)
1068 return (EINVAL);
1069
1070 idx = ledger_key_lookup(l->l_template, args->lla_name);
1071 if ((idx < 0) || (idx >= l->l_size))
1072 return (EINVAL);
1073
1074 /*
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.
1080 */
1081 if (idx == task_ledgers.cpu_time) {
1082 int64_t nsecs;
1083
1084 if (args->lla_refill_period) {
1085 /*
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.
1090 */
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",
1095 nsecs));
1096 } else {
1097 /*
1098 * If no refill is scheduled, then this is a
1099 * fixed amount of CPU time (in nsecs) that can
1100 * be consumed.
1101 */
1102 nsecs = args->lla_limit;
1103 lprintf(("CPU limited to %lld nsecs\n", nsecs));
1104 }
1105 limit = nsecs_to_abstime(nsecs);
1106 } else {
1107 limit = args->lla_limit;
1108 lprintf(("%s limited to %lld\n", args->lla_name, limit));
1109 }
1110
1111 if (args->lla_refill_period > 0)
1112 ledger_set_period(l, idx, args->lla_refill_period);
1113
1114 ledger_set_limit(l, idx, limit);
1115 flag_set(&l->l_entries[idx].le_flags, LEDGER_ACTION_BLOCK);
1116 return (0);
1117 }
1118 #endif