#include <kern/kalloc.h>
#include <kern/task.h>
#include <kern/thread.h>
+#include <kern/coalition.h>
#include <kern/processor.h>
#include <kern/machine.h>
};
lck_grp_t ledger_lck_grp;
+os_refgrp_decl(static, ledger_refgrp, "ledger", NULL);
/*
* Modifying the reference count, table size, or table contents requires
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
ledger_template_dereference(ledger_template_t template)
{
template_unlock(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));
}
}
ledger->l_template = template;
ledger->l_id = ledger_cnt++;
- os_ref_init(&ledger->l_refs, NULL);
+ os_ref_init(&ledger->l_refs, &ledger_refgrp);
ledger->l_size = (int32_t)cnt;
template_lock(template);
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;
}
/*
* Take a reference on a ledger
*/
-kern_return_t
+void
ledger_reference(ledger_t ledger)
{
if (!LEDGER_VALID(ledger)) {
- return KERN_INVALID_ARGUMENT;
- }
- os_ref_retain(&ledger->l_refs);
- return KERN_SUCCESS;
-}
-
-int
-ledger_reference_count(ledger_t ledger)
-{
- if (!LEDGER_VALID(ledger)) {
- return -1;
+ return;
}
- return os_ref_get_count(&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)
{
if (!LEDGER_VALID(ledger)) {
- return KERN_INVALID_ARGUMENT;
+ return;
}
if (os_ref_release(&ledger->l_refs) == 0) {
pmap_ledger_free(ledger);
}
}
-
- return KERN_SUCCESS;
}
/*
* use positive limits.
*/
balance = le->le_credit - le->le_debit;
- if ((le->le_warn_level != LEDGER_LIMIT_INFINITY) && (balance > le->le_warn_level)) {
+ if (le->le_warn_percent != LEDGER_PERCENT_NONE &&
+ ((balance > (le->le_limit * le->le_warn_percent) >> 16))) {
return 1;
}
return 0;
{
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);
{
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];
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;
}
/*
- * 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;
}
{
struct ledger *l = thread->t_ledger;
struct ledger *thl;
+ struct ledger *coalition_ledger;
uint32_t block;
uint64_t now;
uint8_t task_flags;
}
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 (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) {
continue;