]> git.saurik.com Git - apple/xnu.git/blobdiff - osfmk/kern/ledger.c
xnu-6153.61.1.tar.gz
[apple/xnu.git] / osfmk / kern / ledger.c
index ec35a3a52351b35d29d703bad016b6c94ab89288..e905ee666a1862db6fb2c6e3d12ab29bb1feaf5d 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (c) 2010 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2010-2018 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
- * 
+ *
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * unlawful or unlicensed copies of an Apple operating system, or to
  * circumvent, violate, or enable the circumvention or violation of, any
  * terms of an Apple operating system software license agreement.
- * 
+ *
  * Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this file.
- * 
+ *
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
@@ -22,7 +22,7 @@
  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  * Please see the License for the specific language governing rights and
  * limitations under the License.
- * 
+ *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
 /*
@@ -34,6 +34,7 @@
 #include <kern/kalloc.h>
 #include <kern/task.h>
 #include <kern/thread.h>
+#include <kern/coalition.h>
 
 #include <kern/processor.h>
 #include <kern/machine.h>
 #include <mach/mach_types.h>
 #include <os/overflow.h>
 
+#include <vm/pmap.h>
+
 /*
  * Ledger entry flags. Bits in second nibble (masked by 0xF0) are used for
  * ledger actions (LEDGER_ACTION_BLOCK, etc).
  */
-#define        LF_ENTRY_ACTIVE         0x0001  /* entry is active if set */
-#define        LF_WAKE_NEEDED          0x0100  /* one or more threads are asleep */
-#define        LF_WAKE_INPROGRESS      0x0200  /* the wait queue is being processed */
-#define        LF_REFILL_SCHEDULED     0x0400  /* a refill timer has been set */
-#define        LF_REFILL_INPROGRESS    0x0800  /* the ledger is being refilled */
-#define        LF_CALLED_BACK          0x1000  /* callback was called for balance in deficit */
-#define        LF_WARNED               0x2000  /* callback was called for balance warning */ 
-#define        LF_TRACKING_MAX         0x4000  /* track max balance. Exclusive w.r.t refill */
-#define LF_PANIC_ON_NEGATIVE   0x8000  /* panic if it goes negative */
-#define LF_TRACK_CREDIT_ONLY   0x10000 /* only update "credit" */
+#define LF_ENTRY_ACTIVE         0x0001  /* entry is active if set */
+#define LF_WAKE_NEEDED          0x0100  /* one or more threads are asleep */
+#define LF_WAKE_INPROGRESS      0x0200  /* the wait queue is being processed */
+#define LF_REFILL_SCHEDULED     0x0400  /* a refill timer has been set */
+#define LF_REFILL_INPROGRESS    0x0800  /* the ledger is being refilled */
+#define LF_CALLED_BACK          0x1000  /* callback was called for balance in deficit */
+#define LF_WARNED               0x2000  /* callback was called for balance warning */
+#define LF_TRACKING_MAX         0x4000  /* track max balance. Exclusive w.r.t refill */
+#define LF_PANIC_ON_NEGATIVE    0x8000  /* panic if it goes negative */
+#define LF_TRACK_CREDIT_ONLY    0x10000 /* only update "credit" */
 
 /* Determine whether a ledger entry exists and has been initialized and active */
-#define        ENTRY_VALID(l, e)                                       \
-       (((l) != NULL) && ((e) >= 0) && ((e) < (l)->l_size) &&  \
+#define ENTRY_VALID(l, e)                                       \
+       (((l) != NULL) && ((e) >= 0) && ((e) < (l)->l_size) &&  \
        (((l)->l_entries[e].le_flags & LF_ENTRY_ACTIVE) == LF_ENTRY_ACTIVE))
 
 #define ASSERT(a) assert(a)
 #ifdef LEDGER_DEBUG
 int ledger_debug = 0;
 
-#define        lprintf(a) if (ledger_debug) {                                  \
+#define lprintf(a) if (ledger_debug) {                                  \
        printf("%lld  ", abstime_to_nsecs(mach_absolute_time() / 1000000)); \
-       printf a ;                                                      \
+       printf a ;                                                      \
 }
 #else
-#define        lprintf(a)
+#define lprintf(a)
 #endif
 
 struct ledger_callback {
-       ledger_callback_t       lc_func;
-       const void              *lc_param0;
-       const void              *lc_param1;
+       ledger_callback_t       lc_func;
+       const void              *lc_param0;
+       const void              *lc_param1;
 };
 
 struct entry_template {
-       char                    et_key[LEDGER_NAME_MAX];
-       char                    et_group[LEDGER_NAME_MAX];
-       char                    et_units[LEDGER_NAME_MAX];
-       uint32_t                et_flags;
-       struct ledger_callback  *et_callback;
+       char                    et_key[LEDGER_NAME_MAX];
+       char                    et_group[LEDGER_NAME_MAX];
+       char                    et_units[LEDGER_NAME_MAX];
+       uint32_t                et_flags;
+       struct ledger_callback  *et_callback;
 };
 
 lck_grp_t ledger_lck_grp;
+os_refgrp_decl(static, ledger_refgrp, "ledger", NULL);
 
 /*
  * Modifying the reference count, table size, or table contents requires
@@ -106,71 +110,31 @@ lck_grp_t ledger_lck_grp;
  * to extract a value from the table - i.e., 2 or 3 memory references.
  */
 struct ledger_template {
-       const char              *lt_name;
-       int                     lt_refs;
-       int                     lt_cnt;
-       int                     lt_table_size;
-       volatile uint32_t       lt_inuse;
-       lck_mtx_t               lt_lock;
-       zone_t                  lt_zone;
-       struct entry_template   *lt_entries;
+       const char              *lt_name;
+       int                     lt_refs;
+       int                     lt_cnt;
+       int                     lt_table_size;
+       volatile uint32_t       lt_inuse;
+       lck_mtx_t               lt_lock;
+       zone_t                  lt_zone;
+       bool                    lt_initialized;
+       struct entry_template   *lt_entries;
 };
 
-#define template_lock(template)                lck_mtx_lock(&(template)->lt_lock)
-#define template_unlock(template)      lck_mtx_unlock(&(template)->lt_lock)
+#define template_lock(template)         lck_mtx_lock(&(template)->lt_lock)
+#define template_unlock(template)       lck_mtx_unlock(&(template)->lt_lock)
 
-#define TEMPLATE_INUSE(s, t) {                                         \
-       s = splsched();                                         \
-       while (OSCompareAndSwap(0, 1, &((t)->lt_inuse)))        \
-               ;                                               \
+#define TEMPLATE_INUSE(s, t) {                                  \
+       s = splsched();                                         \
+       while (OSCompareAndSwap(0, 1, &((t)->lt_inuse)))        \
+               ;                                               \
 }
 
-#define TEMPLATE_IDLE(s, t) {                                  \
-       (t)->lt_inuse = 0;                                      \
-       splx(s);                                                \
+#define TEMPLATE_IDLE(s, t) {                                   \
+       (t)->lt_inuse = 0;                                      \
+       splx(s);                                                \
 }
 
-/*
- * Use NTOCKS "tocks" to track the rolling maximum balance of a ledger entry.
- */
-#define        NTOCKS 1
-/*
- * The explicit alignment is to ensure that atomic operations don't panic
- * on ARM.
- */
-struct ledger_entry {
-        volatile uint32_t               le_flags;
-        ledger_amount_t                 le_limit;
-        ledger_amount_t                 le_warn_level;
-        volatile ledger_amount_t        le_credit __attribute__((aligned(8)));
-        volatile ledger_amount_t        le_debit  __attribute__((aligned(8)));
-       union {
-               struct {
-                       /*
-                        * XXX - the following two fields can go away if we move all of
-                        * the refill logic into process policy
-                        */
-                       uint64_t        le_refill_period;
-                       uint64_t        le_last_refill;
-               } le_refill;
-               struct _le_maxtracking {
-                       struct _le_peak {
-                               uint32_t        le_max;  /* Lower 32-bits of observed max balance */
-                               uint32_t        le_time; /* time when this peak was observed */
-                       } le_peaks[NTOCKS];
-                       ledger_amount_t    le_lifetime_max; /* greatest peak ever observed */
-               } le_maxtracking;
-       } _le;
-} __attribute__((aligned(8)));
-
-struct ledger {
-       uint64_t                l_id;
-       int32_t                 l_refs;
-       int32_t                 l_size;
-       struct ledger_template  *l_template;
-       struct ledger_entry     l_entries[0] __attribute__((aligned(8)));
-};
-
 static int ledger_cnt = 0;
 /* ledger ast helper functions */
 static uint32_t ledger_check_needblock(ledger_t l, uint64_t now);
