summaryrefslogtreecommitdiff
path: root/src/resource/lua-resource.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/resource/lua-resource.c')
-rw-r--r--src/resource/lua-resource.c1292
1 files changed, 1292 insertions, 0 deletions
diff --git a/src/resource/lua-resource.c b/src/resource/lua-resource.c
new file mode 100644
index 0000000..928c362
--- /dev/null
+++ b/src/resource/lua-resource.c
@@ -0,0 +1,1292 @@
+/*
+ * Copyright (c) 2013, 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 <stdbool.h>
+#include <errno.h>
+
+#include <murphy/common.h>
+#include <murphy/common/debug.h>
+#include <murphy/common/log.h>
+#include <murphy/common/mm.h>
+#include <murphy/common/mainloop.h>
+#include <murphy/core/lua-utils/object.h>
+#include <murphy/core/lua-utils/funcbridge.h>
+#include <murphy/core/lua-bindings/murphy.h>
+
+#include <murphy/resource/client-api.h>
+
+#define MAX_ATTRS 128
+
+/*
+ * Bindings to the resource library
+ */
+
+#define ATTRIBUTE_LUA_CLASS MRP_LUA_CLASS(attribute, lua)
+#define RESOURCE_LUA_CLASS MRP_LUA_CLASS(resource, lua)
+#define RESOURCE_SET_LUA_CLASS MRP_LUA_CLASS(resource_set, lua)
+
+typedef struct resource_lua_s resource_lua_t;
+typedef struct resource_set_lua_s resource_set_lua_t;
+typedef struct attribute_lua_s attribute_lua_t;
+
+struct attribute_lua_s {
+ lua_State *L; /* Lua execution context */
+
+ resource_set_lua_t *resource_set;
+
+ int initialized;
+ resource_lua_t *parent;
+};
+
+struct resource_lua_s {
+ lua_State *L; /* Lua execution context */
+
+ bool available; /* status */
+ bool acquired; /* status*/
+ bool shared; /* bookkeeping */
+ bool mandatory; /* bookkeeping */
+ char *resource_name; /* bookkeeping */
+
+ resource_set_lua_t *parent; /* resource set the resource belongs to */
+
+ int attributes; /* for lua bindings */
+ attribute_lua_t *real_attributes; /* real attributes */
+};
+
+struct resource_set_lua_s {
+ lua_State *L; /* Lua execution context */
+
+ mrp_resource_set_t *resource_set; /* associated murphy resource set */
+
+ int id; /* resource set internal id */
+ int callback; /* callback */
+ bool available; /* status */
+ bool acquired; /* status */
+ bool autorelease; /* input */
+ bool dont_wait; /* input */
+ char *zone; /* input */
+ char *application_class; /* input */
+ int32_t priority; /* input */
+
+ bool committed; /* resource set is locked and cannot be edited anymore */
+ bool initialized; /* resource set was returned to the Lua user */
+
+ mrp_htbl_t *resources;
+};
+
+static mrp_resource_client_t *client = NULL;
+uint32_t n_sets = 0;
+
+/* resource set */
+
+static int resource_set_lua_create(lua_State *L);
+
+static int resource_set_get_resources(void *data, lua_State *L, int member,
+ mrp_lua_value_t *v);
+static int resource_set_get_id(void *data, lua_State *L, int member,
+ mrp_lua_value_t *v);
+static int resource_set_add_resource(lua_State *L);
+static int resource_set_acquire(lua_State *L);
+static int resource_set_release(lua_State *L);
+
+static void resource_set_lua_changed(void *data, lua_State *L, int member);
+static void resource_set_lua_destroy(void *data);
+static int resource_set_lua_stringify(lua_State *L);
+
+#define RS_OFFS(m) MRP_OFFSET(resource_set_lua_t, m)
+#define RS_RDONLY MRP_LUA_CLASS_READONLY
+#define RS_NOTIFY MRP_LUA_CLASS_NOTIFY
+#define RS_NOFLAGS MRP_LUA_CLASS_NOFLAGS
+#define RS_RAWGETTER MRP_LUA_CLASS_RAWGETTER
+
+MRP_LUA_METHOD_LIST_TABLE(resource_set_lua_methods,
+ MRP_LUA_METHOD_CONSTRUCTOR(resource_set_lua_create)
+ MRP_LUA_METHOD(addResource, resource_set_add_resource)
+ MRP_LUA_METHOD(acquire, resource_set_acquire)
+ MRP_LUA_METHOD(release, resource_set_release));
+
+MRP_LUA_METHOD_LIST_TABLE(resource_set_lua_overrides,
+ MRP_LUA_OVERRIDE_CALL (resource_set_lua_create)
+ MRP_LUA_OVERRIDE_STRINGIFY(resource_set_lua_stringify));
+
+MRP_LUA_MEMBER_LIST_TABLE(resource_set_lua_members,
+ MRP_LUA_CLASS_INTEGER("id", RS_OFFS(id), NULL, resource_set_get_id, RS_RDONLY)
+ MRP_LUA_CLASS_STRING("application_class", RS_OFFS(application_class), NULL, NULL, RS_RDONLY)
+ MRP_LUA_CLASS_STRING("zone", RS_OFFS(zone), NULL, NULL, RS_RDONLY)
+ MRP_LUA_CLASS_ANY("resources", RS_OFFS(resources), NULL, resource_set_get_resources, RS_RDONLY | RS_RAWGETTER)
+ MRP_LUA_CLASS_BOOLEAN("dont_wait", RS_OFFS(dont_wait), NULL, NULL, RS_RDONLY)
+ MRP_LUA_CLASS_BOOLEAN("autorelease", RS_OFFS(autorelease), NULL, NULL, RS_RDONLY)
+ MRP_LUA_CLASS_BOOLEAN("available", RS_OFFS(available), NULL, NULL, RS_RDONLY)
+ MRP_LUA_CLASS_BOOLEAN("acquired", RS_OFFS(acquired), NULL, NULL, RS_RDONLY)
+ MRP_LUA_CLASS_INTEGER("priority", RS_OFFS(priority), NULL, NULL, RS_RDONLY)
+ MRP_LUA_CLASS_LFUNC("callback", RS_OFFS(callback), NULL, NULL, RS_NOTIFY));
+
+/* be careful! needs to be in the same order as the member list table */
+typedef enum {
+ RESOURCE_SET_MEMBER_ID,
+ RESOURCE_SET_MEMBER_APPLICATION_CLASS,
+ RESOURCE_SET_MEMBER_ZONE,
+ RESOURCE_SET_MEMBER_RESOURCES,
+ RESOURCE_SET_MEMBER_DONT_WAIT,
+ RESOURCE_SET_MEMBER_AUTORELEASE,
+ RESOURCE_SET_MEMBER_AVAILABLE,
+ RESOURCE_SET_MEMBER_ACQUIRED,
+ RESOURCE_SET_MEMBER_PRIORITY,
+ RESOURCE_SET_MEMBER_CALLBACK,
+} resource_set_member_t;
+
+MRP_LUA_DEFINE_CLASS(resource_set, lua, resource_set_lua_t, resource_set_lua_destroy,
+ resource_set_lua_methods, resource_set_lua_overrides,
+ resource_set_lua_members, NULL, resource_set_lua_changed, NULL, NULL,
+ MRP_LUA_CLASS_EXTENSIBLE | MRP_LUA_CLASS_DYNAMIC);
+
+/* resource */
+
+static int resource_lua_create(lua_State *L);
+static void resource_lua_destroy(void *data);
+static int resource_lua_stringify(lua_State *L);
+static void resource_lua_changed(void *data, lua_State *L, int member);
+
+/* get the whole attribute table */
+static int resource_get_attributes(void *data, lua_State *L, int member, mrp_lua_value_t *v);
+static int resource_set_attributes(void *data, lua_State *L, int member, mrp_lua_value_t *v);
+
+#define R_OFFS(m) MRP_OFFSET(resource_lua_t, m)
+#define R_RDONLY MRP_LUA_CLASS_READONLY
+#define R_NOTIFY MRP_LUA_CLASS_NOTIFY
+#define R_NOFLAGS MRP_LUA_CLASS_NOFLAGS
+#define R_RAWGETTER MRP_LUA_CLASS_RAWGETTER
+#define R_RAWSETTER MRP_LUA_CLASS_RAWSETTER
+
+MRP_LUA_METHOD_LIST_TABLE(resource_lua_methods,
+ MRP_LUA_METHOD_CONSTRUCTOR(resource_lua_create));
+
+MRP_LUA_METHOD_LIST_TABLE(resource_lua_overrides,
+ MRP_LUA_OVERRIDE_CALL (resource_lua_create)
+ MRP_LUA_OVERRIDE_STRINGIFY(resource_lua_stringify));
+
+MRP_LUA_MEMBER_LIST_TABLE(resource_lua_members,
+ MRP_LUA_CLASS_ANY("attributes", R_OFFS(attributes), resource_set_attributes, resource_get_attributes, R_RAWGETTER | R_RAWSETTER)
+ MRP_LUA_CLASS_STRING("resource_name", R_OFFS(resource_name), NULL, NULL, R_RDONLY)
+ MRP_LUA_CLASS_BOOLEAN("available", R_OFFS(available), NULL, NULL, R_RDONLY)
+ MRP_LUA_CLASS_BOOLEAN("acquired", R_OFFS(acquired), NULL, NULL, R_RDONLY)
+ MRP_LUA_CLASS_BOOLEAN("shared", R_OFFS(shared), NULL, NULL, R_RDONLY)
+ MRP_LUA_CLASS_BOOLEAN("mandatory", R_OFFS(mandatory), NULL, NULL, R_RDONLY));
+
+/* be careful! needs to be in the same order as the member list table */
+typedef enum {
+ RESOURCE_MEMBER_ATTRIBUTES,
+ RESOURCE_MEMBER_RESOURCE_NAME,
+ RESOURCE_MEMBER_AVAILABLE,
+ RESOURCE_MEMBER_ACQUIRED,
+ RESOURCE_MEMBER_SHARED,
+ RESOURCE_MEMBER_MANDATORY,
+} resource_member_t;
+
+MRP_LUA_DEFINE_CLASS(resource, lua, resource_lua_t, resource_lua_destroy,
+ resource_lua_methods, resource_lua_overrides,
+ resource_lua_members, NULL, resource_lua_changed, NULL, NULL,
+ MRP_LUA_CLASS_NOFLAGS);
+
+
+/* attribute table */
+
+/* The problem is that attribute table is a member of resource, meaning that
+ we will get events when the full attribute table is changed but won't get
+ any when a unique element of the attribute table is accessed. The solution
+ is to have the attributes handled as an object, whose constructor initializes
+ the attributes from the resource library. Any access to an attribute will
+ be seen as an access to a member and intercepted with "changed". */
+
+static int attribute_lua_create(lua_State *L);
+static void attribute_lua_destroy(void *data);
+static int attribute_lua_stringify(lua_State *L);
+static void attribute_lua_changed(void *data, lua_State *L, int member);
+static int attribute_lua_getfield(lua_State *L);
+static int attribute_lua_setfield(lua_State *L);
+
+#define A_OFFS(m) MRP_OFFSET(attribute_lua_t, m)
+#define A_RDONLY MRP_LUA_CLASS_READONLY
+#define A_NOTIFY MRP_LUA_CLASS_NOTIFY
+#define A_NOFLAGS MRP_LUA_CLASS_NOFLAGS
+#define A_RAWGETTER MRP_LUA_CLASS_RAWGETTER
+#define A_RAWSETTER MRP_LUA_CLASS_RAWSETTER
+
+MRP_LUA_METHOD_LIST_TABLE(attribute_lua_methods,
+ MRP_LUA_METHOD_CONSTRUCTOR(attribute_lua_create));
+
+MRP_LUA_METHOD_LIST_TABLE(attribute_lua_overrides,
+ MRP_LUA_OVERRIDE_CALL (attribute_lua_create)
+ MRP_LUA_OVERRIDE_STRINGIFY(attribute_lua_stringify)
+ MRP_LUA_OVERRIDE_GETFIELD (attribute_lua_getfield)
+ MRP_LUA_OVERRIDE_SETFIELD (attribute_lua_setfield));
+
+/* "initialized" is a placeholder */
+
+MRP_LUA_MEMBER_LIST_TABLE(attribute_lua_members,
+ MRP_LUA_CLASS_BOOLEAN("initialized", A_OFFS(initialized), NULL, NULL, A_RDONLY));
+
+/* be careful! needs to be in the same order as the member list table */
+typedef enum {
+ ATTRIBUTE_MEMBER_INITIALIZED,
+} attribute_member_t;
+
+MRP_LUA_DEFINE_CLASS(attribute, lua, attribute_lua_t, attribute_lua_destroy,
+ attribute_lua_methods, attribute_lua_overrides,
+ attribute_lua_members, NULL, attribute_lua_changed, NULL, NULL,
+ MRP_LUA_CLASS_NOFLAGS);
+
+/* resource set */
+
+static inline resource_set_lua_t *resource_set_lua_check(lua_State *L, int idx)
+{
+ return (resource_set_lua_t *) mrp_lua_check_object(L, RESOURCE_SET_LUA_CLASS, idx);
+}
+
+static int resource_set_add_resource(lua_State *L)
+{
+ int narg;
+ resource_set_lua_t *rset;
+ resource_lua_t *resource;
+ const char *resource_name;
+ bool shared = FALSE;
+ bool mandatory = TRUE;
+ mrp_attr_t attribute_list[MAX_ATTRS], *attrs;
+
+ mrp_debug("> add_resource");
+
+ narg = lua_gettop(L);
+
+ if (narg != 2)
+ return luaL_error(L, "expecting one argument");
+
+ rset = resource_set_lua_check(L, 1);
+
+ if (!rset)
+ goto error;
+
+ /* the argument should be a table with at least "resource_name" index */
+
+ if (!lua_istable(L, -1))
+ return luaL_error(L, "argument error -- not a table");
+
+ lua_pushstring(L, "resource_name");
+ lua_gettable(L, -2);
+
+ if (!lua_isstring(L, -1))
+ return luaL_error(L, "'resource_name' is a mandatory field");
+
+ resource_name = lua_tostring(L, -1);
+ lua_pop(L, 1);
+
+ lua_pushstring(L, "mandatory");
+ lua_gettable(L, -2);
+
+ if (lua_isboolean(L, -1)) {
+ mandatory = lua_toboolean(L, -1);
+ }
+ lua_pop(L, 1);
+
+ lua_pushstring(L, "shared");
+ lua_gettable(L, -2);
+
+ if (lua_isboolean(L, -1)) {
+ shared = lua_toboolean(L, -1);
+ }
+ lua_pop(L, 1);
+
+ /* create resource object and add it to the resource table in the resource
+ * set object */
+
+ resource = (resource_lua_t *) mrp_lua_create_object(L, RESOURCE_LUA_CLASS,
+ NULL, 0);
+
+ if (!resource)
+ goto error;
+
+ /* mrp_lua_object_ref_value(resource, L, 0); */
+
+ resource->mandatory = mandatory;
+ resource->shared = shared;
+ resource->acquired = FALSE;
+ resource->available = FALSE;
+ resource->resource_name = mrp_strdup(resource_name);
+
+ if (!resource->resource_name)
+ goto error;
+
+ resource->parent = rset;
+ resource->L = L;
+
+ resource->real_attributes = (attribute_lua_t *) mrp_lua_create_object(L,
+ ATTRIBUTE_LUA_CLASS, NULL, 0);
+
+ if (!resource->real_attributes)
+ goto error;
+
+ /* mrp_lua_object_ref_value(resource->real_attributes, L, 0); */
+
+ resource->real_attributes->L = L;
+ resource->real_attributes->parent = resource;
+ resource->real_attributes->resource_set = rset;
+ resource->real_attributes->initialized = TRUE;
+
+ attrs = mrp_resource_set_read_all_attributes(rset->resource_set,
+ resource->resource_name, MAX_ATTRS-1, attribute_list);
+
+ if (mrp_resource_set_add_resource(rset->resource_set,
+ resource->resource_name, shared, attrs, mandatory) < 0)
+ goto error;
+
+ /* add to resource map */
+
+ mrp_debug("inserted resource %s to %p", resource->resource_name, rset);
+ mrp_htbl_insert(rset->resources, resource->resource_name, resource);
+
+ return 0;
+
+error:
+ /* TODO: clean up the already allocated objects */
+
+ return luaL_error(L, "internal resource library error");
+}
+
+static int resource_set_acquire(lua_State *L)
+{
+ resource_set_lua_t *rset;
+
+ mrp_debug("acquire");
+
+ rset = resource_set_lua_check(L, 1);
+
+ if (!rset)
+ return luaL_error(L, "internal error");
+
+ if (!rset->committed) {
+
+ /* Application backend requires us to "commit" the resource set before
+ * we can use the resource set. It can be done only after all resources
+ * have been added to the resource set and all the attributes
+ * configured. */
+
+ if (mrp_application_class_add_resource_set(rset->application_class,
+ rset->zone, rset->resource_set, 0) < 0)
+ return luaL_error(L, "failed to commit the resource set");
+
+ rset->committed = TRUE;
+ }
+
+ mrp_resource_set_acquire(rset->resource_set, 0);
+
+ return 0;
+}
+
+static int resource_set_release(lua_State *L)
+{
+ resource_set_lua_t *rset;
+
+ mrp_debug("> release");
+
+ rset = resource_set_lua_check(L, 1);
+
+ if (!rset)
+ return luaL_error(L, "internal error");
+
+ if (!rset->committed) {
+
+ /* Committing the resource set here means that the resource set stays
+ * in released state but already receives events. */
+
+ if (mrp_application_class_add_resource_set(rset->application_class,
+ rset->zone, rset->resource_set, 0) < 0)
+ return luaL_error(L, "failed to commit the resource set");
+
+ rset->committed = TRUE;
+ }
+
+ mrp_resource_set_release(rset->resource_set, 0);
+
+ return 0;
+}
+
+
+void event_cb(uint32_t request_id, mrp_resource_set_t *resource_set, void *user_data)
+{
+ resource_set_lua_t *rset = (resource_set_lua_t *) user_data;
+ mrp_resource_mask_t grant, advice;
+ int top;
+
+ MRP_UNUSED(request_id);
+ MRP_UNUSED(resource_set);
+
+ mrp_debug("> event_cb");
+
+ top = lua_gettop(rset->L);
+
+ grant = mrp_get_resource_set_grant(rset->resource_set);
+ advice = mrp_get_resource_set_advice(rset->resource_set);
+
+ /* update resource set */
+ rset->acquired = !!grant;
+ rset->available = !!advice;
+
+ if (mrp_lua_object_deref_value(rset, rset->L, rset->callback, false)) {
+ mrp_lua_push_object(rset->L, rset);
+
+ if (lua_pcall(rset->L, 1, 0, 0) != 0)
+ mrp_log_error("failed to invoke Lua resource set callback: %s",
+ lua_tostring(rset->L, -1));
+ }
+
+ lua_settop(rset->L, top);
+}
+
+static void htbl_free_resource(void *key, void *object)
+{
+ resource_lua_t *res = (resource_lua_t *) object;
+ MRP_UNUSED(key);
+
+ mrp_lua_destroy_object(res->L, NULL, 0, res);
+#if 0
+
+ mrp_debug("lua-resource: htbl_free_resource %p, res: '%s'", res,
+ res->resource_name);
+
+ MRP_UNUSED(key);
+#endif
+}
+
+static int resource_set_lua_create(lua_State *L)
+{
+ char e[128] = "";
+ resource_set_lua_t *rset;
+ int narg;
+ mrp_htbl_config_t conf;
+
+ mrp_debug("create");
+
+ narg = lua_gettop(L);
+
+ rset = (resource_set_lua_t *) mrp_lua_create_object(L,
+ RESOURCE_SET_LUA_CLASS, NULL, 0);
+
+ if (!rset)
+ return luaL_error(L, "could not create Lua object");
+
+ rset->L = L;
+
+ /* user can affect these values */
+ rset->zone = mrp_strdup("default");
+ rset->application_class = NULL;
+ rset->autorelease = FALSE;
+ rset->dont_wait = FALSE;
+ rset->priority = 0;
+ rset->committed = FALSE;
+ rset->initialized = FALSE;
+
+ switch (narg) {
+ case 2:
+ /* argument table */
+ if (mrp_lua_init_members(rset, L, -2, e, sizeof(e)) != 1)
+ return luaL_error(L, "failed to initialize resource members (%s)",
+ e);
+ break;
+ default:
+ return luaL_error(L, "expecting a constructor argument, "
+ "got %d", narg);
+ }
+
+ if (rset->application_class == NULL)
+ return luaL_error(L, "application_class is a mandatory parameter");
+
+ if (rset->priority < 0)
+ rset->priority = 0;
+
+ /* initial state, these cannot be set by user */
+ rset->available = FALSE;
+ rset->acquired = FALSE;
+
+ /* initialize resource map */
+ conf.nbucket = 0;
+ conf.nentry = 10;
+ conf.comp = mrp_string_comp;
+ conf.hash = mrp_string_hash;
+ conf.free = htbl_free_resource;
+
+ rset->resources = mrp_htbl_create(&conf);
+ if (!rset->resources)
+ goto error;
+
+ /* do the actual resource work */
+
+ if (!client) {
+ /* create the resource client */
+
+ client = mrp_resource_client_create("lua", NULL);
+
+ if (!client)
+ goto error;
+ }
+
+ rset->resource_set = mrp_resource_set_create(client, rset->autorelease,
+ rset->dont_wait, rset->priority, event_cb, rset);
+
+ if (rset->resource_set)
+ n_sets++;
+ else
+ goto error;
+
+ rset->initialized = TRUE;
+
+ mrp_lua_push_object(L, rset);
+
+ return 1;
+
+error:
+ return luaL_error(L, "internal resource library error");
+}
+
+static int resource_set_get_id(void *data, lua_State *L, int member,
+ mrp_lua_value_t *v)
+{
+ resource_set_lua_t *rset;
+ MRP_UNUSED(L);
+ MRP_UNUSED(member);
+
+ mrp_debug("> resource_set_get_id");
+
+ if (!v)
+ return 0;
+
+ rset = (resource_set_lua_t *) data;
+
+ v->s32 = mrp_get_resource_set_id(rset->resource_set);
+
+ return 1;
+}
+
+static int resource_set_get_resources(void *data, lua_State *L, int member, mrp_lua_value_t *v)
+{
+ resource_set_lua_t *rset;
+ void *iter = NULL;
+ mrp_resource_t *resource;
+ mrp_resource_mask_t grant, advice;
+
+ MRP_UNUSED(member);
+ MRP_UNUSED(v);
+
+ mrp_debug("> resource_set_get_resources");
+
+ rset = (resource_set_lua_t *) data;
+
+ if (!rset)
+ return luaL_error(L, "internal error");
+
+ grant = mrp_get_resource_set_grant(rset->resource_set);
+ advice = mrp_get_resource_set_advice(rset->resource_set);
+
+ lua_newtable(L);
+
+ /* push all resource objects to a table and return it */
+
+ while ((resource = mrp_resource_set_iterate_resources(rset->resource_set, &iter))) {
+ const char *name = mrp_resource_get_name(resource);
+ mrp_resource_mask_t mask = mrp_resource_get_mask(resource);
+
+ /* fetch and update the resource object */
+
+ resource_lua_t *res =
+ (resource_lua_t *) mrp_htbl_lookup(rset->resources,
+ (void *) name);
+
+ if (!res) {
+ mrp_log_error("resources out of sync: %s not found", name);
+ continue;
+ }
+
+ /* mrp_lua_object_ref_value(res, L, 0); */
+
+ res->acquired = !!(mask & grant);
+ res->available = !!(mask & advice);
+
+ /* TODO: update attributes */
+
+ /* push the resource to the table */
+ lua_pushstring(L, res->resource_name);
+ mrp_lua_push_object(L, res);
+ lua_settable(L, -3);
+ }
+
+ return 1;
+}
+
+static int resource_set_lua_stringify(lua_State *L)
+{
+ resource_set_lua_t *rset;
+
+ mrp_debug("> stringify");
+
+ rset = resource_set_lua_check(L, 1);
+
+ if (!rset) {
+ lua_pushstring(L, "invalid resource set");
+ return 1;
+ }
+
+ lua_pushfstring(L, "resource set '%s', acquired: %s, available: %s",
+ rset->application_class,
+ rset->acquired ? "yes" : "no",
+ rset->available ? "yes" : "no");
+
+ return 1;
+}
+
+static void resource_set_lua_destroy(void *data)
+{
+ resource_set_lua_t *rset = (resource_set_lua_t *) data;
+
+ mrp_debug("lua destructor for rset %p", rset);
+
+ /* remove resources from the resource set -- they are finally cleaned from
+ * their own lua destructors */
+
+ if (rset->resource_set)
+ mrp_resource_set_destroy(rset->resource_set);
+
+ if (rset->resources) {
+ mrp_debug("deleting htbl at %p", rset->resources);
+ mrp_htbl_destroy(rset->resources, TRUE);
+ rset->resources = NULL;
+ }
+
+ mrp_free(rset->zone);
+ mrp_free(rset->application_class);
+
+ if (rset->initialized) {
+ n_sets--;
+
+ if (n_sets == 0) {
+ mrp_resource_client_destroy(client);
+ client = NULL;
+ }
+ }
+
+ return;
+}
+
+static void resource_set_lua_changed(void *data, lua_State *L, int member)
+{
+ resource_set_lua_t *rset = (resource_set_lua_t *) data;
+
+ MRP_UNUSED(L);
+ MRP_UNUSED(member);
+
+ mrp_debug("> changed");
+
+ switch (member) {
+ case RESOURCE_SET_MEMBER_CALLBACK:
+ /* no special handling needed */
+ break;
+ default:
+ /* trying to change readonly properties, should trigger an error */
+ mrp_log_error("Trying to change a readonly property for resource set %s",
+ rset->application_class);
+ break;
+ }
+
+ return;
+}
+
+/* resource */
+
+static inline resource_lua_t *resource_lua_check(lua_State *L, int idx)
+{
+ return (resource_lua_t *) mrp_lua_check_object(L, RESOURCE_LUA_CLASS, idx);
+}
+
+static int resource_lua_create(lua_State *L)
+{
+ mrp_debug("> resource_lua_create");
+
+ return luaL_error(L, "Resource objects are created with ResourceSet:addResource()");
+}
+
+static int resource_lua_stringify(lua_State *L)
+{
+ resource_lua_t *res;
+
+ mrp_debug("> stringify");
+
+ res = resource_lua_check(L, 1);
+
+ if (!res) {
+ lua_pushstring(L, "invalid resource set");
+ return 1;
+ }
+
+ lua_pushfstring(L, "resource '%s', acquired: %s, available: %s, mandatory: %s, shared: %s",
+ res->resource_name,
+ res->acquired ? "yes" : "no",
+ res->available ? "yes" : "no",
+ res->mandatory ? "yes" : "no",
+ res->shared ? "yes" : "no");
+
+ return 1;
+}
+
+static void resource_lua_destroy(void *data)
+{
+ resource_lua_t *res = (resource_lua_t *) data;
+
+ mrp_debug("lua destructor for resource %p (%s)", res, res->resource_name);
+
+ mrp_free(res->resource_name);
+
+ /* TODO: unref res->real_attributes ? */
+
+ mrp_lua_destroy_object(res->L, NULL, 0, res->real_attributes);
+
+ return;
+}
+
+static void resource_lua_changed(void *data, lua_State *L, int member)
+{
+ MRP_UNUSED(data);
+ MRP_UNUSED(L);
+ MRP_UNUSED(member);
+
+ mrp_debug("> resource_changed");
+}
+
+#if 0
+static int resource_get_attributes(void *data, lua_State *L, int member, mrp_lua_value_t *v)
+{
+ resource_lua_t *res = (resource_lua_t *) data;
+ resource_set_lua_t *rset = res->parent;
+ mrp_attr_t attribute_list[MAX_ATTRS], *attrs;
+
+ mrp_debug("> resource_get_attributes");
+
+ lua_newtable(L);
+
+ attrs = mrp_resource_set_read_all_attributes(rset->resource_set,
+ res->resource_name,
+ MAX_ATTRS-1,
+ attribute_list);
+
+ while (attrs->name != NULL) {
+
+ switch (attrs->type) {
+ case mqi_string:
+ lua_pushstring(L, attrs->name);
+ lua_pushstring(L, attrs->value.string);
+ lua_settable(L, -3);
+ break;
+ case mqi_integer:
+ lua_pushstring(L, attrs->name);
+ lua_pushinteger(L, attrs->value.integer);
+ lua_settable(L, -3);
+ break;
+ case mqi_unsignd:
+ if (attrs->value.unsignd > INT_MAX) {
+ /* too big! */
+ mrp_log_error("Sorry, we don't support big unsigned values right now");
+ }
+ else {
+ lua_pushstring(L, attrs->name);
+ lua_pushinteger(L, attrs->value.unsignd);
+ lua_settable(L, -3);
+ }
+ break;
+ case mqi_floating:
+ lua_pushstring(L, attrs->name);
+ lua_pushnumber(L, attrs->value.floating);
+ lua_settable(L, -3);
+ break;
+ default:
+ mrp_log_error("Unhandled attribute type");
+ break;
+ }
+
+ attrs++;
+ }
+
+ return 1;
+}
+#else
+static int resource_get_attributes(void *data, lua_State *L, int member, mrp_lua_value_t *v)
+{
+ resource_lua_t *res = (resource_lua_t *) data;
+
+ MRP_UNUSED(member);
+ MRP_UNUSED(v);
+
+ mrp_debug("> resource_get_attributes");
+
+ mrp_lua_push_object(L, res->real_attributes);
+
+ return 1;
+}
+#endif
+
+static int resource_set_attributes(void *data, lua_State *L, int member, mrp_lua_value_t *v)
+{
+ resource_lua_t *res = (resource_lua_t *) data;
+ resource_set_lua_t *rset = res->parent;
+ mrp_attr_t attribute_list[MAX_ATTRS], *attrs, *orig;
+
+ MRP_UNUSED(member);
+ MRP_UNUSED(v);
+
+ mrp_debug("> resource_set_attributes");
+
+ if (!lua_istable(L, -1))
+ return luaL_error(L, "argument error -- not a table");
+
+ mrp_resource_set_read_all_attributes(rset->resource_set,
+ res->resource_name, MAX_ATTRS-1, attribute_list);
+
+ attrs = orig = attribute_list;
+
+ while (attrs->name != NULL) {
+ /* get the attribute from the lua table by name */
+
+ lua_pushstring(L, attrs->name);
+ lua_gettable(L, -2);
+
+ /* update the attribute */
+
+ switch (attrs->type) {
+ case mqi_string:
+ if (lua_isstring(L, -1)) {
+ attrs->value.string = lua_tostring(L, -1);
+ mrp_debug("updated attr '%s' to '%s'", attrs->name, attrs->value.string);
+ }
+ break;
+ case mqi_integer:
+ if (lua_isnumber(L, -1)) {
+ attrs->value.integer = lua_tointeger(L, -1);
+ mrp_debug("updated attr '%s' to '%i'", attrs->name, attrs->value.integer);
+ }
+ break;
+ case mqi_unsignd:
+ if (lua_isnumber(L, -1)) {
+ int val = lua_tointeger(L, -1);
+ if (val >= 0) {
+ attrs->value.unsignd = val;
+ mrp_debug("updated attr '%s' to '%u'", attrs->name, attrs->value.unsignd);
+ }
+ }
+ break;
+ case mqi_floating:
+ if (lua_isnumber(L, -1)) {
+ attrs->value.floating = lua_tonumber(L, -1);
+ mrp_debug("updated attr '%s' to '%f'", attrs->name, attrs->value.floating);
+ }
+ break;
+ default:
+ break;
+ }
+
+ lua_pop(L, 1);
+ attrs++;
+ }
+
+ /* write the attributes back */
+ mrp_resource_set_write_attributes(rset->resource_set, res->resource_name, orig);
+
+ return 1;
+}
+
+static inline attribute_lua_t *attribute_lua_check(lua_State *L, int idx)
+{
+ return (attribute_lua_t *) mrp_lua_check_object(L, ATTRIBUTE_LUA_CLASS, idx);
+}
+
+static int attribute_lua_create(lua_State *L)
+{
+ mrp_debug("> attribute_create");
+
+ return luaL_error(L, "Attribute objects are created with ResourceSet:addResource()");
+}
+
+static void attribute_lua_destroy(void *data)
+{
+ attribute_lua_t *attribute = (attribute_lua_t *) data;
+
+ mrp_debug("lua destructor for attribute table %p", attribute);
+
+ return;
+}
+
+static int attribute_lua_stringify(lua_State *L)
+{
+ attribute_lua_t *attribute = attribute_lua_check(L, 1);
+ resource_lua_t *res = attribute->parent;
+ resource_set_lua_t *rset = res->parent;
+ mrp_attr_t attribute_list[MAX_ATTRS], *attrs;
+
+ int available = 4095;
+ char buf[available+1], *p;
+ char numbuf[16];
+ int vallen;
+
+ mrp_debug("> attribute_stringify");
+
+ memset(buf, 0, sizeof(buf));
+ p = buf;
+
+ mrp_resource_set_read_all_attributes(rset->resource_set,
+ res->resource_name, MAX_ATTRS-1, attribute_list);
+
+ attrs = attribute_list;
+
+ while (attrs->name != NULL) {
+
+ int keylen = strlen(attrs->name);
+
+ /* we need space for 2 + null */
+ available -= keylen + 3;
+
+ if (available < 0)
+ goto outofspace;
+
+ strncpy(p, attrs->name, keylen);
+ p += keylen;
+
+ /*
+ * we copy ": \0" and then proceed to only
+ * move the pointer by two, thus we can
+ * add one to the amount of available
+ * space.
+ */
+ strncpy(p, ": ", 3);
+ p += 2;
+ available += 1;
+
+ switch (attrs->type) {
+ case mqi_string:
+ vallen = strlen(attrs->value.string);
+ available -= vallen + 1;
+ if (available < 0)
+ goto outofspace;
+ strncpy(p, attrs->value.string, vallen);
+ p += vallen;
+ *p = '\n';
+ p += 1;
+ break;
+ case mqi_integer:
+ snprintf(numbuf, sizeof(numbuf), "%d",
+ (int) attrs->value.integer);
+ vallen = strlen(numbuf);
+ available -= vallen + 1;
+ if (available < 0)
+ goto outofspace;
+ strncpy(p, numbuf, vallen);
+ p += vallen;
+ *p = '\n';
+ p += 1;
+ break;
+ case mqi_unsignd:
+ snprintf(numbuf, sizeof(numbuf), "%u", attrs->value.unsignd);
+ vallen = strlen(numbuf);
+ available -= vallen + 1;
+ if (available < 0)
+ goto outofspace;
+ strncpy(p, numbuf, vallen);
+ p += vallen;
+ *p = '\n';
+ p += 1;
+ break;
+ case mqi_floating:
+ snprintf(numbuf, sizeof(numbuf), "%f", attrs->value.floating);
+ vallen = strlen(numbuf);
+ available -= vallen + 1;
+ if (available < 0)
+ goto outofspace;
+ strncpy(p, numbuf, vallen);
+ p += vallen;
+ *p = '\n';
+ p += 1;
+ break;
+ default:
+ break;
+ }
+
+ attrs++;
+ }
+ lua_pushstring(L, buf);
+
+ return 1;
+
+outofspace:
+ return luaL_error(L, "out of string buffer space");
+}
+
+static void attribute_lua_changed(void *data, lua_State *L, int member)
+{
+ MRP_UNUSED(data);
+ MRP_UNUSED(L);
+ MRP_UNUSED(member);
+
+ mrp_debug("> attribute_changed");
+ return;
+}
+
+static int attribute_lua_getfield(lua_State *L)
+{
+ attribute_lua_t *attribute = attribute_lua_check(L, 1);
+ resource_lua_t *res = attribute->parent;
+ resource_set_lua_t *rset = res->parent;
+ mrp_attr_t attribute_list[MAX_ATTRS], *attrs;
+ const char *key;
+
+ mrp_debug("> attribute_lua_getfield");
+
+ /* attributes are indexed by string */
+
+ if (lua_type(L, 2) != LUA_TSTRING)
+ return luaL_error(L, "invalid attribute index type (needs to be string)");
+
+ key = lua_tostring(L, 2);
+
+ attrs = mrp_resource_set_read_all_attributes(rset->resource_set,
+ res->resource_name, MAX_ATTRS-1, attribute_list);
+
+ if (!attrs)
+ return luaL_error(L, "internal resource library error");
+
+ while (attrs->name != NULL) {
+
+ if (strcmp(attrs->name, key) == 0) {
+
+ switch (attrs->type) {
+ case mqi_string:
+ lua_pushstring(L, attrs->value.string);
+ return 1;
+ case mqi_integer:
+ lua_pushinteger(L, attrs->value.integer);
+ return 1;
+ case mqi_unsignd:
+ if (attrs->value.unsignd > INT_MAX) {
+ /* too big! */
+ mrp_log_error("Sorry, we don't support big unsigned values right now");
+ return luaL_error(L, "too big value in attribute");
+ }
+ else {
+ lua_pushinteger(L, attrs->value.unsignd);
+ }
+ return 1;
+ case mqi_floating:
+ lua_pushnumber(L, attrs->value.floating);
+ return 1;
+ default:
+ mrp_log_error("Unhandled attribute type");
+ return 1;
+ }
+ }
+
+ attrs++;
+ }
+
+ return luaL_error(L, "trying to get a non-existing attribute");
+}
+
+static int attribute_lua_setfield(lua_State *L)
+{
+ attribute_lua_t *attribute = attribute_lua_check(L, 1);
+ resource_lua_t *res = attribute->parent;
+ resource_set_lua_t *rset = res->parent;
+ mrp_attr_t attribute_list[MAX_ATTRS], *attrs, *orig;
+ const char *key;
+ int new_type;
+
+ mrp_debug("> attribute_lua_setfield");
+
+ /* attributes are indexed by string */
+
+ if (lua_type(L, 2) != LUA_TSTRING)
+ return luaL_error(L, "invalid attribute index type (needs to be string)");
+
+ key = lua_tostring(L, 2);
+ new_type = lua_type(L, 3);
+
+ attrs = mrp_resource_set_read_all_attributes(rset->resource_set,
+ res->resource_name, MAX_ATTRS-1, attribute_list);
+
+ if (!attrs)
+ return luaL_error(L, "internal resource library error");
+
+ orig = attrs;
+
+ while (attrs->name != NULL) {
+
+ if (strcmp(attrs->name, key) == 0) {
+
+ switch (attrs->type) {
+ case mqi_string:
+ if (new_type != LUA_TSTRING)
+ return luaL_error(L, "type mismatch");
+ attrs->value.string = lua_tostring(L, 3);
+ break;
+ case mqi_integer:
+ {
+ int32_t i;
+ double dbl;
+
+ if (new_type != LUA_TNUMBER)
+ return luaL_error(L, "type mismatch");
+
+ if ((i = lua_tointeger(L, 3)) == (dbl = lua_tonumber(L, 3)))
+ attrs->value.integer = i;
+ else
+ return luaL_error(L, "type mismatch");
+
+ break;
+ }
+ case mqi_unsignd:
+ {
+ int32_t i;
+ double dbl;
+
+ if (new_type != LUA_TNUMBER)
+ return luaL_error(L, "type mismatch");
+
+ if ((i = lua_tointeger(L, 3)) == (dbl = lua_tonumber(L, 3)) && i >= 0)
+ attrs->value.unsignd = i;
+ else
+ return luaL_error(L, "type mismatch");
+
+ break;
+ }
+ case mqi_floating:
+ {
+ if (new_type != LUA_TNUMBER)
+ return luaL_error(L, "type mismatch");
+ attrs->value.floating = lua_tonumber(L, 3);
+ break;
+ }
+ default:
+ return luaL_error(L, "unhandled attribute type");
+ }
+ break; /* while */
+ }
+
+ attrs++;
+ }
+
+ mrp_resource_set_write_attributes(rset->resource_set, res->resource_name, orig);
+
+ return 1;
+}
+
+#if 0
+MURPHY_REGISTER_LUA_BINDINGS(murphy, RESOURCE_LUA_CLASS,
+ { "Resource", resource_lua_create });
+
+MURPHY_REGISTER_LUA_BINDINGS(murphy, RESOURCE_SET_LUA_CLASS,
+ { "ResourceSet", resource_set_lua_create });
+
+MURPHY_REGISTER_LUA_BINDINGS(murphy, ATTRIBUTE_LUA_CLASS,
+ { "Attribute", attribute_lua_create });
+#else
+
+static void register_murphy_bindings(void) MRP_INIT;
+
+static void register_murphy_bindings(void) {
+ static struct luaL_Reg resource_methods[] = {
+ { "Resource", resource_lua_create },
+ { NULL, NULL }
+ };
+
+ static mrp_lua_bindings_t resource_bindings = {
+ .meta = "murphy",
+ .methods = resource_methods,
+ .classdef = &resource_lua_class_def,
+ };
+
+ static struct luaL_Reg resource_set_methods[] = {
+ { "ResourceSet", resource_set_lua_create },
+ { NULL, NULL }
+ };
+
+ static mrp_lua_bindings_t resource_set_bindings = {
+ .meta = "murphy",
+ .methods = resource_set_methods,
+ .classdef = &resource_set_lua_class_def,
+ };
+
+ static struct luaL_Reg attribute_methods[] = {
+ { "Attribute", attribute_lua_create },
+ { NULL, NULL }
+ };
+
+ static mrp_lua_bindings_t attribute_bindings = {
+ .meta = "murphy",
+ .methods = attribute_methods,
+ .classdef = &attribute_lua_class_def,
+ };
+
+ mrp_list_init(&attribute_bindings.hook);
+ mrp_lua_register_murphy_bindings(&attribute_bindings);
+
+ mrp_list_init(&resource_bindings.hook);
+ mrp_lua_register_murphy_bindings(&resource_bindings);
+
+ mrp_list_init(&resource_set_bindings.hook);
+ mrp_lua_register_murphy_bindings(&resource_set_bindings);
+}
+#endif
+
+
+/*
+
+resourcehandler = function (rset)
+ if rset.resources.screen.acquired == true then
+ print("got it")
+ else
+ print("didn't get it")
+ end
+end
+
+resourcehandler = function (rset) print("bar") end
+
+rset = m:ResourceSet ( { zone = "driver", callback = resourceHandler, application_class = "player" } )
+
+rset:addResource({ resource_name = "audio_playback", mandatory = true })
+
+rset.resources.audio_playback.attributes.pid = "500"
+
+rset:acquire()
+
+rset:release()
+
+*/