/*
- * 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,
* 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@
*/
/*
#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
* 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);
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
uint64_t nsecs;
absolutetime_to_nanoseconds(abstime, &nsecs);
- return (nsecs);
+ return nsecs;
}
static uint64_t
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
{
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;
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
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));
+ }
}
/*
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);
idx = template->lt_cnt++;
template_unlock(template);
- return (idx);
+ return idx;
}
{
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;
}
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;
}
/*
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;
}
/*
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;
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);
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);
+ }
+ }
}
/*
* 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;
}
/*
}
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 *
callback = ledger->l_template->lt_entries[entry].et_callback;
TEMPLATE_IDLE(s, ledger->l_template);
- return (callback);
+ return callback;
}
/*
* 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);
* 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 */
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)) {
* 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) {
/*
* 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
}
}
- 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);
}
}
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];
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;
}
/*
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)
{
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.
{
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
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];
}
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
{
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;
}
/*
* 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];
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;
}
/*
*/
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
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
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;
}
/*
*/
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;
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;
}
/*
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;
}
/*
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;
}
/*
{
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;
}
/*
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];
/*
* 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);
flag_set(&le->le_flags, LF_REFILL_SCHEDULED);
- return (KERN_SUCCESS);
+ return KERN_SUCCESS;
}
/*
{
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
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];
}
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
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;
*/
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);
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);
/*
/*
* 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
}
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.
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 */
}
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;
}
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.
* 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;
}
{
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
{
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
{
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
{
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];
*balance = le->le_credit - le->le_debit;
- return (KERN_SUCCESS);
+ return KERN_SUCCESS;
}
int
* 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);
}
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);
}
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;
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();
{
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
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
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.
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