@@ -179,7 +143,7 @@ static uint32_t flag_set(volatile uint32_t *flags, uint32_t bit);
 static uint32_t flag_clear(volatile uint32_t *flags, uint32_t bit);
 
 static void ledger_entry_check_new_balance(thread_t thread, ledger_t ledger,
-                                           int entry, struct ledger_entry *le);
+    int entry, struct ledger_entry *le);
 
 #if 0
 static void
@@ -198,7 +162,7 @@ abstime_to_nsecs(uint64_t abstime)
        uint64_t nsecs;
 
        absolutetime_to_nanoseconds(abstime, &nsecs);
-       return (nsecs);
+       return nsecs;
 }
 
 static uint64_t
@@ -207,13 +171,13 @@ nsecs_to_abstime(uint64_t nsecs)
        uint64_t abstime;
 
        nanoseconds_to_absolutetime(nsecs, &abstime);
-       return (abstime);
+       return abstime;
 }
 
 void
 ledger_init(void)
 {
-        lck_grp_init(&ledger_lck_grp, "ledger", LCK_GRP_ATTR_NULL);
+       lck_grp_init(&ledger_lck_grp, "ledger", LCK_GRP_ATTR_NULL);
 }
 
 ledger_template_t
@@ -221,9 +185,10 @@ ledger_template_create(const char *name)
 {
        ledger_template_t template;
 
-       template = (ledger_template_t)kalloc(sizeof (*template));
-       if (template == NULL)
-               return (NULL);
+       template = (ledger_template_t)kalloc(sizeof(*template));
+       if (template == NULL) {
+               return NULL;
+       }
 
        template->lt_name = name;
        template->lt_refs = 1;
@@ -234,13 +199,48 @@ ledger_template_create(const char *name)
        lck_mtx_init(&template->lt_lock, &ledger_lck_grp, LCK_ATTR_NULL);
 
        template->lt_entries = (struct entry_template *)
-           kalloc(sizeof (struct entry_template) * template->lt_table_size);
+           kalloc(sizeof(struct entry_template) * template->lt_table_size);
        if (template->lt_entries == NULL) {
-               kfree(template, sizeof (*template));
+               kfree(template, sizeof(*template));
                template = NULL;
        }
 
-       return (template);
+       return template;
+}
+
+ledger_template_t
+ledger_template_copy(ledger_template_t template, const char *name)
+{
+       struct entry_template * new_entries = NULL;
+       ledger_template_t new_template = ledger_template_create(name);
+
+       if (new_template == NULL) {
+               return new_template;
+       }
+
+       template_lock(template);
+       assert(template->lt_initialized);
+
+       new_entries = (struct entry_template *)
+           kalloc(sizeof(struct entry_template) * template->lt_table_size);
+
+       if (new_entries) {
+               /* Copy the template entries. */
+               bcopy(template->lt_entries, new_entries, sizeof(struct entry_template) * template->lt_table_size);
+               kfree(new_template->lt_entries, sizeof(struct entry_template) * new_template->lt_table_size);
+
+               new_template->lt_entries = new_entries;
+               new_template->lt_table_size = template->lt_table_size;
+               new_template->lt_cnt = template->lt_cnt;
+       } else {
+               /* Tear down the new template; we've failed. :( */
+               ledger_template_dereference(new_template);
+               new_template = NULL;
+       }
+
+       template_unlock(template);
+
+       return new_template;
 }
 
 void
@@ -250,8 +250,11 @@ ledger_template_dereference(ledger_template_t template)
        template->lt_refs--;
        template_unlock(template);
 
-       if (template->lt_refs == 0)
-               kfree(template, sizeof (*template));
+       if (template->lt_refs == 0) {
+               kfree(template->lt_entries, sizeof(struct entry_template) * template->lt_table_size);
+               lck_mtx_destroy(&template->lt_lock, &ledger_lck_grp);
+               kfree(template, sizeof(*template));
+       }
 }
 
 /*
@@ -267,8 +270,9 @@ ledger_entry_add(ledger_template_t template, const char *key,
        int idx;
        struct entry_template *et;
 
-       if ((key == NULL) || (strlen(key) >= LEDGER_NAME_MAX) || (template->lt_zone != NULL))
-               return (-1);
+       if ((key == NULL) || (strlen(key) >= LEDGER_NAME_MAX) || (template->lt_zone != NULL)) {
+               return -1;
+       }
 
        template_lock(template);
 
@@ -314,7 +318,7 @@ ledger_entry_add(ledger_template_t template, const char *key,
        idx = template->lt_cnt++;
        template_unlock(template);
 
-       return (idx);
+       return idx;
 }
 
 
@@ -323,14 +327,15 @@ ledger_entry_setactive(ledger_t ledger, int entry)
 {
        struct ledger_entry *le;
 
-       if ((ledger == NULL)  || (entry < 0) || (entry >= ledger->l_size))
-               return (KERN_INVALID_ARGUMENT);
+       if ((ledger == NULL) || (entry < 0) || (entry >= ledger->l_size)) {
+               return KERN_INVALID_ARGUMENT;
+       }
 
        le = &ledger->l_entries[entry];
        if ((le->le_flags & LF_ENTRY_ACTIVE) == 0) {
                flag_set(&le->le_flags, LF_ENTRY_ACTIVE);
        }
-       return (KERN_SUCCESS);
+       return KERN_SUCCESS;
 }
 
 
@@ -340,16 +345,19 @@ ledger_key_lookup(ledger_template_t template, const char *key)
        int idx;
 
        template_lock(template);
-       for (idx = 0; idx < template->lt_cnt; idx++)
+       for (idx = 0; idx < template->lt_cnt; idx++) {
                if (template->lt_entries != NULL &&
-                   (strcmp(key, template->lt_entries[idx].et_key) == 0))
+                   (strcmp(key, template->lt_entries[idx].et_key) == 0)) {
                        break;
+               }
+       }
 
-       if (idx >= template->lt_cnt)
+       if (idx >= template->lt_cnt) {
                idx = -1;
+       }
        template_unlock(template);
 
-       return (idx);
+       return idx;
 }
 
 /*
@@ -364,8 +372,24 @@ ledger_template_complete(ledger_template_t template)
        size_t ledger_size;
        ledger_size = sizeof(struct ledger) + (template->lt_cnt * sizeof(struct ledger_entry));
        template->lt_zone = zinit(ledger_size, CONFIG_TASK_MAX * ledger_size,
-                              ledger_size,
-                              template->lt_name);
+           ledger_size,
+           template->lt_name);
+       template->lt_initialized = true;
+}
+
+/*
+ * Like ledger_template_complete, except we'll ask
+ * the pmap layer to manage allocations for us.
+ * Meant for ledgers that should be owned by the
+ * pmap layer.
+ */
+void
+ledger_template_complete_secure_alloc(ledger_template_t template)
+{
+       size_t ledger_size;
+       ledger_size = sizeof(struct ledger) + (template->lt_cnt * sizeof(struct ledger_entry));
+       pmap_ledger_alloc_init(ledger_size);
+       template->lt_initialized = true;
 }
 
 /*
@@ -385,10 +409,14 @@ ledger_instantiate(ledger_template_t template, int entry_type)
        template_lock(template);
        template->lt_refs++;
        cnt = template->lt_cnt;
-       assert(template->lt_zone);
        template_unlock(template);
 
-       ledger = (ledger_t)zalloc(template->lt_zone);
+       if (template->lt_zone) {
+               ledger = (ledger_t)zalloc(template->lt_zone);
+       } else {
+               ledger = pmap_ledger_alloc();
+       }
+
        if (ledger == NULL) {
                ledger_template_dereference(template);
                return LEDGER_NULL;
@@ -396,7 +424,7 @@ ledger_instantiate(ledger_template_t template, int entry_type)
 
        ledger->l_template = template;
        ledger->l_id = ledger_cnt++;
-       ledger->l_refs = 1;
+       os_ref_init(&ledger->l_refs, &ledger_refgrp);
        ledger->l_size = (int32_t)cnt;
 
        template_lock(template);
@@ -407,80 +435,71 @@ ledger_instantiate(ledger_template_t template, int entry_type)
 
                le->le_flags = et->et_flags;
                /* make entry inactive by removing  active bit */
