+/* 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) && \
+ (((l)->l_entries[e].le_flags & ENTRY_ACTIVE) == ENTRY_ACTIVE))
+
+#ifdef LEDGER_DEBUG
+int ledger_debug = 0;
+
+#define ASSERT(a) assert(a)
+#define lprintf(a) if (ledger_debug) { \
+ printf("%lld ", abstime_to_nsecs(mach_absolute_time() / 1000000)); \
+ printf a ; \
+}
+#else
+#define lprintf(a)
+#define ASSERT(a)
+#endif
+
+struct ledger_callback {
+ 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;
+};
+
+lck_grp_t ledger_lck_grp;
+
+/*
+ * Modifying the reference count, table size, or table contents requires
+ * holding the lt_lock. Modfying the table address requires both lt_lock
+ * and setting the inuse bit. This means that the lt_entries field can be
+ * safely dereferenced if you hold either the lock or the inuse bit. The
+ * inuse bit exists solely to allow us to swap in a new, larger entries
+ * table without requiring a full lock to be acquired on each lookup.
+ * Accordingly, the inuse bit should never be held for longer than it takes
+ * 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;
+ 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_INUSE(s, t) { \
+ s = splsched(); \
+ while (OSCompareAndSwap(0, 1, &((t)->lt_inuse))) \
+ ; \
+}
+
+#define TEMPLATE_IDLE(s, t) { \
+ (t)->lt_inuse = 0; \
+ splx(s); \
+}
+
+/*
+ * 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;
+ volatile ledger_amount_t le_credit __attribute__((aligned(8)));
+ volatile ledger_amount_t le_debit __attribute__((aligned(8)));
+ /*
+ * 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;
+} __attribute__((aligned(8)));
+
+struct ledger {
+ int l_id;
+ struct ledger_template *l_template;
+ int l_refs;
+ int l_size;
+ struct ledger_entry *l_entries;
+};
+
+static int ledger_cnt = 0;
+/* ledger ast helper functions */
+static uint32_t ledger_check_needblock(ledger_t l, uint64_t now);
+static kern_return_t ledger_perform_blocking(ledger_t l);
+static uint32_t flag_set(volatile uint32_t *flags, uint32_t bit);
+static uint32_t flag_clear(volatile uint32_t *flags, uint32_t bit);
+
+#if 0
+static void
+debug_callback(const void *p0, __unused const void *p1)