# include <kernel/kernel.h> # include <kernel/rsrc.h> # include <type.h> # include <status.h> object rsrcd; /* resource manager */ mapping resources; /* registered resources */ string owner; /* owner of these resources */ /* * NAME: create() * DESCRIPTION: initialize resource mapping */ static void create(int clone) { if (clone) { resources = ([ "stack" : ({ 0, -1, 0 }), "ticks" : ({ 0, -1, 0 }), "tick usage" : ({ 0.0, -1, 0 }) ]); rsrcd = find_object(RSRCD); } } /* * NAME: set_owner() * DESCRIPTION: set the owner of this resource */ void set_owner(string name) { if (previous_object() == rsrcd) { owner = name; } } /* * NAME: remove_rsrc() * DESCRIPTION: remove a resource */ void remove_rsrc(string name) { if (previous_object() == rsrcd) { resources[name] = nil; } } /* * NAME: rsrc_set_limit() * DESCRIPTION: set individual resource limit */ void rsrc_set_limit(string name, int max, int decay) { if (previous_object() == rsrcd) { mixed *rsrc; if ((rsrc=resources[name])) { rsrc[RSRC_MAX] = max; } else { resources[name] = ({ (decay == 0) ? 0 : 0.0, max, 0 }); } } } /* * NAME: decay_rsrc() * DESCRIPTION: decay a resource */ private void decay_rsrc(mixed *rsrc, mixed *grsrc, int time) { float usage, decay; int period, t; usage = rsrc[RSRC_USAGE]; decay = (float) (100 - (int) grsrc[GRSRC_DECAY]) / 100.0; period = grsrc[GRSRC_PERIOD]; time -= period; t = rsrc[RSRC_DECAYTIME]; do { usage *= decay; if (usage < 0.5) { t = time + period; break; } t += period; } while (time >= t); rlimits (-1; -1) { rsrc[RSRC_DECAYTIME] = t; rsrc[RSRC_USAGE] = floor(usage + 0.5); } } /* * NAME: rsrc_get() * DESCRIPTION: get individual resource usage */ int *rsrc_get(string name, mixed *grsrc) { if (previous_object() == rsrcd) { mixed *rsrc; int time; rsrc = resources[name]; if (!rsrc) { return ({ ((int) grsrc[GRSRC_DECAY] == 0) ? 0 : 0.0, grsrc[GRSRC_MAX], 0 }) + grsrc[GRSRC_DECAY .. GRSRC_PERIOD]; } else { if ((int) grsrc[GRSRC_DECAY] != 0 && (time=time()) - (int) rsrc[RSRC_DECAYTIME] >= (int) grsrc[GRSRC_PERIOD]) { /* decay resource */ decay_rsrc(rsrc, grsrc, time); } rsrc += grsrc[GRSRC_DECAY .. GRSRC_PERIOD]; if ((int) rsrc[RSRC_MAX] < 0) { rsrc[RSRC_MAX] = grsrc[GRSRC_MAX]; } if (typeof(rsrc[RSRC_INDEXED]) == T_MAPPING) { rsrc[RSRC_INDEXED] = rsrc[RSRC_INDEXED][..]; } return rsrc; } } } /* * NAME: rsrc_incr() * DESCRIPTION: increment or decrement a resource, return 1 if successful, * 0 if the maximum would be exceeded */ int rsrc_incr(string name, mixed index, int incr, mixed *grsrc, int force) { if (previous_object() == rsrcd) { mixed *rsrc; int time, max; rsrc = resources[name]; time = time(); if (!rsrc) { /* new resource */ rsrc = resources[name] = ((int) grsrc[GRSRC_DECAY] == 0) ? ({ 0, -1, 0 }) : ({ 0.0, -1, time }); max = grsrc[GRSRC_MAX]; } else { /* existing resource */ if ((int) grsrc[GRSRC_DECAY] != 0 && time - (int) rsrc[RSRC_DECAYTIME] >= (int) grsrc[GRSRC_PERIOD]) { /* decay resource */ decay_rsrc(rsrc, grsrc, time); } max = ((int) rsrc[RSRC_MAX] >= 0) ? rsrc[RSRC_MAX] : grsrc[GRSRC_MAX]; } if (!force && max >= 0 && (incr > max || (int) rsrc[RSRC_USAGE] > max - incr) && incr > 0) { return FALSE; /* would exceed limit */ } if (incr != 0) { rlimits (-1; -1) { if (index) { /* * indexed resource */ catch { if (typeof(index) == T_OBJECT) { /* let object keep track */ index->_F_rsrc_incr(name, incr); } else if (typeof(rsrc[RSRC_INDEXED]) != T_MAPPING) { rsrc[RSRC_INDEXED] = ([ index : incr ]); } else if (!rsrc[RSRC_INDEXED][index]) { rsrc[RSRC_INDEXED][index] = incr; } else if (!(rsrc[RSRC_INDEXED][index] += incr)) { rsrc[RSRC_INDEXED][index] = nil; } } : { return FALSE; /* error: increment failed */ } } if (typeof(rsrc[RSRC_USAGE]) == T_INT) { /* normal resource */ rsrc[RSRC_USAGE] += incr; } else { /* * decaying resources are expected to be updated frequently, * so handle it with a callout */ call_out("rsrc_update", 0, rsrc, incr); } } } return TRUE; } } /* * NAME: rsrc_update() * DESCRIPTION: update a decaying resource */ static void rsrc_update(float *rsrc, int incr) { rsrc[RSRC_USAGE] += (float) incr; } /* * NAME: call_limits() * DESCRIPTION: return stack & ticks limits */ mixed *call_limits(mixed *limits, int stack, int ticks, int *rstack, int *rticks, int *usage) { if (previous_object() == rsrcd) { int maxstack, maxticks; /* determine available stack */ maxstack = resources["stack"][RSRC_MAX]; if (maxstack < 0) { maxstack = rstack[GRSRC_MAX]; } if (maxstack > stack && stack >= 0) { maxstack = stack; } if (maxstack >= 0) { maxstack++; } /* determine available ticks */ maxticks = resources["ticks"][RSRC_MAX]; if (maxticks < 0) { maxticks = rticks[GRSRC_MAX]; } if (maxticks >= 0) { mixed *rsrc; int n; rsrc = resources["tick usage"]; if ((n=time()) - (int) rsrc[RSRC_DECAYTIME] >= usage[GRSRC_PERIOD]) { /* decay resource */ decay_rsrc(rsrc, usage, n); } n = rsrc[RSRC_MAX]; if (n < 0) { n = usage[GRSRC_MAX]; } if (n >= 0 && (int) rsrc[RSRC_USAGE] >= n >> 1) { maxticks = (int) ((float) maxticks * ((float) n - rsrc[RSRC_USAGE]) / (float) (n >> 1)); } if (maxticks > ticks - 25 && ticks >= 0) { maxticks = ticks - 25; } if (maxticks <= 0) { maxticks = 1; } } return ({ limits, owner, maxstack, maxticks, ticks }); } } /* * NAME: update_ticks() * DESCRIPTION: update ticks for the current owner */ void update_ticks(int ticks) { if (previous_object() == rsrcd) { call_out("rsrc_update", 0, resources["tick usage"], ticks); } } /* * NAME: reboot() * DESCRIPTION: recover from a reboot */ void reboot(int downtime) { if (previous_object() == rsrcd) { mixed **rsrcs, *rsrc; int i; rsrcs = map_values(resources); for (i = sizeof(rsrcs); --i >= 0; ) { rsrc = rsrcs[i]; if (typeof(rsrc[RSRC_DECAYTIME]) == T_INT && (int) rsrc[RSRC_DECAYTIME] != 0) { rsrc[RSRC_DECAYTIME] += downtime; } } } }