-               if (entry_type == LEDGER_CREATE_INACTIVE_ENTRIES)
+               if (entry_type == LEDGER_CREATE_INACTIVE_ENTRIES) {
                        flag_clear(&le->le_flags, LF_ENTRY_ACTIVE);
+               }
                /*
                 * If template has a callback, this entry is opted-in,
                 * by default.
                 */
-               if (et->et_callback != NULL)
+               if (et->et_callback != NULL) {
                        flag_set(&le->le_flags, LEDGER_ACTION_CALLBACK);
+               }
                le->le_credit        = 0;
                le->le_debit         = 0;
                le->le_limit         = LEDGER_LIMIT_INFINITY;
-               le->le_warn_level    = LEDGER_LIMIT_INFINITY;           
+               le->le_warn_percent  = LEDGER_PERCENT_NONE;
                le->_le.le_refill.le_refill_period = 0;
                le->_le.le_refill.le_last_refill   = 0;
        }
        template_unlock(template);
 
-       return (ledger);
+       return ledger;
 }
 
 static uint32_t
 flag_set(volatile uint32_t *flags, uint32_t bit)
 {
-       return (OSBitOrAtomic(bit, flags));
+       return OSBitOrAtomic(bit, flags);
 }
 
 static uint32_t
 flag_clear(volatile uint32_t *flags, uint32_t bit)
 {
-       return (OSBitAndAtomic(~bit, flags));
+       return OSBitAndAtomic(~bit, flags);
 }
 
 /*
  * Take a reference on a ledger
  */
-kern_return_t
+void
 ledger_reference(ledger_t ledger)
 {
-       if (!LEDGER_VALID(ledger))
-               return (KERN_INVALID_ARGUMENT);
-       OSIncrementAtomic(&ledger->l_refs);
-       return (KERN_SUCCESS);
-}
-
-int
-ledger_reference_count(ledger_t ledger)
-{
-       if (!LEDGER_VALID(ledger))
-               return (-1);
+       if (!LEDGER_VALID(ledger)) {
+               return;
+       }
 
-       return (ledger->l_refs);
+       os_ref_retain(&ledger->l_refs);
 }
 
 /*
  * Remove a reference on a ledger.  If this is the last reference,
  * deallocate the unused ledger.
  */
-kern_return_t
+void
 ledger_dereference(ledger_t ledger)
 {
-       int v;
-
-       if (!LEDGER_VALID(ledger))
-               return (KERN_INVALID_ARGUMENT);
-
-       v = OSDecrementAtomic(&ledger->l_refs);
-       ASSERT(v >= 1);
-
-       /* Just released the last reference.  Free it. */
-       if (v == 1) {
-               zfree(ledger->l_template->lt_zone, ledger);
+       if (!LEDGER_VALID(ledger)) {
+               return;
        }
 
-       return (KERN_SUCCESS);
+       if (os_ref_release(&ledger->l_refs) == 0) {
+               if (ledger->l_template->lt_zone) {
+                       zfree(ledger->l_template->lt_zone, ledger);
+               } else {
+                       pmap_ledger_free(ledger);
+               }
+       }
 }
 
 /*
@@ -502,9 +521,11 @@ warn_level_exceeded(struct ledger_entry *le)
         * use positive limits.
         */
        balance = le->le_credit - le->le_debit;
-       if ((le->le_warn_level != LEDGER_LIMIT_INFINITY) && (balance > le->le_warn_level))
-               return (1);
-       return (0);
+       if (le->le_warn_percent != LEDGER_PERCENT_NONE &&
+           ((balance > (le->le_limit * le->le_warn_percent) >> 16))) {
+               return 1;
+       }
+       return 0;
 }
 
 /*
@@ -522,12 +543,14 @@ limit_exceeded(struct ledger_entry *le)
        }
 
        balance = le->le_credit - le->le_debit;
-       if ((le->le_limit <= 0) && (balance < le->le_limit))
-               return (1);
+       if ((le->le_limit <= 0) && (balance < le->le_limit)) {
+               return 1;
+       }
 
-       if ((le->le_limit > 0) && (balance > le->le_limit))
-               return (1);
-       return (0);
+       if ((le->le_limit > 0) && (balance > le->le_limit)) {
+               return 1;
+       }
+       return 0;
 }
 
 static inline struct ledger_callback *
@@ -540,7 +563,7 @@ entry_get_callback(ledger_t ledger, int entry)
        callback = ledger->l_template->lt_entries[entry].et_callback;
        TEMPLATE_IDLE(s, ledger->l_template);
 
-       return (callback);
+       return callback;
 }
 
 /*
@@ -625,16 +648,18 @@ ledger_refill(uint64_t now, ledger_t ledger, int entry)
         * OK, it's been a long time.  Do a divide to figure out
         * how long.
         */
-       if (elapsed > 0)
+       if (elapsed > 0) {
                periods = (now - le->_le.le_refill.le_last_refill) / period;
+       }
 
        balance = le->le_credit - le->le_debit;
        due = periods * le->le_limit;
 
-       if (balance - due < 0)
+       if (balance - due < 0) {
                due = balance;
+       }
 
-       assertf(due >= 0,"now=%llu, ledger=%p, entry=%d, balance=%lld, due=%lld", now, ledger, entry, balance, due);
+       assertf(due >= 0, "now=%llu, ledger=%p, entry=%d, balance=%lld, due=%lld", now, ledger, entry, balance, due);
 
        OSAddAtomic64(due, &le->le_debit);
 
@@ -645,86 +670,36 @@ ledger_refill(uint64_t now, ledger_t ledger, int entry)
         * Otherwise set it to the time at which it last should have been
         * fully refilled.
         */
-       if (balance == due)
+       if (balance == due) {
                le->_le.le_refill.le_last_refill = now;
-       else
+       } else {
                le->_le.le_refill.le_last_refill += (le->_le.le_refill.le_refill_period * periods);
+       }
 
        flag_clear(&le->le_flags, LF_REFILL_INPROGRESS);
 
        lprintf(("Refill %lld %lld->%lld\n", periods, balance, balance - due));
-       if (!limit_exceeded(le))
+       if (!limit_exceeded(le)) {
                ledger_limit_entry_wakeup(le);
+       }
 }
 
