diff options
Diffstat (limited to 'src/resource/resource-set.c')
-rw-r--r-- | src/resource/resource-set.c | 684 |
1 files changed, 684 insertions, 0 deletions
diff --git a/src/resource/resource-set.c b/src/resource/resource-set.c new file mode 100644 index 0000000..12e56d7 --- /dev/null +++ b/src/resource/resource-set.c @@ -0,0 +1,684 @@ +/* + * Copyright (c) 2012, Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <string.h> + +#include <murphy/common/mm.h> +#include <murphy/common/hashtbl.h> +#include <murphy/common/utils.h> +#include <murphy/common/log.h> +#include <murphy/common/mainloop.h> + +#include <murphy-db/mqi.h> + +#include <murphy/resource/client-api.h> +#include <murphy/resource/common-api.h> + +#include "resource-set.h" +#include "application-class.h" +#include "resource.h" +#include "resource-client.h" +#include "resource-owner.h" +#include "resource-lua.h" + + +#define STAMP_MAX ((uint32_t)1 << MRP_KEY_STAMP_BITS) +#define PRIORITY_MAX ((uint32_t)1 << MRP_KEY_PRIORITY_BITS) + + +static MRP_LIST_HOOK(resource_set_list); +static uint32_t resource_set_count; +static mrp_htbl_t *id_hash; + +static int add_to_id_hash(mrp_resource_set_t *); +static void remove_from_id_hash(mrp_resource_set_t *); + +static mrp_resource_t *find_resource_by_name(mrp_resource_set_t *,const char*); +#if 0 +static mrp_resource_t *find_resource_by_id(mrp_resource_set_t *, uint32_t); +#endif + +static uint32_t get_request_stamp(void); +static const char *state_str(mrp_resource_state_t); +static void send_rset_event(mrp_resource_set_t *rset, + mrp_resource_event_t ev); + +uint32_t mrp_get_resource_set_count(void) +{ + return resource_set_count; +} + +mrp_resource_set_t *mrp_resource_set_create(mrp_resource_client_t *client, + bool auto_release, + bool dont_wait, + uint32_t priority, + mrp_resource_event_cb_t event_cb, + void *user_data) +{ + static uint32_t our_id; + + mrp_resource_set_t *rset; + + MRP_ASSERT(client, "invalid argument"); + + if (priority >= PRIORITY_MAX) + priority = PRIORITY_MAX - 1; + + if (!(rset = mrp_allocz(sizeof(mrp_resource_set_t)))) + mrp_log_error("Memory alloc failure. Can't create resource set"); + else { + rset->id = ++our_id; + + rset->dont_wait.current = dont_wait; + rset->dont_wait.client = dont_wait; + + rset->auto_release.current = auto_release; + rset->auto_release.client = auto_release; + + mrp_list_init(&rset->resource.list); + rset->resource.share = false; + + mrp_list_append(&client->resource_sets, &rset->client.list); + rset->client.ptr = client; + rset->client.reqno = MRP_RESOURCE_REQNO_INVALID; + + mrp_list_init(&rset->class.list); + rset->class.priority = priority; + + mrp_list_append(&resource_set_list, &rset->list); + + rset->event = event_cb; + rset->user_data = user_data; + + resource_set_count++; + + add_to_id_hash(rset); + mrp_resource_lua_register_resource_set(rset); + + send_rset_event(rset, MRP_RESOURCE_EVENT_CREATED); + } + + return rset; +} + +void mrp_resource_set_destroy(mrp_resource_set_t *rset) +{ + mrp_resource_state_t state; + mrp_list_hook_t *entry, *n; + mrp_resource_t *res; + + if (rset) { + state = rset->state; + + rset->event = NULL; /* make sure nothing is sent any more */ + + send_rset_event(rset, MRP_RESOURCE_EVENT_DESTROYED); + + mrp_resource_lua_unregister_resource_set(rset); + remove_from_id_hash(rset); + + if (state == mrp_resource_acquire) + mrp_resource_set_release(rset, MRP_RESOURCE_REQNO_INVALID); + + mrp_list_foreach(&rset->resource.list, entry, n) { + res = mrp_list_entry(entry, mrp_resource_t, list); + mrp_resource_notify(res, rset, MRP_RESOURCE_EVENT_DESTROYED); + mrp_resource_destroy(res); + } + + mrp_list_delete(&rset->list); + mrp_list_delete(&rset->client.list); + mrp_list_delete(&rset->class.list); + + mrp_free(rset); + + if (resource_set_count > 0) + resource_set_count--; + } +} + +mrp_resource_set_t *mrp_resource_set_find_by_id(uint32_t id) +{ + return id_hash ? mrp_htbl_lookup(id_hash, NULL + id) : NULL; +} + +uint32_t mrp_get_resource_set_id(mrp_resource_set_t *rset) +{ + MRP_ASSERT(rset, "invalid argument"); + + return rset->id; +} + +mrp_resource_state_t mrp_get_resource_set_state(mrp_resource_set_t *rset) +{ + MRP_ASSERT(rset, "invalid argument"); + + return rset->state; +} + +mrp_resource_mask_t mrp_get_resource_set_grant(mrp_resource_set_t *rset) +{ + MRP_ASSERT(rset, "invalid argument"); + + return rset->resource.mask.grant; +} + +mrp_resource_mask_t mrp_get_resource_set_advice(mrp_resource_set_t *rset) +{ + MRP_ASSERT(rset, "invalid argument"); + + return rset->resource.mask.advice; +} + +mrp_resource_client_t *mrp_get_resource_set_client(mrp_resource_set_t *rset) +{ + MRP_ASSERT(rset, "invalid argument"); + + return rset->client.ptr; +} + +mrp_resource_t *mrp_resource_set_find_resource(uint32_t rsetid, + const char *resnam) +{ + mrp_resource_set_t *rset; + mrp_resource_t *res; + + MRP_ASSERT(resnam, "invalid argument"); + + if (!(rset = mrp_resource_set_find_by_id(rsetid))) + res = NULL; + else + res = find_resource_by_name(rset, resnam); + + return res; +} + + +mrp_resource_t *mrp_resource_set_iterate_resources(mrp_resource_set_t *rset, + void **cursor) +{ + mrp_list_hook_t *list, *entry; + + MRP_ASSERT(rset && cursor, "invalid argument"); + + list = &rset->resource.list; + entry = (*cursor == NULL) ? list->next : (mrp_list_hook_t *)*cursor; + + if (entry == list) + return NULL; + + *cursor = entry->next; + + return mrp_list_entry(entry, mrp_resource_t, list); +} + + +int mrp_resource_set_add_resource(mrp_resource_set_t *rset, + const char *name, + bool shared, + mrp_attr_t *attrs, + bool mandatory) +{ + uint32_t mask; + mrp_resource_t *res; + uint32_t rsetid; + bool autorel; + + MRP_ASSERT(rset && name, "invalid argument"); + + rsetid = rset->id; + autorel = rset->auto_release.client; + + if (!(res = mrp_resource_create(name, rsetid, autorel, shared, attrs))) { + mrp_log_error("Can't add resource '%s' name to resource set %u", + name, rset->id); + return -1; + } + + mask = mrp_resource_get_mask(res); + + rset->resource.mask.all |= mask; + rset->resource.mask.mandatory |= mandatory ? mask : 0; + rset->resource.share |= mrp_resource_is_shared(res); + + + mrp_list_append(&rset->resource.list, &res->list); + + mrp_resource_lua_add_resource_to_resource_set(rset, res); + + return 0; +} + +mrp_attr_t *mrp_resource_set_read_attribute(mrp_resource_set_t *rset, + const char *resnam, + uint32_t attridx, + mrp_attr_t *buf) +{ + mrp_resource_t *res; + + MRP_ASSERT(rset && resnam, "invalid argument"); + + if (!(res = find_resource_by_name(rset, resnam))) + return NULL; + + return mrp_resource_read_attribute(res, attridx, buf); +} + +mrp_attr_t *mrp_resource_set_read_all_attributes(mrp_resource_set_t *rset, + const char *resnam, + uint32_t buflen, + mrp_attr_t *buf) +{ + mrp_resource_t *res; + + MRP_ASSERT(rset && resnam, "invalid argument"); + + if (!(res = find_resource_by_name(rset, resnam))) + return NULL; + + return mrp_resource_read_all_attributes(res, buflen, buf); +} + +int mrp_resource_set_write_attributes(mrp_resource_set_t *rset, + const char *resnam, + mrp_attr_t *attrs) +{ + mrp_resource_t *res; + + MRP_ASSERT(rset && resnam && attrs, "invalid argument"); + + if (!(res = find_resource_by_name(rset, resnam))) + return -1; + + if (mrp_resource_write_attributes(res, attrs) < 0) + return -1; + + return 0; +} + +void mrp_resource_set_acquire(mrp_resource_set_t *rset, uint32_t reqid) +{ + mrp_resource_state_t old_state; + mqi_handle_t trh; + + MRP_ASSERT(rset, "invalid argument"); + + mrp_debug("acquiring resource set #%d", rset->id); + + old_state = rset->state; + rset->state = mrp_resource_acquire; + + if (rset->class.ptr) { + rset->request.id = reqid; + rset->request.stamp = get_request_stamp(); + + mrp_application_class_move_resource_set(rset); + + if (old_state != mrp_resource_acquire) + mrp_resource_set_notify(rset, MRP_RESOURCE_EVENT_ACQUIRE); + + trh = mqi_begin_transaction(); + mrp_resource_owner_update_zone(rset->zone, rset, reqid); + mqi_commit_transaction(trh); + } +} + +void mrp_resource_set_release(mrp_resource_set_t *rset, uint32_t reqid) +{ + mqi_handle_t trh; + + MRP_ASSERT(rset, "invalid argument"); + + mrp_debug("releasing resource set #%d", rset->id); + + if (!rset->class.ptr) + rset->state = mrp_resource_release; + else { + if (rset->state == mrp_resource_release) { + if (rset->event) + rset->event(reqid, rset, rset->user_data); + } + else { + rset->state = mrp_resource_release; + rset->request.id = reqid; + rset->request.stamp = get_request_stamp(); + + mrp_application_class_move_resource_set(rset); + + mrp_resource_set_notify(rset, MRP_RESOURCE_EVENT_RELEASE); + + trh = mqi_begin_transaction(); + mrp_resource_owner_update_zone(rset->zone, rset, reqid); + mqi_commit_transaction(trh); + } + } +} + +void mrp_resource_set_updated(mrp_resource_set_t *rset) +{ + mrp_resource_t *res; + mrp_resource_def_t *def; + mrp_list_hook_t *resen, *n; + mrp_resource_mask_t mask; + bool grant; + + MRP_ASSERT(rset, "invalid argument"); + + mrp_debug("resource set got #%d updated", rset->id); + + mrp_list_foreach(&rset->resource.list, resen, n) { + res = mrp_list_entry(resen, mrp_resource_t, list); + def = res->def; + + mask = ((mrp_resource_mask_t)1) << def->id; + grant = (mask & rset->resource.mask.grant) ? true : false; + + mrp_debug(" %s now %sgranted", def->name, grant ? "" : "not "); + + mrp_resource_user_update(res, rset->state, grant); + } +} + + +MRP_REGISTER_EVENTS(resource_events, + MRP_EVENT(MURPHY_RESOURCE_EVENT_CREATED , MRP_RESOURCE_EVENT_CREATED ), + MRP_EVENT(MURPHY_RESOURCE_EVENT_DESTROYED, MRP_RESOURCE_EVENT_DESTROYED), + MRP_EVENT(MURPHY_RESOURCE_EVENT_ACQUIRE , MRP_RESOURCE_EVENT_ACQUIRE ), + MRP_EVENT(MURPHY_RESOURCE_EVENT_RELEASE , MRP_RESOURCE_EVENT_RELEASE )); + + + +static void send_rset_event(mrp_resource_set_t *rset, mrp_resource_event_t ev) +{ + mrp_event_bus_t *bus = MRP_GLOBAL_BUS; + uint32_t id = resource_events[ev].id; + int flags = MRP_EVENT_SYNCHRONOUS;; + uint16_t tag = MRP_RESOURCE_TAG_RSET_ID; + + MRP_ASSERT(rset, "invalid argument"); + + /* The resource set id is enough information, because the full resource + * set can be found by making a query with the id. */ + + + mrp_debug("emit event %d for rset %u", id, rset->id); + + switch (ev) { + case MRP_RESOURCE_EVENT_CREATED: + mrp_event_emit_msg(bus, id, flags, MRP_MSG_TAG_UINT32(tag, rset->id)); + break; + case MRP_RESOURCE_EVENT_ACQUIRE: + mrp_event_emit_msg(bus, id, flags, MRP_MSG_TAG_UINT32(tag, rset->id)); + break; + case MRP_RESOURCE_EVENT_RELEASE: + mrp_event_emit_msg(bus, id, flags, MRP_MSG_TAG_UINT32(tag, rset->id)); + break; + case MRP_RESOURCE_EVENT_DESTROYED: + mrp_event_emit_msg(bus, id, flags, MRP_MSG_TAG_UINT32(tag, rset->id)); + break; + default: + break; + } +} + +void mrp_resource_set_notify(mrp_resource_set_t *rset, mrp_resource_event_t ev) +{ + mrp_resource_t *res; + void *cursor = NULL; + + MRP_ASSERT(rset, "invalid argument"); + + send_rset_event(rset, ev); + + while ((res = mrp_resource_set_iterate_resources(rset, &cursor))) + mrp_resource_notify(res, rset, ev); +} + +void mrp_resource_set_request_auto_release(mrp_resource_set_t *rset, + bool auto_release) +{ + MRP_ASSERT(rset, "invalid argument"); + + rset->auto_release.current = auto_release; +} + +void mrp_resource_set_request_dont_wait(mrp_resource_set_t *rset, + bool dont_wait) +{ + MRP_ASSERT(rset, "invalid argument"); + + rset->dont_wait.current = dont_wait; +} + +int mrp_resource_set_print(mrp_resource_set_t *rset, size_t indent, + char *buf, int len) +{ +#define PRINT(fmt, args...) if (p<e) { p += snprintf(p, e-p, fmt , ##args); } + + mrp_resource_t *res; + mrp_list_hook_t *resen, *n; + uint32_t mandatory; + char gap[] = " "; + char *p, *e; + + if (len <= 0) + return 0; + + MRP_ASSERT(rset && indent < sizeof(gap)-1 && buf, + "invalid argument"); + + gap[indent] = '\0'; + + e = (p = buf) + len; + + mandatory = rset->resource.mask.mandatory; + + PRINT("%s%3u - 0x%02x/0x%02x 0x%02x/0x%02x 0x%08x %d %s%s%s %s\n", + gap, rset->id, + rset->resource.mask.all, mandatory, + rset->resource.mask.grant, rset->resource.mask.advice, + mrp_application_class_get_sorting_key(rset), rset->class.priority, + rset->resource.share ? "shared ":"exclusive", + rset->auto_release.client ? ",autorelease" : "", + rset->dont_wait.client ? ",dontwait" : "", + state_str(rset->state)); + + mrp_list_foreach(&rset->resource.list, resen, n) { + res = mrp_list_entry(resen, mrp_resource_t, list); + p += mrp_resource_print(res, mandatory, indent+6, p, e-p); + } + + if (p >= e) { + if (len >= 5) { + e[-5] = e[-4] = e[-3] = '.'; + e[-2] = '\n'; + e[-1] = '\0'; + } + } + + return p - buf; + +#undef PRINT +} + +static uint32_t rset_hash(const void *key) +{ + return (uint32_t)(key - NULL); +} + +static int rset_comp(const void *key1, const void *key2) +{ + uint32_t k1 = key1 - NULL; + uint32_t k2 = key2 - NULL; + + return (k1 == k2) ? 0 : ((k1 > k2) ? 1 : -1); +} + +static void init_id_hash(void) +{ + mrp_htbl_config_t cfg; + + if (!id_hash) { + cfg.nentry = 32; + cfg.comp = rset_comp; + cfg.hash = rset_hash; + cfg.free = NULL; + cfg.nbucket = cfg.nentry; + + id_hash = mrp_htbl_create(&cfg); + + MRP_ASSERT(id_hash, "failed to make id_hash for resource sets"); + } +} + +static int add_to_id_hash(mrp_resource_set_t *rset) +{ + MRP_ASSERT(rset, "invalid argument"); + + init_id_hash(); + + if (!mrp_htbl_insert(id_hash, NULL + rset->id, rset)) + return -1; + + return 0; +} + +static void remove_from_id_hash(mrp_resource_set_t *rset) +{ + mrp_resource_set_t *deleted; + + if (id_hash && rset) { + deleted = mrp_htbl_remove(id_hash, NULL + rset->id, false); + + MRP_ASSERT(!deleted || deleted == rset, "confused with data " + "structures when deleting resource-set from id hash"); + + /* in case we were not compiled with debug enabled */ + if (deleted != rset) { + mrp_log_error("confused with data structures when deleting " + "resource-set '%u' from id hash", rset->id); + } + } +} + +static mrp_resource_t *find_resource_by_name(mrp_resource_set_t *rset, + const char *name) +{ + mrp_list_hook_t *entry, *n; + mrp_resource_t *res; + mrp_resource_def_t *rdef; + + MRP_ASSERT(rset && name, "invalid_argument"); + + mrp_list_foreach(&rset->resource.list, entry, n) { + res = mrp_list_entry(entry, mrp_resource_t, list); + rdef = res->def; + + MRP_ASSERT(rdef, "confused with data structures"); + + if (!strcasecmp(name, rdef->name)) + return res; + } + + return NULL; +} + +#if 0 +static mrp_resource_t *find_resource_by_id(mrp_resource_set_t *rset, + uint32_t id) +{ + mrp_list_hook_t *entry, *n; + mrp_resource_t *res; + mrp_resource_def_t *rdef; + + MRP_ASSERT(rset, "invalid_argument"); + + mrp_list_foreach(&rset->resource.list, entry, n) { + res = mrp_list_entry(entry, mrp_resource_t, list); + rdef = res->def; + + MRP_ASSERT(rdef, "confused with data structures"); + + if (id == rdef->id) + return res; + } + + return NULL; +} +#endif + +static uint32_t get_request_stamp(void) +{ + static uint32_t stamp; + + mrp_list_hook_t *entry, *n; + mrp_resource_set_t *rset; + uint32_t min; + + if ((min = stamp) >= STAMP_MAX) { + mrp_log_info("rebasing resource set stamps"); + + mrp_list_foreach(&resource_set_list, entry, n) { + rset = mrp_list_entry(entry, mrp_resource_set_t, list); + if (rset->request.stamp < min) + min = rset->request.stamp; + } + + stamp -= min; + + mrp_list_foreach(&resource_set_list, entry, n) { + rset = mrp_list_entry(entry, mrp_resource_set_t, list); + rset->request.stamp -= min; + } + } + + MRP_ASSERT(stamp < STAMP_MAX, "Request stamp overflow"); + + return stamp++; +} + +static const char *state_str(mrp_resource_state_t state) +{ + switch(state) { + case mrp_resource_no_request: return "no-request"; + case mrp_resource_release: return "release"; + case mrp_resource_acquire: return "acquire"; + default: return "< ??? >"; + } +} + + +/* + * Local Variables: + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + * + */ |