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