-/*
- * In tenths of a second, the length of one lookback period (a "tock") for
- * ledger rolling maximum calculations. The effective lookback window will be this times
- * NTOCKS.
- *
- * Use a tock length of 2.5 seconds to get a total lookback period of 5 seconds.
- *
- * XXX Could make this caller-definable, at the point that rolling max tracking
- * is enabled for the entry.
- */
-#define        TOCKLEN 25
-
-/*
- * How many sched_tick's are there in one tock (one of our lookback periods)?
- *
- *  X sched_ticks        2.5 sec      N sched_ticks
- * ---------------   =  ----------  * -------------
- *      tock               tock            sec
- *
- * where N sched_ticks/sec is calculated via 1 << SCHED_TICK_SHIFT (see sched_prim.h)
- *
- * This should give us 20 sched_tick's in one 2.5 second-long tock.
- */
-#define SCHED_TICKS_PER_TOCK ((TOCKLEN * (1 << SCHED_TICK_SHIFT)) / 10)
-
-/*
- * Rolling max timestamps use their own unit (let's call this a "tock"). One tock is the
- * length of one lookback period that we use for our rolling max calculation.
- *
- * Calculate the current time in tocks from sched_tick (which runs at a some
- * fixed rate).
- */
-#define        CURRENT_TOCKSTAMP() (sched_tick / SCHED_TICKS_PER_TOCK)
-
-/*
- * Does the given tockstamp fall in either the current or the previous tocks?
- */
-#define TOCKSTAMP_IS_STALE(now, tock) ((((now) - (tock)) < NTOCKS) ? FALSE : TRUE)
-
 void
 ledger_entry_check_new_balance(thread_t thread, ledger_t ledger,
-                               int entry, struct ledger_entry *le)
+    int entry, struct ledger_entry *le)
 {
-       ledger_amount_t credit, debit;
-
        if (le->le_flags & LF_TRACKING_MAX) {
                ledger_amount_t balance = le->le_credit - le->le_debit;
-               uint32_t now = CURRENT_TOCKSTAMP();
-               struct _le_peak *p = &le->_le.le_maxtracking.le_peaks[now % NTOCKS];
 
-               if (!TOCKSTAMP_IS_STALE(now, p->le_time) || (balance > p->le_max)) {
-                       /*
-                        * The current balance is greater than the previously
-                        * observed peak for the current time block, *or* we
-                        * haven't yet recorded a peak for the current time block --
-                        * so this is our new peak.
-                        *
-                        * (We only track the lower 32-bits of a balance for rolling
-                        * max purposes.)
-                        */
-                       p->le_max = (uint32_t)balance;
-                       p->le_time = now;
+               if (balance > le->_le._le_max.le_lifetime_max) {
+                       le->_le._le_max.le_lifetime_max = balance;
                }
 
-               struct _le_maxtracking *m = &le->_le.le_maxtracking;
-               if(balance > m->le_lifetime_max){
-                       m->le_lifetime_max = balance;
+#if CONFIG_LEDGER_INTERVAL_MAX
+               if (balance > le->_le._le_max.le_interval_max) {
+                       le->_le._le_max.le_interval_max = balance;
                }
+#endif /* LEDGER_CONFIG_INTERVAL_MAX */
        }
 
        /* Check to see whether we're due a refill */
@@ -732,8 +707,9 @@ ledger_entry_check_new_balance(thread_t thread, ledger_t ledger,
                assert(!(le->le_flags & LF_TRACKING_MAX));
 
                uint64_t now = mach_absolute_time();
-               if ((now - le->_le.le_refill.le_last_refill) > le->_le.le_refill.le_refill_period)
+               if ((now - le->_le.le_refill.le_last_refill) > le->_le.le_refill.le_refill_period) {
                        ledger_refill(now, ledger, entry);
+               }
        }
 
        if (limit_exceeded(le)) {
@@ -759,8 +735,9 @@ ledger_entry_check_new_balance(thread_t thread, ledger_t ledger,
                 * If there are any threads blocked on this entry, now would
                 * be a good time to wake them up.
                 */
-               if (le->le_flags & LF_WAKE_NEEDED)
+               if (le->le_flags & LF_WAKE_NEEDED) {
                        ledger_limit_entry_wakeup(le);
+               }
 
                if (le->le_flags & LEDGER_ACTION_CALLBACK) {
                        /*
@@ -768,24 +745,24 @@ ledger_entry_check_new_balance(thread_t thread, ledger_t ledger,
                         * the ledger's balance crosses into or out of the warning
                         * level.
                         */
-                       if (warn_level_exceeded(le)) {
-                               /*
-                                * This ledger's balance is above the warning level.
-                                */ 
-                               if ((le->le_flags & LF_WARNED) == 0) {
-                                       /*
-                                        * If we are above the warning level and
-                                        * have not yet invoked the callback,
-                                        * set the AST so it can be done before returning
-                                        * to userland.
-                                        */
+                       if (warn_level_exceeded(le)) {
+                               /*
+                                * This ledger's balance is above the warning level.
+                                */
+                               if ((le->le_flags & LF_WARNED) == 0) {
+                                       /*
+                                        * If we are above the warning level and
+                                        * have not yet invoked the callback,
+                                        * set the AST so it can be done before returning
+                                        * to userland.
+                                        */
                                        act_set_astledger_async(thread);
                                }
                        } else {
                                /*
                                 * This ledger's balance is below the warning level.
                                 */
-                               if (le->le_flags & LF_WARNED) {
+                               if (le->le_flags & LF_WARNED) {
                                        /*
                                         * If we are below the warning level and
                                         * the LF_WARNED flag is still set, we need
@@ -799,16 +776,13 @@ ledger_entry_check_new_balance(thread_t thread, ledger_t ledger,
                }
        }
 
-       credit = le->le_credit;
-       debit = le->le_debit;
        if ((le->le_flags & LF_PANIC_ON_NEGATIVE) &&
-           ((credit < debit) ||
-            (le->le_credit < le->le_debit))) {
-               panic("ledger_entry_check_new_balance(%p,%d): negative ledger %p credit:%lld/%lld debit:%lld/%lld balance:%lld/%lld\n",
-                     ledger, entry, le,
-                     credit, le->le_credit,
-                     debit, le->le_debit,
-                     credit - debit, le->le_credit - le->le_debit);
+           (le->le_credit < le->le_debit)) {
+               panic("ledger_entry_check_new_balance(%p,%d): negative ledger %p credit:%lld debit:%lld balance:%lld\n",
+                   ledger, entry, le,
+                   le->le_credit,
+                   le->le_debit,
+                   le->le_credit - le->le_debit);
        }
 }
 
@@ -830,11 +804,13 @@ ledger_credit_thread(thread_t thread, ledger_t ledger, int entry, ledger_amount_
        ledger_amount_t old, new;
        struct ledger_entry *le;
 
-       if (!ENTRY_VALID(ledger, entry) || (amount < 0))
-               return (KERN_INVALID_VALUE);
+       if (!ENTRY_VALID(ledger, entry) || (amount < 0)) {
+               return KERN_INVALID_VALUE;
+       }
 
-       if (amount == 0)
-               return (KERN_SUCCESS);
+       if (amount == 0) {
+               return KERN_SUCCESS;
+       }
 
        le = &ledger->l_entries[entry];
 
@@ -842,9 +818,11 @@ ledger_credit_thread(thread_t thread, ledger_t ledger, int entry, ledger_amount_
        new = old + amount;
        lprintf(("%p Credit %lld->%lld\n", thread, old, new));
 
-       ledger_entry_check_new_balance(thread, ledger, entry, le);
+       if (thread) {
+               ledger_entry_check_new_balance(thread, ledger, entry, le);
+       }
 
-       return (KERN_SUCCESS);
+       return KERN_SUCCESS;
 }
 
 /*
@@ -856,6 +834,15 @@ ledger_credit(ledger_t ledger, int entry, ledger_amount_t amount)
        return ledger_credit_thread(current_thread(), ledger, entry, amount);
 }
 
+/*
+ * Add value to an entry in a ledger; do not check balance after update.
+ */
+kern_return_t
+ledger_credit_nocheck(ledger_t ledger, int entry, ledger_amount_t amount)
+{
+       return ledger_credit_thread(NULL, ledger, entry, amount);
+}
+
 /* Add all of one ledger's values into another.
  * They must have been created from the same template.
  * This is not done atomically. Another thread (if not otherwise synchronized)
@@ -869,13 +856,13 @@ ledger_rollup(ledger_t to_ledger, ledger_t from_ledger)
 {
        int i;
 
-       assert(to_ledger->l_template == from_ledger->l_template);
+       assert(to_ledger->l_template->lt_cnt == from_ledger->l_template->lt_cnt);
 
        for (i = 0; i < to_ledger->l_size; i++) {
                ledger_rollup_entry(to_ledger, from_ledger, i);
        }
 
-       return (KERN_SUCCESS);
+       return KERN_SUCCESS;
 }
 
 /* Add one ledger entry value to another.
@@ -888,20 +875,20 @@ ledger_rollup_entry(ledger_t to_ledger, ledger_t from_ledger, int entry)
 {
        struct ledger_entry *from_le, *to_le;
 
-       assert(to_ledger->l_template == from_ledger->l_template);
+       assert(to_ledger->l_template->lt_cnt == from_ledger->l_template->lt_cnt);
        if (ENTRY_VALID(from_ledger, entry) && ENTRY_VALID(to_ledger, entry)) {
                from_le = &from_ledger->l_entries[entry];
                to_le   =   &to_ledger->l_entries[entry];
                OSAddAtomic64(from_le->le_credit, &to_le->le_credit);
-               OSAddAtomic64(from_le->le_debit,  &to_le->le_debit);
+               OSAddAtomic64(from_le->le_debit, &to_le->le_debit);
        }
 
-       return (KERN_SUCCESS);
+       return KERN_SUCCESS;
 }
 
 /*
  * Zero the balance of a ledger by adding to its credit or debit, whichever is smaller.
- * Note that some clients of ledgers (notably, task wakeup statistics) require that 
+ * Note that some clients of ledgers (notably, task wakeup statistics) require that
  * le_credit only ever increase as a function of ledger_credit().
  */
 kern_return_t
@@ -910,8 +897,9 @@ ledger_zero_balance(ledger_t ledger, int entry)
        struct ledger_entry *le;
        ledger_amount_t debit, credit;
 
-       if (!ENTRY_VALID(ledger, entry))
-               return (KERN_INVALID_VALUE);
+       if (!ENTRY_VALID(ledger, entry)) {
+               return KERN_INVALID_VALUE;
+       }
 
        le = &ledger->l_entries[entry];
 
@@ -926,16 +914,18 @@ top:
                }
                lprintf(("%p zeroed %lld->%lld\n", current_thread(), le->le_credit, 0));
        } else if (credit > debit) {
-               if (!OSCompareAndSwap64(debit, credit, &le->le_debit))
+               if (!OSCompareAndSwap64(debit, credit, &le->le_debit)) {
                        goto top;
+               }
                lprintf(("%p zeroed %lld->%lld\n", current_thread(), le->le_debit, le->le_credit));
        } else if (credit < debit) {
-               if (!OSCompareAndSwap64(credit, debit, &le->le_credit))
+               if (!OSCompareAndSwap64(credit, debit, &le->le_credit)) {
                        goto top;
+               }
                lprintf(("%p zeroed %lld->%lld\n", current_thread(), le->le_credit, le->le_debit));
        }
 
-       return (KERN_SUCCESS);
+       return KERN_SUCCESS;
 }
 
 kern_return_t
@@ -943,15 +933,16 @@ ledger_get_limit(ledger_t ledger, int entry, ledger_amount_t *limit)
 {
        struct ledger_entry *le;
 
-       if (!ENTRY_VALID(ledger, entry))
-               return (KERN_INVALID_VALUE);
+       if (!ENTRY_VALID(ledger, entry)) {
+               return KERN_INVALID_VALUE;
+       }
 
        le = &ledger->l_entries[entry];
        *limit = le->le_limit;
 
        lprintf(("ledger_get_limit: %lld\n", *limit));
 
-       return (KERN_SUCCESS);
+       return KERN_SUCCESS;
 }
 
 /*
@@ -959,17 +950,18 @@ ledger_get_limit(ledger_t ledger, int entry, ledger_amount_t *limit)
  * current balance, so the change doesn't affect the thread until the
  * next refill.
  *
- * warn_level: If non-zero, causes the callback to be invoked when 
+ * warn_level: If non-zero, causes the callback to be invoked when
  * the balance exceeds this level. Specified as a percentage [of the limit].
  */
 kern_return_t
 ledger_set_limit(ledger_t ledger, int entry, ledger_amount_t limit,
-                uint8_t warn_level_percentage)
+    uint8_t warn_level_percentage)
 {
        struct ledger_entry *le;
 
-       if (!ENTRY_VALID(ledger, entry))
-               return (KERN_INVALID_VALUE);
+       if (!ENTRY_VALID(ledger, entry)) {
+               return KERN_INVALID_VALUE;
+       }
 
        lprintf(("ledger_set_limit: %lld\n", limit));
        le = &ledger->l_entries[entry];
@@ -989,72 +981,60 @@ ledger_set_limit(ledger_t ledger, int entry, ledger_amount_t limit,
                le->_le.le_refill.le_last_refill = 0;
        }
        flag_clear(&le->le_flags, LF_CALLED_BACK);
-       flag_clear(&le->le_flags, LF_WARNED);        
+       flag_clear(&le->le_flags, LF_WARNED);
        ledger_limit_entry_wakeup(le);
 
        if (warn_level_percentage != 0) {
                assert(warn_level_percentage <= 100);
                assert(limit > 0); /* no negative limit support for warnings */
                assert(limit != LEDGER_LIMIT_INFINITY); /* warn % without limit makes no sense */
-               le->le_warn_level = (le->le_limit * warn_level_percentage) / 100;
+               le->le_warn_percent = warn_level_percentage * (1u << 16) / 100;
        } else {
-               le->le_warn_level = LEDGER_LIMIT_INFINITY;
+               le->le_warn_percent = LEDGER_PERCENT_NONE;
        }
 
-       return (KERN_SUCCESS);
+       return KERN_SUCCESS;
 }
 
+#if CONFIG_LEDGER_INTERVAL_MAX
 kern_return_t
-ledger_get_recent_max(ledger_t ledger, int entry,
-       ledger_amount_t *max_observed_balance)
+ledger_get_interval_max(ledger_t ledger, int entry,
+    ledger_amount_t *max_interval_balance, int reset)
 {
-       struct ledger_entry     *le;
-       uint32_t                now = CURRENT_TOCKSTAMP();
-       int                     i;
-
+       struct ledger_entry *le;
        le = &ledger->l_entries[entry];
 
        if (!ENTRY_VALID(ledger, entry) || !(le->le_flags & LF_TRACKING_MAX)) {
-               return (KERN_INVALID_VALUE);
+               return KERN_INVALID_VALUE;
        }
 
-       /*
-        * Start with the current balance; if neither of the recorded peaks are
-        * within recent history, we use this.
-        */
-       *max_observed_balance = le->le_credit - le->le_debit;
-
-       for (i = 0; i < NTOCKS; i++) {
-               if (!TOCKSTAMP_IS_STALE(now, le->_le.le_maxtracking.le_peaks[i].le_time) &&
-                   (le->_le.le_maxtracking.le_peaks[i].le_max > *max_observed_balance)) {
-                       /*
-                        * The peak for this time block isn't stale, and it
-                        * is greater than the current balance -- so use it.
-                        */
-                   *max_observed_balance = le->_le.le_maxtracking.le_peaks[i].le_max;
-               }
-       }
+       *max_interval_balance = le->_le._le_max.le_interval_max;
+       lprintf(("ledger_get_interval_max: %lld%s\n", *max_interval_balance,
+           (reset) ? " --> 0" : ""));
 
-       lprintf(("ledger_get_maximum: %lld\n", *max_observed_balance));
+       if (reset) {
+               le->_le._le_max.le_interval_max = 0;
+       }
 
-       return (KERN_SUCCESS);
+       return KERN_SUCCESS;
 }
+#endif /* CONFIG_LEDGER_INTERVAL_MAX */
 
 kern_return_t
 ledger_get_lifetime_max(ledger_t ledger, int entry,
-        ledger_amount_t *max_lifetime_balance)
+    ledger_amount_t *max_lifetime_balance)
 {
        struct ledger_entry *le;
        le = &ledger->l_entries[entry];
 
        if (!ENTRY_VALID(ledger, entry) || !(le->le_flags & LF_TRACKING_MAX)) {
-               return (KERN_INVALID_VALUE);
+               return KERN_INVALID_VALUE;
        }
 
-       *max_lifetime_balance = le->_le.le_maxtracking.le_lifetime_max;
+       *max_lifetime_balance = le->_le._le_max.le_lifetime_max;
        lprintf(("ledger_get_lifetime_max: %lld\n", *max_lifetime_balance));
 
-       return (KERN_SUCCESS);
+       return KERN_SUCCESS;
 }
 
 /*
@@ -1062,24 +1042,24 @@ ledger_get_lifetime_max(ledger_t ledger, int entry,
  */
 kern_return_t
 ledger_track_maximum(ledger_template_t template, int entry,
-       __unused int period_in_secs)
+    __unused int period_in_secs)
 {
        template_lock(template);
 
        if ((entry < 0) || (entry >= template->lt_cnt)) {
-               template_unlock(template);      
-               return (KERN_INVALID_VALUE);
+               template_unlock(template);
+               return KERN_INVALID_VALUE;
        }
 
        /* Refill is incompatible with max tracking. */
        if (template->lt_entries[entry].et_flags & LF_REFILL_SCHEDULED) {
-               return (KERN_INVALID_VALUE);
+               return KERN_INVALID_VALUE;
        }
 
        template->lt_entries[entry].et_flags |= LF_TRACKING_MAX;
        template_unlock(template);
 
-       return (KERN_SUCCESS);
+       return KERN_SUCCESS;
 }
 
 kern_return_t
@@ -1089,14 +1069,14 @@ ledger_panic_on_negative(ledger_template_t template, int entry)
 
        if ((entry < 0) || (entry >= template->lt_cnt)) {
                template_unlock(template);
-               return (KERN_INVALID_VALUE);
+               return KERN_INVALID_VALUE;
        }
 
        template->lt_entries[entry].et_flags |= LF_PANIC_ON_NEGATIVE;
 
        template_unlock(template);
 
-       return (KERN_SUCCESS);
+       return KERN_SUCCESS;
 }
 
 kern_return_t
@@ -1106,14 +1086,14 @@ ledger_track_credit_only(ledger_template_t template, int entry)
 
        if ((entry < 0) || (entry >= template->lt_cnt)) {
                template_unlock(template);
-               return (KERN_INVALID_VALUE);
+               return KERN_INVALID_VALUE;
        }
 
        template->lt_entries[entry].et_flags |= LF_TRACK_CREDIT_ONLY;
 
        template_unlock(template);
 
-       return (KERN_SUCCESS);
+       return KERN_SUCCESS;
 }
 
 /*
@@ -1121,16 +1101,17 @@ ledger_track_credit_only(ledger_template_t template, int entry)
  */
 kern_return_t
 ledger_set_callback(ledger_template_t template, int entry,
-   ledger_callback_t func, const void *param0, const void *param1)
+    ledger_callback_t func, const void *param0, const void *param1)
 {
        struct entry_template *et;
        struct ledger_callback *old_cb, *new_cb;
 
-       if ((entry < 0) || (entry >= template->lt_cnt))
-               return (KERN_INVALID_VALUE);
+       if ((entry < 0) || (entry >= template->lt_cnt)) {
+               return KERN_INVALID_VALUE;
+       }
 
        if (func) {
-               new_cb = (struct ledger_callback *)kalloc(sizeof (*new_cb));
+               new_cb = (struct ledger_callback *)kalloc(sizeof(*new_cb));
                new_cb->lc_func = func;
                new_cb->lc_param0 = param0;
                new_cb->lc_param1 = param1;
@@ -1143,10 +1124,11 @@ ledger_set_callback(ledger_template_t template, int entry,
        old_cb = et->et_callback;
        et->et_callback = new_cb;
        template_unlock(template);
-       if (old_cb)
-               kfree(old_cb, sizeof (*old_cb));
+       if (old_cb) {
+               kfree(old_cb, sizeof(*old_cb));
+       }
 
-       return (KERN_SUCCESS);
+       return KERN_SUCCESS;
 }
 
 /*
@@ -1159,18 +1141,19 @@ ledger_set_callback(ledger_template_t template, int entry,
 kern_return_t
 ledger_disable_callback(ledger_t ledger, int entry)
 {
-       if (!ENTRY_VALID(ledger, entry))
-               return (KERN_INVALID_VALUE);
+       if (!ENTRY_VALID(ledger, entry)) {
+               return KERN_INVALID_VALUE;
+       }
 
        /*
-        * le_warn_level is used to indicate *if* this ledger has a warning configured,
+        * le_warn_percent is used to indicate *if* this ledger has a warning configured,
         * in addition to what that warning level is set to.
         * This means a side-effect of ledger_disable_callback() is that the
         * warning level is forgotten.
         */
-       ledger->l_entries[entry].le_warn_level = LEDGER_LIMIT_INFINITY;
+       ledger->l_entries[entry].le_warn_percent = LEDGER_PERCENT_NONE;
        flag_clear(&ledger->l_entries[entry].le_flags, LEDGER_ACTION_CALLBACK);
-       return (KERN_SUCCESS);
+       return KERN_SUCCESS;
 }
 
 /*
@@ -1183,13 +1166,14 @@ ledger_disable_callback(ledger_t ledger, int entry)
 kern_return_t
 ledger_enable_callback(ledger_t ledger, int entry)
 {
-       if (!ENTRY_VALID(ledger, entry))
-               return (KERN_INVALID_VALUE);
+       if (!ENTRY_VALID(ledger, entry)) {
+               return KERN_INVALID_VALUE;
+       }
 
        assert(entry_get_callback(ledger, entry) != NULL);
 
        flag_set(&ledger->l_entries[entry].le_flags, LEDGER_ACTION_CALLBACK);
-       return (KERN_SUCCESS);
+       return KERN_SUCCESS;
 }
 
 /*
@@ -1202,13 +1186,14 @@ ledger_get_period(ledger_t ledger, int entry, uint64_t *period)
 {
        struct ledger_entry *le;
 
-       if (!ENTRY_VALID(ledger, entry))
-               return (KERN_INVALID_VALUE);
+       if (!ENTRY_VALID(ledger, entry)) {
+               return KERN_INVALID_VALUE;
+       }
 
        le = &ledger->l_entries[entry];
        *period = abstime_to_nsecs(le->_le.le_refill.le_refill_period);
        lprintf(("ledger_get_period: %llx\n", *period));
-       return (KERN_SUCCESS);
+       return KERN_SUCCESS;
 }
 
 /*
@@ -1220,8 +1205,9 @@ ledger_set_period(ledger_t ledger, int entry, uint64_t period)
        struct ledger_entry *le;
 
        lprintf(("ledger_set_period: %llx\n", period));
-       if (!ENTRY_VALID(ledger, entry))
-               return (KERN_INVALID_VALUE);
+       if (!ENTRY_VALID(ledger, entry)) {
+               return KERN_INVALID_VALUE;
+       }
 
        le = &ledger->l_entries[entry];
 
@@ -1235,7 +1221,7 @@ ledger_set_period(ledger_t ledger, int entry, uint64_t period)
                /*
                 * Refill is incompatible with rolling max tracking.
                 */
-               return (KERN_INVALID_VALUE);
+               return KERN_INVALID_VALUE;
        }
 
        le->_le.le_refill.le_refill_period = nsecs_to_abstime(period);
@@ -1251,7 +1237,7 @@ ledger_set_period(ledger_t ledger, int entry, uint64_t period)
 
        flag_set(&le->le_flags, LF_REFILL_SCHEDULED);
 
-       return (KERN_SUCCESS);
+       return KERN_SUCCESS;
 }
 
 /*
@@ -1262,36 +1248,39 @@ ledger_disable_refill(ledger_t ledger, int entry)
 {
        struct ledger_entry *le;
 
-       if (!ENTRY_VALID(ledger, entry))
-               return (KERN_INVALID_VALUE);
+       if (!ENTRY_VALID(ledger, entry)) {
+               return KERN_INVALID_VALUE;
+       }
 
        le = &ledger->l_entries[entry];
 
        flag_clear(&le->le_flags, LF_REFILL_SCHEDULED);
 
-       return (KERN_SUCCESS);
+       return KERN_SUCCESS;
 }
 
 kern_return_t
 ledger_get_actions(ledger_t ledger, int entry, int *actions)
 {
-       if (!ENTRY_VALID(ledger, entry))
-               return (KERN_INVALID_VALUE);
+       if (!ENTRY_VALID(ledger, entry)) {
+               return KERN_INVALID_VALUE;
+       }
 
        *actions = ledger->l_entries[entry].le_flags & LEDGER_ACTION_MASK;
-       lprintf(("ledger_get_actions: %#x\n", *actions));       
-       return (KERN_SUCCESS);
+       lprintf(("ledger_get_actions: %#x\n", *actions));
+       return KERN_SUCCESS;
 }
 
 kern_return_t
 ledger_set_action(ledger_t ledger, int entry, int action)
 {
        lprintf(("ledger_set_action: %#x\n", action));
-       if (!ENTRY_VALID(ledger, entry))
-               return (KERN_INVALID_VALUE);
+       if (!ENTRY_VALID(ledger, entry)) {
+               return KERN_INVALID_VALUE;
+       }
 
        flag_set(&ledger->l_entries[entry].le_flags, action);
-       return (KERN_SUCCESS);
+       return KERN_SUCCESS;
 }
 
 kern_return_t
@@ -1300,11 +1289,13 @@ ledger_debit_thread(thread_t thread, ledger_t ledger, int entry, ledger_amount_t
        struct ledger_entry *le;
        ledger_amount_t old, new;
 
-       if (!ENTRY_VALID(ledger, entry) || (amount < 0))
-               return (KERN_INVALID_ARGUMENT);
+       if (!ENTRY_VALID(ledger, entry) || (amount < 0)) {
+               return KERN_INVALID_ARGUMENT;
+       }
 
-       if (amount == 0)
-               return (KERN_SUCCESS);
+       if (amount == 0) {
+               return KERN_SUCCESS;
+       }
 
        le = &ledger->l_entries[entry];
 
@@ -1318,9 +1309,11 @@ ledger_debit_thread(thread_t thread, ledger_t ledger, int entry, ledger_amount_t
        }
        lprintf(("%p Debit %lld->%lld\n", thread, old, new));
 
-       ledger_entry_check_new_balance(thread, ledger, entry, le);
+       if (thread) {
+               ledger_entry_check_new_balance(thread, ledger, entry, le);
+       }
 
-       return (KERN_SUCCESS);
+       return KERN_SUCCESS;
 }
 
 kern_return_t
@@ -1329,16 +1322,23 @@ ledger_debit(ledger_t ledger, int entry, ledger_amount_t amount)
        return ledger_debit_thread(current_thread(), ledger, entry, amount);
 }
 
+kern_return_t
+ledger_debit_nocheck(ledger_t ledger, int entry, ledger_amount_t amount)
+{
+       return ledger_debit_thread(NULL, ledger, entry, amount);
+}
+
 void
 ledger_ast(thread_t thread)
 {
-       struct ledger   *l = thread->t_ledger;
-       struct ledger   *thl;
-       uint32_t        block;
-       uint64_t        now;
-       uint8_t         task_flags;
-       uint8_t         task_percentage;
-       uint64_t        task_interval;
+       struct ledger   *l = thread->t_ledger;
+       struct ledger   *thl;
+       struct ledger   *coalition_ledger;
+       uint32_t        block;
+       uint64_t        now;
+       uint8_t         task_flags;
+       uint8_t         task_percentage;
+       uint64_t        task_interval;
 
        kern_return_t ret;
        task_t task = thread->task;
@@ -1365,9 +1365,9 @@ top:
         */
        if (((task_flags & TASK_RUSECPU_FLAGS_PERTHR_LIMIT) != 0) &&
            ((thread->options & TH_OPT_PRVT_CPULIMIT) == 0)) {
-               uint8_t  percentage;
+               uint8_t  percentage;
                uint64_t interval;
-               int      action;
+               int      action;
 
                thread_get_cpulimit(&action, &percentage, &interval);
 
@@ -1381,7 +1381,7 @@ top:
                        assert((thread->options & TH_OPT_PROC_CPULIMIT) != 0);
                }
        } else if (((task_flags & TASK_RUSECPU_FLAGS_PERTHR_LIMIT) == 0) &&
-                  (thread->options & TH_OPT_PROC_CPULIMIT)) {
+           (thread->options & TH_OPT_PROC_CPULIMIT)) {
                assert((thread->options & TH_OPT_PRVT_CPULIMIT) == 0);
 
                /*
@@ -1395,9 +1395,10 @@ top:
        /*
         * If the task or thread is being terminated, let's just get on with it
         */
-       if ((l == NULL) || !task->active || task->halting || !thread->active)
+       if ((l == NULL) || !task->active || task->halting || !thread->active) {
                return;
-       
+       }
+
        /*
         * Examine all entries in deficit to see which might be eligble for
         * an automatic refill, which require callbacks to be issued, and
@@ -1416,6 +1417,11 @@ top:
        }
        block |= ledger_check_needblock(l, now);
 
+       coalition_ledger = coalition_ledger_get_from_task(task);
+       if (LEDGER_VALID(coalition_ledger)) {
+               block |= ledger_check_needblock(coalition_ledger, now);
+       }
+       ledger_dereference(coalition_ledger);
        /*
         * If we are supposed to block on the availability of one or more
         * resources, find the first entry in deficit for which we should wait.
@@ -1425,12 +1431,14 @@ top:
        if (block) {
                if (LEDGER_VALID(thl)) {
                        ret = ledger_perform_blocking(thl);
-                       if (ret != KERN_SUCCESS)
+                       if (ret != KERN_SUCCESS) {
                                goto top;
+                       }
                }
                ret = ledger_perform_blocking(l);
-               if (ret != KERN_SUCCESS)
+               if (ret != KERN_SUCCESS) {
                        goto top;
+               }
        } /* block */
 }
 
