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