@@ -1479,30 +1487,34 @@ ledger_check_needblock(ledger_t l, uint64_t now)
                if (le->le_flags & LF_REFILL_SCHEDULED) {
                        assert(!(le->le_flags & LF_TRACKING_MAX));
 
-                       if ((le->_le.le_refill.le_last_refill + le->_le.le_refill.le_refill_period) > now) {
+                       if ((le->_le.le_refill.le_last_refill + le->_le.le_refill.le_refill_period) <= now) {
                                ledger_refill(now, l, i);
-                               if (limit_exceeded(le) == FALSE)
+                               if (limit_exceeded(le) == FALSE) {
                                        continue;
+                               }
                        }
                }
 
-               if (le->le_flags & LEDGER_ACTION_BLOCK)
+               if (le->le_flags & LEDGER_ACTION_BLOCK) {
                        block = 1;
-               if ((le->le_flags & LEDGER_ACTION_CALLBACK) == 0)
+               }
+               if ((le->le_flags & LEDGER_ACTION_CALLBACK) == 0) {
                        continue;
+               }
 
-                /*
-                 * If the LEDGER_ACTION_CALLBACK flag is on, we expect there to
-                 * be a registered callback.
-                 */
+               /*
+                * If the LEDGER_ACTION_CALLBACK flag is on, we expect there to
+                * be a registered callback.
+                */
                assert(lc != NULL);
                flags = flag_set(&le->le_flags, LF_CALLED_BACK);
                /* Callback has already been called */
-               if (flags & LF_CALLED_BACK)
+               if (flags & LF_CALLED_BACK) {
                        continue;
+               }
                lc->lc_func(FALSE, lc->lc_param0, lc->lc_param1);
        }
-       return(block);
+       return block;
 }
 
 
@@ -1517,24 +1529,27 @@ ledger_perform_blocking(ledger_t l)
        for (i = 0; i < l->l_size; i++) {
                le = &l->l_entries[i];
                if ((!limit_exceeded(le)) ||
-                   ((le->le_flags & LEDGER_ACTION_BLOCK) == 0))
+                   ((le->le_flags & LEDGER_ACTION_BLOCK) == 0)) {
                        continue;
+               }
 
                assert(!(le->le_flags & LF_TRACKING_MAX));
 
                /* Prepare to sleep until the resource is refilled */
-               ret = assert_wait_deadline(le, TRUE,
+               ret = assert_wait_deadline(le, THREAD_INTERRUPTIBLE,
                    le->_le.le_refill.le_last_refill + le->_le.le_refill.le_refill_period);
-               if (ret != THREAD_WAITING)
-                       return(KERN_SUCCESS);
+               if (ret != THREAD_WAITING) {
+                       return KERN_SUCCESS;
+               }
 
                /* Mark that somebody is waiting on this entry  */
                flag_set(&le->le_flags, LF_WAKE_NEEDED);
 
                ret = thread_block_reason(THREAD_CONTINUE_NULL, NULL,
                    AST_LEDGER);
-               if (ret != THREAD_AWAKENED)
-                       return(KERN_SUCCESS);
+               if (ret != THREAD_AWAKENED) {
+                       return KERN_SUCCESS;
+               }
 
                /*
                 * The world may have changed while we were asleep.
@@ -1542,9 +1557,9 @@ ledger_perform_blocking(ledger_t l)
                 * deficit.  Or maybe we're supposed to die now.
                 * Go back to the top and reevaluate.
                 */
-               return(KERN_FAILURE);
+               return KERN_FAILURE;
        }
-       return(KERN_SUCCESS);
+       return KERN_SUCCESS;
 }
 
 
@@ -1554,15 +1569,16 @@ ledger_get_entries(ledger_t ledger, int entry, ledger_amount_t *credit,
 {
        struct ledger_entry *le;
 
-       if (!ENTRY_VALID(ledger, entry))
-               return (KERN_INVALID_ARGUMENT);
+       if (!ENTRY_VALID(ledger, entry)) {
+               return KERN_INVALID_ARGUMENT;
+       }
 
        le = &ledger->l_entries[entry];
 
        *credit = le->le_credit;
        *debit = le->le_debit;
 
-       return (KERN_SUCCESS);
+       return KERN_SUCCESS;
 }
 
 kern_return_t
@@ -1570,14 +1586,15 @@ ledger_reset_callback_state(ledger_t ledger, int entry)
 {
        struct ledger_entry *le;
 
-       if (!ENTRY_VALID(ledger, entry))
-               return (KERN_INVALID_ARGUMENT);
+       if (!ENTRY_VALID(ledger, entry)) {
+               return KERN_INVALID_ARGUMENT;
+       }
 
        le = &ledger->l_entries[entry];
 
        flag_clear(&le->le_flags, LF_CALLED_BACK);
 
-       return (KERN_SUCCESS);
+       return KERN_SUCCESS;
 }
 
 kern_return_t
@@ -1585,14 +1602,35 @@ ledger_disable_panic_on_negative(ledger_t ledger, int entry)
 {
        struct ledger_entry *le;
 
-       if (!ENTRY_VALID(ledger, entry))
-               return (KERN_INVALID_ARGUMENT);
+       if (!ENTRY_VALID(ledger, entry)) {
+               return KERN_INVALID_ARGUMENT;
+       }
 
        le = &ledger->l_entries[entry];
 
        flag_clear(&le->le_flags, LF_PANIC_ON_NEGATIVE);
 
-       return (KERN_SUCCESS);
+       return KERN_SUCCESS;
+}
+
+kern_return_t
+ledger_get_panic_on_negative(ledger_t ledger, int entry, int *panic_on_negative)
+{
+       struct ledger_entry *le;
+
+       if (!ENTRY_VALID(ledger, entry)) {
+               return KERN_INVALID_ARGUMENT;
+       }
+
+       le = &ledger->l_entries[entry];
+
+       if (le->le_flags & LF_PANIC_ON_NEGATIVE) {
+               *panic_on_negative = TRUE;
+       } else {
+               *panic_on_negative = FALSE;
+       }
+
+       return KERN_SUCCESS;
 }
 
 kern_return_t
@@ -1600,8 +1638,9 @@ ledger_get_balance(ledger_t ledger, int entry, ledger_amount_t *balance)
 {
        struct ledger_entry *le;
 
-       if (!ENTRY_VALID(ledger, entry))
-               return (KERN_INVALID_ARGUMENT);
+       if (!ENTRY_VALID(ledger, entry)) {
+               return KERN_INVALID_ARGUMENT;
+       }
 
        le = &ledger->l_entries[entry];
 
@@ -1613,7 +1652,7 @@ ledger_get_balance(ledger_t ledger, int entry, ledger_amount_t *balance)
 
        *balance = le->le_credit - le->le_debit;
 
-       return (KERN_SUCCESS);
+       return KERN_SUCCESS;
 }
 
 int
@@ -1629,21 +1668,24 @@ ledger_template_info(void **buf, int *len)
         * caller's as the source.
         */
        l = current_task()->ledger;
-       if ((*len < 0) || (l == NULL))
-               return (EINVAL);
-
-       if (*len > l->l_size)
-                *len = l->l_size;
-       lti = kalloc((*len) * sizeof (struct ledger_template_info));
-       if (lti == NULL)
-               return (ENOMEM);
+       if ((*len < 0) || (l == NULL)) {
+               return EINVAL;
+       }
+
+       if (*len > l->l_size) {
+               *len = l->l_size;
+       }
+       lti = kalloc((*len) * sizeof(struct ledger_template_info));
+       if (lti == NULL) {
+               return ENOMEM;
+       }
        *buf = lti;
 
        template_lock(l->l_template);
        et = l->l_template->lt_entries;
 
        for (i = 0; i < *len; i++) {
-               memset(lti, 0, sizeof (*lti));
+               memset(lti, 0, sizeof(*lti));
                strlcpy(lti->lti_name, et->et_key, LEDGER_NAME_MAX);
                strlcpy(lti->lti_group, et->et_group, LEDGER_NAME_MAX);
                strlcpy(lti->lti_units, et->et_units, LEDGER_NAME_MAX);
@@ -1652,25 +1694,25 @@ ledger_template_info(void **buf, int *len)
        }
        template_unlock(l->l_template);
 
-       return (0);
+       return 0;
 }
 
 static void
 ledger_fill_entry_info(struct ledger_entry      *le,
-                       struct ledger_entry_info *lei,
-                       uint64_t                  now)
+    struct ledger_entry_info *lei,
+    uint64_t                  now)
 {
-       assert(le  != NULL);
+       assert(le != NULL);
        assert(lei != NULL);
 
-       memset(lei, 0, sizeof (*lei));
+       memset(lei, 0, sizeof(*lei));
 
        lei->lei_limit         = le->le_limit;
        lei->lei_credit        = le->le_credit;
        lei->lei_debit         = le->le_debit;
        lei->lei_balance       = lei->lei_credit - lei->lei_debit;
-       lei->lei_refill_period = (le->le_flags & LF_REFILL_SCHEDULED) ? 
-                                                            abstime_to_nsecs(le->_le.le_refill.le_refill_period) : 0;
+       lei->lei_refill_period = (le->le_flags & LF_REFILL_SCHEDULED) ?
+           abstime_to_nsecs(le->_le.le_refill.le_refill_period) : 0;
        lei->lei_last_refill   = abstime_to_nsecs(now - le->_le.le_refill.le_last_refill);
 }
 
@@ -1683,14 +1725,17 @@ ledger_get_task_entry_info_multiple(task_t task, void **buf, int *len)
        int i;
        ledger_t l;
 
-       if ((*len < 0) || ((l = task->ledger) == NULL))
-               return (EINVAL);
+       if ((*len < 0) || ((l = task->ledger) == NULL)) {
+               return EINVAL;
+       }
 
-       if (*len > l->l_size)
-                *len = l->l_size;
-       lei = kalloc((*len) * sizeof (struct ledger_entry_info));
-       if (lei == NULL)
-               return (ENOMEM);
+       if (*len > l->l_size) {
+               *len = l->l_size;
+       }
+       lei = kalloc((*len) * sizeof(struct ledger_entry_info));
+       if (lei == NULL) {
+               return ENOMEM;
+       }
        *buf = lei;
 
        le = l->l_entries;
@@ -1701,13 +1746,13 @@ ledger_get_task_entry_info_multiple(task_t task, void **buf, int *len)
                lei++;
        }
 
-       return (0);
+       return 0;
 }
 
 void
 ledger_get_entry_info(ledger_t                  ledger,
-                      int                       entry,
-                      struct ledger_entry_info *lei)
+    int                       entry,
+    struct ledger_entry_info *lei)
 {
        uint64_t now = mach_absolute_time();
 
@@ -1725,15 +1770,16 @@ ledger_info(task_t task, struct ledger_info *info)
 {
        ledger_t l;
 
-       if ((l = task->ledger) == NULL)
-               return (ENOENT);
+       if ((l = task->ledger) == NULL) {
+               return ENOENT;
+       }
 
-       memset(info, 0, sizeof (*info));
+       memset(info, 0, sizeof(*info));
 
        strlcpy(info->li_name, l->l_template->lt_name, LEDGER_NAME_MAX);
        info->li_id = l->l_id;
        info->li_entries = l->l_size;
-       return (0);
+       return 0;
 }
 
 #ifdef LEDGER_DEBUG
@@ -1744,12 +1790,14 @@ ledger_limit(task_t task, struct ledger_limit_args *args)
        int64_t limit;
        int idx;
 
-       if ((l = task->ledger) == NULL)
-               return (EINVAL);
+       if ((l = task->ledger) == NULL) {
+               return EINVAL;
+       }
 
        idx = ledger_key_lookup(l->l_template, args->lla_name);
-       if ((idx < 0) || (idx >= l->l_size))
-               return (EINVAL);
+       if ((idx < 0) || (idx >= l->l_size)) {
+               return EINVAL;
+       }
 
        /*
         * XXX - this doesn't really seem like the right place to have
@@ -1763,7 +1811,7 @@ ledger_limit(task_t task, struct ledger_limit_args *args)
 
                if (args->lla_refill_period) {
                        /*
-                        * If a refill is scheduled, then the limit is 
+                        * If a refill is scheduled, then the limit is
                         * specified as a percentage of one CPU.  The
                         * syscall specifies the refill period in terms of
                         * milliseconds, so we need to convert to nsecs.
@@ -1788,11 +1836,12 @@ ledger_limit(task_t task, struct ledger_limit_args *args)
                lprintf(("%s limited to %lld\n", args->lla_name, limit));
        }
 
-       if (args->lla_refill_period > 0)
+       if (args->lla_refill_period > 0) {
                ledger_set_period(l, idx, args->lla_refill_period);
+       }
 
        ledger_set_limit(l, idx, limit);
        flag_set(&l->l_entries[idx].le_flags, LEDGER_ACTION_BLOCK);
-       return (0);
+       return 0;
 }
 #endif