plugin_ivi_resource_manager_la_LIBADD = $(PLUGIN_IVI_RESOURCE_MANAGER_LIBS)
plugin_LTLIBRARIES += plugin-ivi-resource-manager.la
+
+#
+# GAM support:
+# - decision-tree library
+# - gam-resource-manager plugin
+# - pattern generator and decision-test
+#
+
+# decision-tree library
+if BUILD_RESOURCES
+DECISION_TREE_LIBRARY = libmurphy-decision-tree.la
+
+lib_LTLIBRARIES += $(DECISION_TREE_LIBRARY)
+
+libmurphy_decision_tree_ladir = \
+ $(includedir)/murphy/decision-tree
+
+libmurphy_decision_tree_la_HEADERS = \
+ plugins/gam-resource-manager/decision-tree.h \
+ plugins/gam-resource-manager/c5-decision-tree.h
+libmurphy_decision_tree_la_SOURCES = \
+ plugins/gam-resource-manager/decision-tree.c \
+ plugins/gam-resource-manager/c5-decision-tree.c
+libmurphy_decision_tree_la_CFLAGS = \
+ $(AM_CFLAGS)
+libmurphy_decision_tree_la_LIBADD = \
+ libmurphy-common.la
+
+libmurphy_decision_tree_la_DEPENDENCIES = linker-script.decision_tree \
+ $(filter %.la, $(libmurphy_decision_tree_la_LIBADD))
+
+# debug file:line-function mapping generation
+decision-tree-func-info.c: $(libmurphy_decision_tree_la_REGULAR_SOURCES)
+ $(QUIET_GEN)$(top_builddir)/build-aux/gen-debug-table -o $@ $^
+
+clean-func-infos::
+ -rm decision-tree-func-info.c
+
+# decision-tree linker script generation
+linker-script.decision_tree: $(libmurphy_decision_tree_la_HEADERS)
+ $(QUIET_GEN)$(top_builddir)/build-aux/gen-linker-script -q \
+ -c "$(libmurphy_decision_tree_la_CFLAGS)" -o $@ $^
+
+clean-linker-script::
+ -rm -f linker-script.decision_tree
+
+generate-linker-scripts: linker-script.decision_tree
+
+
+# gam-resource-manager plugin
+PLUGIN_GAM_RESOURCE_MANAGER_REGULAR_SOURCES = \
+ plugins/gam-resource-manager/plugin-gam-resource-manager.c \
+ plugins/gam-resource-manager/backend.c \
+ plugins/gam-resource-manager/source.c \
+ plugins/gam-resource-manager/sink.c \
+ plugins/gam-resource-manager/usecase.c
+PLUGIN_GAM_RESOURCE_MANAGER_SOURCES = \
+ $(PLUGIN_GAM_RESOURCE_MANAGER_REGULAR_SOURCES) \
+ plugin-gam-resource-manager-func-info.c
+PLUGIN_GAM_RESOURCE_MANAGER_CFLAGS = \
+ $(LUA_CFLAGS)
+
+PLUGIN_GAM_RESOURCE_MANAGER_LIBS = \
+ libmurphy-common.la \
+ libmurphy-decision-tree.la \
+ $(RESOURCE_LIBRARY) \
+ $(LUA_LIBS)
+
+plugin_gam_resource_manager_la_SOURCES = $(PLUGIN_GAM_RESOURCE_MANAGER_SOURCES)
+plugin_gam_resource_manager_la_CFLAGS = $(PLUGIN_GAM_RESOURCE_MANAGER_CFLAGS)\
+ $(MURPHY_CFLAGS) $(AM_CFLAGS) \
+ $(JSON_CFLAGS)
+plugin_gam_resource_manager_la_LDFLAGS = -module -avoid-version
+plugin_gam_resource_manager_la_LIBADD = $(PLUGIN_GAM_RESOURCE_MANAGER_LIBS)
+
+plugin_LTLIBRARIES += plugin-gam-resource-manager.la
+
+# debug file:line-function mapping generation
+plugin-gam-resource-manager-func-info.c: $(PLUGIN_GAM_RESOURCE_MANAGER_REGULAR_SOURCES)
+ $(QUIET_GEN)$(top_builddir)/build-aux/gen-debug-table -o $@ $^
+
+clean-func-infos::
+ -rm plugin-gam-resource-manager-func-info.c
+
+# pattern-generator
+bin_PROGRAMS += pattern-generator
+
+pattern_generator_SOURCES = \
+ plugins/gam-resource-manager/pattern-generator.c \
+ plugins/gam-resource-manager/decision-maker.c
+pattern_generator_CFLAGS = $(AM_CFLAGS)
+pattern_generator_LDADD = libmurphy-common.la
+
+# decision-test
+bin_PROGRAMS += decision-test
+
+decision_test_SOURCES = plugins/gam-resource-manager/decision-test.c
+decision_test_CFLAGS = $(AM_CFLAGS)
+decision_test_LDADD = \
+ libbreedline-murphy.la libbreedline.la \
+ libmurphy-common.la \
+ libmurphy-decision-tree.la
endif
-- load the IVI resource manager if it is available
load_if_exists('ivi-resource-manager')
+-- load the GAM resource manager if it is available
+load_if_exists('gam-resource-manager', {
+ config_dir = '/home/jko/Sources/protos/gam-poc/state-machine',
+ decision_names = 'gam-wrtApplication-4',
+ max_active = 4
+})
+
+
+
--
-- define application classes
--
--
-- define resource classes
--
-if not m:plugin_loaded('ivi-resource-manager') then
+if not m:plugin_loaded('ivi-resource-manager') and
+ not m:plugin_loaded('gam-resource-manager')
+then
resource.class {
name = "audio_playback",
shareable = true,
}
end
-resource.class {
- name = "audio_recording",
- shareable = false,
- attributes = {
- role = { mdb.string, "music", "rw" },
- pid = { mdb.string, "<unknown>", "rw" },
- policy = { mdb.string, "relaxed", "rw" }
- }
-}
+if not m:plugin_loaded('gam-resource-manager') then
+ resource.class {
+ name = "audio_recording",
+ shareable = false,
+ attributes = {
+ role = { mdb.string, "music", "rw" },
+ pid = { mdb.string, "<unknown>", "rw" },
+ policy = { mdb.string, "relaxed", "rw" }
+ }
+ }
+end
resource.class {
name = "video_playback",
--- /dev/null
+/*
+ * Copyright (c) 2014, 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 <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <murphy/common.h>
+
+#include <murphy-db/mqi.h>
+
+#include <murphy/resource/config-api.h>
+#include <murphy/resource/manager-api.h>
+#include <murphy/resource/client-api.h>
+
+#include "backend.h"
+#include "source.h"
+#include "sink.h"
+#include "usecase.h"
+
+#define ANY_ZONE (~((uint32_t)0))
+
+
+#define ATTRIBUTE(n,t,v) {n, MRP_RESOURCE_RW, mqi_##t, {.t=v}}
+#define ATTR_END {NULL, 0, 0, {.string=NULL}}
+
+
+typedef enum decision_value_e decision_value_t;
+typedef enum state_value_e state_value_t;
+typedef struct resource_s resource_t;
+typedef struct resource_type_s resource_type_t;
+typedef struct decision_s decision_t;
+typedef struct state_s state_t;
+
+enum decision_value_e {
+ STATE_ERROR = -1,
+
+ STATE_STOP = 0,
+ STATE_PAUSE,
+ STATE_PLAY,
+
+ STATE_MAX
+};
+
+enum state_value_e {
+ DECISION_ERROR = -1,
+
+ DECISION_TEARDOWN = 0,
+ DECISION_DISCONNECTED,
+ DECISION_CONNECTED,
+ DECISION_SUSPENDED,
+
+ DECISION_MAX
+};
+
+struct resource_type_s {
+ int id;
+ const char *name;
+ uint32_t resid;
+};
+
+struct mrp_resmgr_backend_s {
+ mrp_resmgr_t *resmgr;
+ resource_type_t types[MRP_RESMGR_RESOURCE_TYPE_MAX];
+ struct {
+ mrp_htbl_t *by_pointer;
+ mrp_htbl_t *by_connid;
+ } resources;
+};
+
+struct decision_s {
+ int32_t new;
+ int32_t current;
+};
+
+struct state_s {
+ int32_t new;
+ int32_t current;
+};
+
+struct mrp_resmgr_resource_s {
+ const char *name;
+ mrp_resmgr_backend_t *backend;
+ mrp_resource_t *res;
+ resource_type_t *type;
+ mrp_resmgr_source_t *source;
+ mrp_resmgr_sink_t *sink;
+ mrp_list_hook_t source_link;
+ uint32_t zoneid;
+ uint32_t connid;
+ uint32_t connno;
+ decision_t decision;
+ state_t state;
+};
+
+
+static void make_resource_definition(mrp_resmgr_backend_t *, int, const char*);
+static resource_type_t *find_resource_definition_by_id(mrp_resmgr_backend_t *,
+ int);
+
+static int hash_compare(const void *, const void *);
+static uint32_t ptr_hash_function(const void *);
+static uint32_t id_hash_function(const void *);
+
+//static const char *get_resource_appid(mrp_resource_t *);
+static int32_t get_resource_sourceid(mrp_resource_t *);
+static int32_t get_resource_sinkid(mrp_resource_t *);
+static int32_t get_resource_connid(mrp_resource_t *);
+static int32_t get_resource_connno(mrp_resource_t *);
+static int32_t get_resource_stamp(mrp_resource_t *);
+
+static bool set_resource_source_and_sink(mrp_resource_t *,
+ mrp_resmgr_source_t *,
+ mrp_resmgr_sink_t *);
+static bool set_resource_stamp(mrp_resource_t *, int32_t);
+static bool set_resource_decision(mrp_resource_t *, int32_t);
+
+
+static void resource_create(mrp_resmgr_backend_t *, mrp_application_class_t *,
+ mrp_zone_t *, mrp_resource_t *);
+static void resource_destroy(mrp_resmgr_backend_t *, mrp_zone_t *,
+ mrp_resource_t *);
+static bool resource_acquire(mrp_resmgr_backend_t *, mrp_zone_t *,
+ mrp_resource_t *);
+static bool resource_release(mrp_resmgr_backend_t *, mrp_zone_t *,
+ mrp_resource_t *);
+
+static bool resource_register_by_id(mrp_resmgr_backend_t *,
+ mrp_resmgr_resource_t *);
+static mrp_resmgr_resource_t *resource_lookup_by_pointer(mrp_resmgr_backend_t*,
+ mrp_resource_t *);
+
+static size_t resource_print_name(mrp_resmgr_source_t *,uint32_t,char *,size_t);
+
+
+static void make_decisions(mrp_resmgr_backend_t *);
+static void commit_decisions(mrp_resmgr_backend_t *);
+static size_t print_decision(mrp_resmgr_resource_t *, char *, size_t);
+static size_t print_commit(mrp_resmgr_resource_t *, char *, size_t);
+
+static void backend_notify(mrp_resource_event_t, mrp_zone_t *,
+ mrp_application_class_t *, mrp_resource_t *, void*);
+static void backend_init(mrp_zone_t *, void *);
+static bool backend_allocate(mrp_zone_t *, mrp_resource_t *, void *);
+static void backend_free(mrp_zone_t *, mrp_resource_t *, void *);
+static bool backend_advice(mrp_zone_t *, mrp_resource_t *, void *);
+static void backend_commit(mrp_zone_t *, void *);
+
+
+
+#define APPID_ATTRIDX 0
+#define ROLE_ATTRIDX 1
+#define PID_ATTRIDX 2
+#define POLICY_ATTRIDX 3
+#define SRCNAM_ATTRIDX 4
+#define SRCID_ATTRIDX 5
+#define SINKNAM_ATTRIDX 6
+#define SINKID_ATTRIDX 7
+#define CONNID_ATTRIDX 8
+#define CONNNO_ATTRIDX 9
+#define STAMP_ATTRIDX 10
+#define DECISION_ATTRIDX 11
+
+#define ATTR_MAX 12
+
+static mrp_attr_def_t audio_attrs[] = {
+ ATTRIBUTE( "appid" , string , "<undefined>" ),
+ ATTRIBUTE( "role" , string , "music" ),
+ ATTRIBUTE( "pid" , string , "<unknown>" ),
+ ATTRIBUTE( "policy" , string , "relaxed" ),
+ ATTRIBUTE( "source_name", string , "<undefined>" ),
+ ATTRIBUTE( "source_id" , integer, 0 ),
+ ATTRIBUTE( "sink_name" , string , "<undefined>" ),
+ ATTRIBUTE( "sink_id" , integer, 0 ),
+ ATTRIBUTE( "connid" , integer, 0 ),
+ ATTRIBUTE( "connno" , integer, 0 ),
+ ATTRIBUTE( "stamp" , integer, 0 ),
+ ATTRIBUTE( "decision" , string , "<not yet>" ),
+ ATTR_END
+};
+
+static mrp_resource_mgr_ftbl_t playback_ftbl = {
+ backend_notify, /* notify */
+ backend_init, /* init */
+ backend_allocate, /* allocate */
+ backend_free, /* free */
+ backend_advice, /* advice */
+ NULL /* commit */
+};
+
+static mrp_resource_mgr_ftbl_t recording_ftbl = {
+ backend_notify, /* notify */
+ NULL, /* init */
+ backend_allocate, /* allocate */
+ backend_free, /* free */
+ backend_advice, /* advice */
+ backend_commit /* commit */
+};
+
+static mrp_resource_mgr_ftbl_t *backend_ftbl[MRP_RESMGR_RESOURCE_TYPE_MAX] = {
+ [ MRP_RESMGR_RESOURCE_TYPE_PLAYBACK ] = &playback_ftbl ,
+ [ MRP_RESMGR_RESOURCE_TYPE_RECORDING ] = &recording_ftbl,
+};
+
+
+static const char *decision_names[DECISION_MAX + 1] = {
+ [ DECISION_TEARDOWN ] = "teardown" ,
+ [ DECISION_DISCONNECTED ] = "disconnected",
+ [ DECISION_CONNECTED ] = "connected" ,
+ [ DECISION_SUSPENDED ] = "suspended" ,
+};
+
+static const char *state_names[STATE_MAX + 1] = {
+ [ STATE_STOP ] = "stop" ,
+ [ STATE_PAUSE ] = "pause",
+ [ STATE_PLAY ] = "play" ,
+};
+
+static state_value_t decision2state[DECISION_MAX] = {
+ [ DECISION_TEARDOWN ] = STATE_STOP ,
+ [ DECISION_DISCONNECTED ] = STATE_STOP ,
+ [ DECISION_CONNECTED ] = STATE_PLAY ,
+ [ DECISION_SUSPENDED ] = STATE_PAUSE,
+};
+
+
+mrp_resmgr_backend_t *mrp_resmgr_backend_create(mrp_resmgr_t *resmgr)
+{
+ mrp_resmgr_backend_t *backend;
+ mrp_htbl_config_t pcfg, icfg;
+
+ MRP_ASSERT(resmgr, "invalid argument");
+
+ if ((backend = mrp_allocz(sizeof(mrp_resmgr_backend_t)))) {
+ pcfg.nentry = MRP_RESMGR_RESOURCE_MAX;
+ pcfg.comp = hash_compare;
+ pcfg.hash = ptr_hash_function;
+ pcfg.free = NULL;
+ pcfg.nbucket = MRP_RESMGR_RESOURCE_BUCKETS;
+
+ icfg.nentry = MRP_RESMGR_RESOURCE_MAX;
+ icfg.comp = hash_compare;
+ icfg.hash = id_hash_function;
+ icfg.free = NULL;
+ icfg.nbucket = MRP_RESMGR_RESOURCE_BUCKETS;
+
+ backend->resmgr = resmgr;
+ backend->resources.by_pointer = mrp_htbl_create(&pcfg);
+ backend->resources.by_connid = mrp_htbl_create(&icfg);
+
+ make_resource_definition(backend, MRP_RESMGR_RESOURCE_TYPE_PLAYBACK,
+ MRP_RESMGR_PLAYBACK_RESOURCE);
+ make_resource_definition(backend, MRP_RESMGR_RESOURCE_TYPE_RECORDING,
+ MRP_RESMGR_RECORDING_RESOURCE);
+ }
+
+ return backend;
+}
+
+void mrp_resmgr_backend_destroy(mrp_resmgr_backend_t *backend)
+{
+ if (backend) {
+ mrp_free(backend);
+ }
+}
+
+const char **mrp_resmgr_backend_get_decision_names(void)
+{
+ return decision_names;
+}
+
+uint32_t mrp_resmgr_backend_get_resource_connid(mrp_resmgr_resource_t *ar)
+{
+ MRP_ASSERT(ar, "invalid argument");
+
+ return ar->connid;
+}
+
+uint32_t mrp_resmgr_backend_get_resource_connno(mrp_resmgr_resource_t *ar)
+{
+ MRP_ASSERT(ar, "invalid argument");
+
+ return ar->connno;
+}
+
+int32_t mrp_resmgr_backend_get_resource_state(mrp_resmgr_resource_t *ar)
+{
+ MRP_ASSERT(ar, "invalid argument");
+
+ if (get_resource_stamp(ar->res) == 0)
+ return 0;
+
+ return ar->state.current;
+}
+
+int32_t mrp_resmgr_backend_get_resource_decision_id(mrp_resmgr_resource_t *ar)
+{
+ MRP_ASSERT(ar, "invalid argument");
+
+ if (get_resource_stamp(ar->res) == 0)
+ return 0;
+
+ return mrp_resmgr_sink_get_decision_id(ar->sink, ar->source);
+}
+
+
+uint32_t mrp_resmgr_backend_get_attribute_index(const char *name,
+ mqi_data_type_t type)
+{
+ mrp_attr_def_t *attrd;
+ uint32_t idx;
+
+ if (name) {
+ for (idx = 0; (attrd = audio_attrs + idx)->name; idx++) {
+ if (!strcmp(name, attrd->name)) {
+ if (attrd->type == type)
+ return idx;
+ break;
+ }
+ } /* for attrd */
+ }
+
+ return MRP_RESMGR_RESOURCE_FIELD_INVALID;
+}
+
+
+int32_t mrp_resmgr_backend_get_integer_attribute(mrp_resmgr_resource_t *ar,
+ uint32_t idx)
+{
+ mrp_attr_t attr;
+
+ if (mrp_resource_read_attribute(ar->res, idx, &attr)) {
+ if (attr.type == mqi_integer)
+ return attr.value.integer;
+ }
+
+ return 0;
+}
+
+const char *mrp_resmgr_backend_get_string_attribute(mrp_resmgr_resource_t *ar,
+ uint32_t idx)
+{
+ mrp_attr_t attr;
+
+ if (mrp_resource_read_attribute(ar->res, idx, &attr)) {
+ if (attr.type == mqi_string)
+ return attr.value.string;
+ }
+
+ return "";
+}
+
+
+mrp_resmgr_resource_t *mrp_resmgr_backend_resource_list_entry(
+ mrp_list_hook_t *entry)
+{
+ MRP_ASSERT(entry, "invalid argument");
+
+ return mrp_list_entry(entry, mrp_resmgr_resource_t, source_link);
+}
+
+
+
+
+
+
+#if 0
+int mrp_resmgr_backend_print(mrp_resmgr_backend_t *backend,
+ uint32_t zoneid,
+ char *buf, int len)
+{
+#define PRINT(...) \
+ do { \
+ p += snprintf(p, e-p, __VA_ARGS__); \
+ if (p >= e) \
+ return p - buf; \
+ } while (0)
+
+ char *p, *e;
+ uint32_t grantid;
+ mrp_list_hook_t *resources, *rentry, *rn;
+ mrp_resmgr_resource_t *ar;
+ mrp_attr_t a;
+ size_t i;
+ char disable[256];
+ char requisite[1024];
+
+ MRP_ASSERT(backend && buf && len > 0, "invalid argument");
+
+ e = (p = buf) + len;
+ *p = 0;
+
+ if (zoneid < MRP_ZONE_MAX) {
+ resources = backend->zones + zoneid;
+ grantid = backend->grantids[zoneid];
+ }
+ else {
+ resources = NULL;
+ grantid = 0;
+ }
+
+ PRINT(" Resource '%s' - grantid:%u\n",
+ MRP_SYSCTL_AUDIO_RESOURCE, grantid);
+
+ if (!resources || mrp_list_empty(resources))
+ PRINT(" No resources\n");
+ else {
+ mrp_list_foreach_back(resources, rentry, rn) {
+ ar = mrp_list_entry(rentry, mrp_resmgr_resource_t, link);
+
+ mrp_resmgr_disable_print(ar->disable, disable,
+ sizeof(disable));
+ mrp_application_requisite_print(ar->requisite, requisite,
+ sizeof(requisite));
+
+ PRINT(" "
+ "key:0x%08x %s %s grantid:%u requisite:%s disable:%s",
+ ar->key,
+ ar->interrupt ? "interrupt" : "base",
+ ar->acquire ? "acquire":"release",
+ ar->grantid,
+ requisite,
+ disable);
+
+ for (i = 0; i < MRP_ARRAY_SIZE(audio_attrs) - 1; i++) {
+ if ((mrp_resource_read_attribute(ar->res, i, &a))) {
+ PRINT(" %s:", a.name);
+
+ switch (a.type) {
+ case mqi_string: PRINT("'%s'",a.value.string); break;
+ case mqi_integer: PRINT("%d",a.value.integer); break;
+ case mqi_unsignd: PRINT("%u",a.value.unsignd); break;
+ case mqi_floating: PRINT("%lf",a.value.floating);break;
+ default: PRINT("<unsupported type>"); break;
+ }
+ }
+ }
+
+ PRINT("\n");
+ } /* mrp_list_foreach_back - resources */
+ }
+
+ return p - buf;
+}
+#endif
+
+static void make_resource_definition(mrp_resmgr_backend_t *backend,
+ int id,
+ const char *name)
+{
+ resource_type_t *type = backend->types + id;
+
+ MRP_ASSERT(backend && id >= 0 && id < MRP_RESMGR_RESOURCE_TYPE_MAX,
+ "invalid attribute");
+
+ type->id = id;
+ type->name = mrp_strdup(name);
+ type->resid = mrp_resource_definition_create(type->name, true, /* share */
+ audio_attrs, backend_ftbl[id],
+ backend);
+
+ mrp_lua_resclass_create_from_c(type->resid);
+}
+
+static resource_type_t *find_resource_definition_by_id(
+ mrp_resmgr_backend_t *backend,
+ int id)
+{
+ resource_type_t *type;
+ int i;
+
+ MRP_ASSERT(backend, "invalid argument");
+
+ for (i = 0; i < MRP_RESMGR_RESOURCE_TYPE_MAX; i++) {
+ type = backend->types + i;
+
+ if (type->id == id)
+ return type;
+ }
+
+ return NULL;
+}
+
+static int hash_compare(const void *key1, const void *key2)
+{
+ if (key1 < key2)
+ return -1;
+ if (key1 > key2)
+ return 1;
+ return 0;
+}
+
+static uint32_t ptr_hash_function(const void *key)
+{
+ return (uint32_t)(((size_t)key >> 4) & 0xffffffff);
+}
+
+static uint32_t id_hash_function(const void *key)
+{
+ return (uint32_t)(key - (const void *)0);
+}
+
+
+#if 0
+static const char *get_resource_appid(mrp_resource_t *res)
+{
+ mrp_attr_t attr;
+ const char *appid;
+
+ if (!mrp_resource_read_attribute(res, APPID_ATTRIDX, &attr) ||
+ attr.type != mqi_string || !(appid = attr.value.string) )
+ appid = NULL;
+
+ return appid;
+}
+#endif
+
+static int32_t get_resource_sourceid(mrp_resource_t *res)
+{
+ mrp_attr_t attr;
+
+ if (!mrp_resource_read_attribute(res, SRCID_ATTRIDX, &attr) ||
+ attr.type != mqi_integer)
+ {
+ return 0;
+ }
+
+ return attr.value.integer;
+}
+
+static int32_t get_resource_sinkid(mrp_resource_t *res)
+{
+ mrp_attr_t attr;
+
+ if (!mrp_resource_read_attribute(res, SINKID_ATTRIDX, &attr) ||
+ attr.type != mqi_integer)
+ {
+ return 0;
+ }
+
+ return attr.value.integer;
+}
+
+
+static int32_t get_resource_connid(mrp_resource_t *res)
+{
+ mrp_attr_t attr;
+
+ if (!mrp_resource_read_attribute(res, CONNID_ATTRIDX, &attr) ||
+ attr.type != mqi_integer)
+ {
+ return 0;
+ }
+
+ return attr.value.integer;
+}
+
+static int32_t get_resource_connno(mrp_resource_t *res)
+{
+ mrp_attr_t attr;
+
+ if (!mrp_resource_read_attribute(res, CONNNO_ATTRIDX, &attr) ||
+ attr.type != mqi_integer)
+ {
+ return 0;
+ }
+
+ return attr.value.integer;
+}
+
+static int32_t get_resource_stamp(mrp_resource_t *res)
+{
+ mrp_attr_t attr;
+
+ if (!mrp_resource_read_attribute(res, STAMP_ATTRIDX, &attr) ||
+ attr.type != mqi_integer)
+ {
+ return 0;
+ }
+
+ return attr.value.integer;
+}
+
+static bool set_resource_source_and_sink(mrp_resource_t *res,
+ mrp_resmgr_source_t *source,
+ mrp_resmgr_sink_t *sink)
+{
+ const char *source_name;
+ const char *sink_name;
+ mrp_attr_t attrs[ATTR_MAX+1];
+
+ memset(attrs, 0, sizeof(attrs));
+
+ if (!mrp_resource_read_all_attributes(res, ATTR_MAX+1, attrs))
+ return false;
+
+ if (source && (source_name = mrp_resmgr_source_get_name(source)))
+ attrs[SRCNAM_ATTRIDX].value.string = source_name;
+
+ if (sink && (sink_name = mrp_resmgr_sink_get_name(sink)))
+ attrs[SINKNAM_ATTRIDX].value.string = sink_name;
+
+ if (mrp_resource_write_attributes(res, attrs) < 0)
+ return false;
+
+ return true;
+}
+
+
+static bool set_resource_stamp(mrp_resource_t *res, int32_t stamp)
+{
+ mrp_attr_t attrs[ATTR_MAX+1];
+
+ memset(attrs, 0, sizeof(attrs));
+
+ if (!mrp_resource_read_all_attributes(res, ATTR_MAX+1, attrs))
+ return false;
+
+ attrs[STAMP_ATTRIDX].value.integer = stamp;
+
+ if (mrp_resource_write_attributes(res, attrs) < 0)
+ return false;
+
+ return true;
+}
+
+static bool set_resource_decision(mrp_resource_t *res, int32_t decision)
+{
+ const char *decision_name;
+ mrp_attr_t attrs[ATTR_MAX+1];
+
+ if (decision < 0 || decision >= DECISION_MAX)
+ decision_name = "<error>";
+ else
+ decision_name = decision_names[decision];
+
+ memset(attrs, 0, sizeof(attrs));
+
+ if (!mrp_resource_read_all_attributes(res, ATTR_MAX+1, attrs))
+ return false;
+
+ attrs[DECISION_ATTRIDX].value.string = decision_name;
+
+ if (mrp_resource_write_attributes(res, attrs) < 0)
+ return false;
+
+ return true;
+}
+
+
+static void resource_create(mrp_resmgr_backend_t *backend,
+ mrp_application_class_t *ac,
+ mrp_zone_t *zone,
+ mrp_resource_t *res)
+{
+ mrp_resmgr_t *resmgr;
+ mrp_resmgr_resource_t *ar;
+ uint32_t zoneid;
+ uint32_t resid;
+ resource_type_t *type;
+ uint32_t srcid, sinkid;
+ mrp_resmgr_source_t *src;
+ mrp_resmgr_sink_t *sink;
+ int32_t connid;
+ int32_t connno;
+ char name[256];
+
+ MRP_UNUSED(ac);
+ MRP_UNUSED(zone);
+
+ MRP_ASSERT(backend && backend->resmgr && res, "invalid argument");
+
+ resmgr = backend->resmgr;
+ zoneid = mrp_zone_get_id(zone);
+ resid = mrp_resource_get_id(res);
+ type = find_resource_definition_by_id(backend, resid);
+ srcid = get_resource_sourceid(res);
+ sinkid = get_resource_sinkid(res);
+ src = (srcid > 0) ? mrp_resmgr_source_find_by_id(resmgr, srcid):NULL;
+ sink = (sinkid > 0) ? mrp_resmgr_sink_find_by_gam_id(resmgr,sinkid):NULL;
+ connid = get_resource_connid(res);
+ connno = get_resource_connno(res);
+
+ if (!type)
+ return;
+
+ resource_print_name(src, connno, name, sizeof(name));
+
+
+ if (!(ar = mrp_allocz(sizeof(mrp_resmgr_resource_t))))
+ return;
+
+ ar->name = mrp_strdup(name);
+ ar->backend = backend;
+ ar->res = res;
+ ar->type = type;
+ ar->source = src;
+ ar->sink = sink;
+ ar->zoneid = zoneid;
+ ar->connid = connid;
+ ar->connno = connno;
+
+ mrp_list_init(&ar->source_link);
+
+ if (!mrp_htbl_insert(backend->resources.by_pointer, res, ar)) {
+ mrp_log_error("gam-resource-manager: can't add resource %s"
+ "to hash (by pointer)", ar->name);
+ mrp_free(ar);
+ return;
+ }
+
+ resource_register_by_id(backend, ar);
+
+ set_resource_source_and_sink(ar->res, ar->source, ar->sink);
+}
+
+static void resource_destroy(mrp_resmgr_backend_t *backend,
+ mrp_zone_t *zone,
+ mrp_resource_t *res)
+{
+ mrp_resmgr_usecase_t *usecase;
+ mrp_resmgr_resource_t *ar;
+ mrp_htbl_t *hash;
+
+ MRP_ASSERT(backend && backend->resmgr && zone && res,"invalid argument");
+
+ if (!(hash = backend->resources.by_pointer) ||
+ !(ar = mrp_htbl_remove(hash, res, false)))
+ {
+ mrp_debug("failed to destroy audio resource: can't find it");
+ return;
+ }
+
+ mrp_debug("%s resource '%s' going to be destroyed",
+ ar->type->name, ar->name);
+
+ if (ar->connid > 0 && (hash = backend->resources.by_connid)) {
+ if (ar != mrp_htbl_remove(hash, NULL + ar->connid, false)) {
+ mrp_log_error("gam-resource-manager: confused with data "
+ "structures when attempting to remove "
+ "resource '%s' from ID hash", ar->name);
+ }
+ }
+
+ mrp_list_delete(&ar->source_link);
+
+ mrp_free((void *)ar->name);
+
+ mrp_free(ar);
+
+ usecase = mrp_resmgr_get_usecase(backend->resmgr);
+ mrp_resmgr_usecase_update(usecase);
+}
+
+static bool resource_acquire(mrp_resmgr_backend_t *backend,
+ mrp_zone_t *zone,
+ mrp_resource_t *res)
+{
+ static int32_t stamp;
+
+ mrp_resmgr_resource_t *ar;
+
+ MRP_ASSERT(backend && zone && res, "invalid argument");
+
+ if (!(ar = resource_lookup_by_pointer(backend, res))) {
+ mrp_debug("failed to acquire audio resource: can't find it");
+ return false;
+ }
+
+ if (!set_resource_stamp(ar->res, ++stamp)) {
+ mrp_log_error("gam-resource-manager: failed to set 'stamp' "
+ "property for '%s' when acquiring", ar->name);
+ return false;
+ }
+
+ return true;
+}
+
+
+static bool resource_release(mrp_resmgr_backend_t *backend,
+ mrp_zone_t *zone,
+ mrp_resource_t *res)
+{
+ mrp_resmgr_resource_t *ar;
+
+ MRP_ASSERT(backend && zone && res, "invalid argument");
+
+ if (!(ar = resource_lookup_by_pointer(backend, res))) {
+ mrp_debug("failed to release audio resource: can't find it");
+ return false;
+ }
+
+ if (!set_resource_stamp(ar->res, 0)) {
+ mrp_log_error("gam-resource-manager: failed to set 'stamp' "
+ "property for '%s' when releasing", ar->name);
+ return false;
+ }
+
+ return true;
+}
+
+
+static bool resource_register_by_id(mrp_resmgr_backend_t *backend,
+ mrp_resmgr_resource_t *ar)
+{
+ if (ar->connid < 1)
+ return false;
+
+ if (!mrp_htbl_insert(backend->resources.by_connid, NULL + ar->connid, ar)) {
+ mrp_log_error("gam-resource-manager: can't add resource '%s'"
+ "to hash (by connid)", ar->name);
+ return false;
+ }
+
+ if (!mrp_resmgr_source_add_resource(ar->source, &ar->source_link)) {
+ mrp_log_error("gam-resource-manager: can't add resource '%s'"
+ "to source", ar->name);
+ return false;
+ }
+
+ return true;
+}
+
+static mrp_resmgr_resource_t *resource_lookup_by_pointer(mrp_resmgr_backend_t *backend,
+ mrp_resource_t *res)
+{
+ mrp_htbl_t *htbl;
+
+ if (!backend || !(htbl = backend->resources.by_pointer) || !res)
+ return NULL;
+
+ return mrp_htbl_lookup(htbl, res);
+}
+
+static size_t resource_print_name(mrp_resmgr_source_t *src,
+ uint32_t connno,
+ char *name,
+ size_t len)
+{
+ size_t ret;
+
+ if (!src)
+ ret = snprintf(name, len, "<invalid>");
+ else if (connno < 2)
+ ret = snprintf(name, len, "%s", mrp_resmgr_source_get_name(src));
+ else {
+ ret = snprintf(name, len, "%s%d", mrp_resmgr_source_get_name(src),
+ connno);
+ }
+
+ return ret;
+}
+
+
+static int decision_cb(void *key, void *object, void *user_data)
+{
+ mrp_resmgr_backend_t *backend = (mrp_resmgr_backend_t *)user_data;
+ mrp_resmgr_resource_t *ar = (mrp_resmgr_resource_t *)object;
+ mrp_resmgr_t *resmgr;
+ mrp_resmgr_usecase_t *usecase;
+ bool sink_available, source_available;
+ int32_t decision_new, state_new;
+ mrp_attr_t attrs[ATTR_MAX+1];
+ uint16_t src_id, sink_id;
+ uint32_t connid;
+ mrp_resmgr_source_t *src;
+ bool need_update;
+ char buf[512];
+
+ MRP_UNUSED(key);
+ MRP_UNUSED(user_data);
+
+ MRP_ASSERT(ar && ar->backend == backend, "confused with data structures");
+
+ if (!ar->sink || !ar->source || !ar->connno) {
+ memset(attrs, 0, sizeof(attrs));
+ need_update = false;
+
+ if (mrp_resource_read_all_attributes(ar->res, ATTR_MAX+1, attrs)) {
+ src_id = attrs[SRCID_ATTRIDX].value.integer;
+ sink_id = attrs[SINKID_ATTRIDX].value.integer;
+ connid = attrs[CONNID_ATTRIDX].value.integer;
+
+ if (!ar->source && src_id > 0) {
+ src = mrp_resmgr_source_find_by_id(backend->resmgr, src_id);
+
+ if (src && mrp_resmgr_source_add_resource(src,&ar->source_link)) {
+ resource_print_name(src, ar->connno, buf, sizeof(buf));
+ mrp_free(ar->name);
+
+ ar->name = mrp_strdup(buf);
+ ar->source = src;
+
+ mrp_debug("update resource %s source to '%s'",
+ ar->name, mrp_resmgr_source_get_name(src));
+
+ need_update = true;
+ }
+ }
+
+ if (!ar->sink && sink_id > 0) {
+ ar->sink = mrp_resmgr_sink_find_by_gam_id(backend->resmgr,
+ sink_id);
+ mrp_debug("update resource %s sink to '%s'",
+ ar->name, mrp_resmgr_sink_get_name(ar->sink));
+
+ need_update = true;
+ }
+
+ if (!ar->connid && connid > 0) {
+ ar->connid = connid;
+ mrp_debug("update resource %s connid to %u",
+ ar->name, connid);
+
+ need_update = true;
+ }
+
+ if (need_update) {
+ resmgr = backend->resmgr;
+
+ if ((usecase = mrp_resmgr_get_usecase(resmgr)))
+ mrp_resmgr_usecase_update(usecase);
+ }
+ }
+ }
+
+ source_available = mrp_resmgr_source_get_availability(ar->source);
+ sink_available = mrp_resmgr_sink_get_availability(ar->sink);
+
+ if (!source_available || !sink_available)
+ decision_new = DECISION_DISCONNECTED; /* or teardown ? */
+ else if (ar->connno != 0 || ar->connid < 1)
+ decision_new = DECISION_DISCONNECTED;
+ else
+ decision_new = mrp_resmgr_source_make_decision(ar->source);
+
+ if (decision_new < 0 || decision_new >= DECISION_MAX)
+ decision_new = ar->decision.current;
+
+ if (decision_new < 0 || decision_new >= DECISION_MAX)
+ decision_new = 0;
+
+ state_new = decision2state[decision_new];
+
+ ar->decision.new = decision_new;
+ ar->state.new = state_new;
+
+ print_decision(ar, buf, sizeof(buf));
+ mrp_debug(" %s", buf);
+
+ return MRP_HTBL_ITER_MORE;
+}
+
+static void make_decisions(mrp_resmgr_backend_t *backend)
+{
+ mrp_resmgr_usecase_t *usecase;
+
+ usecase = mrp_resmgr_get_usecase(backend->resmgr);
+ mrp_resmgr_usecase_update(usecase);
+
+ mrp_htbl_foreach(backend->resources.by_pointer, decision_cb, backend);
+}
+
+static int commit_cb(void *key, void *object, void *user_data)
+{
+ mrp_resmgr_backend_t *backend = (mrp_resmgr_backend_t *)user_data;
+ mrp_resmgr_resource_t *ar = (mrp_resmgr_resource_t *)object;
+ char buf[256];
+
+ MRP_UNUSED(key);
+ MRP_UNUSED(user_data);
+
+ MRP_ASSERT(ar && ar->backend == backend, "confused with data structures");
+
+ if (ar->source) {
+ print_commit(ar, buf, sizeof(buf));
+ mrp_debug(" %s", buf);
+
+ ar->decision.current = ar->decision.new;
+ ar->state.current = ar->state.new;
+
+ set_resource_decision(ar->res, ar->decision.current);
+ }
+
+ return MRP_HTBL_ITER_MORE;
+}
+
+static void commit_decisions(mrp_resmgr_backend_t *backend)
+{
+ mrp_resmgr_usecase_t *usecase;
+
+ mrp_htbl_foreach(backend->resources.by_pointer, commit_cb, backend);
+
+ usecase = mrp_resmgr_get_usecase(backend->resmgr);
+ mrp_resmgr_usecase_update(usecase);
+}
+
+
+static size_t print_decision(mrp_resmgr_resource_t *ar, char *buf, size_t len)
+{
+ char name [256];
+ char decision[256];
+ char state[256];
+
+ snprintf(name, sizeof(name), "%s:", ar->name);
+
+ if (ar->decision.new == ar->decision.current) {
+ snprintf(decision, sizeof(decision), "%s (no change)",
+ decision_names[ar->decision.new]);
+ }
+ else {
+ snprintf(decision, sizeof(decision), "%s => %s",
+ decision_names[ar->decision.current],
+ decision_names[ar->decision.new]);
+ }
+
+ if (ar->state.new == ar->state.current)
+ state[0] = 0;
+ else {
+ snprintf(state, sizeof(state), "%s => %s",
+ state_names[ar->state.current],
+ state_names[ar->state.new]);
+ }
+
+ return snprintf(buf, len, "%-24s %-28s %s", name, decision, state);
+}
+
+
+static size_t print_commit(mrp_resmgr_resource_t *ar, char *buf, size_t len)
+{
+ const char *decision;
+ const char *state;
+ char name[256];
+
+ snprintf(name, sizeof(name), "%s:", ar->name);
+
+ decision = decision_names[ar->decision.new];
+ state = state_names[ar->state.new];
+
+ return snprintf(buf, len, "%-24s %-12s %s", name, decision, state);
+}
+
+
+static void backend_notify(mrp_resource_event_t event,
+ mrp_zone_t *zone,
+ mrp_application_class_t *ac,
+ mrp_resource_t *res,
+ void *userdata)
+{
+ mrp_resmgr_backend_t *backend = (mrp_resmgr_backend_t *)userdata;
+ const char *zonename = mrp_zone_get_name(zone);
+
+ MRP_ASSERT(zone && ac && res && backend, "invalid argument");
+
+ switch (event) {
+
+ case MRP_RESOURCE_EVENT_CREATED:
+ mrp_debug("audio resource in zone '%s' created", zonename);
+ resource_create(backend, ac, zone, res);
+ break;
+
+ case MRP_RESOURCE_EVENT_DESTROYED:
+ mrp_debug("audio resource in zone '%s' destroyed", zonename);
+ resource_destroy(backend, zone, res);
+ break;
+
+ case MRP_RESOURCE_EVENT_ACQUIRE:
+ mrp_debug("audio resource in zone '%s' is acquiring", zonename);
+ resource_acquire(backend, zone, res);
+ break;
+
+ case MRP_RESOURCE_EVENT_RELEASE:
+ mrp_debug("audio resource in zone '%s' is released", zonename);
+ resource_release(backend, zone, res);
+ break;
+
+ default:
+ mrp_log_error("gam-resource-manager: invalid event %d at audio "
+ "notification (zone '%s')", event, zonename);
+ break;
+ }
+}
+
+static void backend_init(mrp_zone_t *zone, void *userdata)
+{
+ mrp_resmgr_backend_t *backend = (mrp_resmgr_backend_t *)userdata;
+ // uint32_t zoneid;
+ const char *zonename;
+
+ MRP_ASSERT(zone && backend && backend->resmgr, "invalid argument");
+
+ // zoneid = mrp_zone_get_id(zone);
+ zonename = mrp_zone_get_name(zone);
+
+ if (!zonename)
+ zonename = "<unknown>";
+
+ mrp_debug("audio init in zone '%s'", zonename);
+
+ make_decisions(backend);
+}
+
+static bool backend_allocate(mrp_zone_t *zone,
+ mrp_resource_t *res,
+ void *userdata)
+{
+ mrp_resmgr_backend_t *backend = (mrp_resmgr_backend_t *)userdata;
+ // uint32_t zoneid;
+ const char *zonename;
+ mrp_resmgr_resource_t *ar;
+ bool allocated;
+
+ MRP_ASSERT(zone && res && backend && backend->resmgr, "invalid argument");
+
+ // zoneid = mrp_zone_get_id(zone);
+
+ if (!(zonename = mrp_zone_get_name(zone)))
+ zonename = "<unknown>";
+
+ if ((ar = resource_lookup_by_pointer(backend, res))) {
+ allocated = (ar->state.new == STATE_PLAY);
+
+ mrp_debug("%s allocation for '%s' in zone '%s' %s",
+ ar->type->name, ar->name, zonename,
+ allocated ? "succeeded":"failed");
+
+ return allocated;
+ }
+
+ mrp_log_error("gam-resource-manager: attempt to allocate untracked "
+ "resource in zone '%s'", zonename);
+
+ return FALSE;
+}
+
+static void backend_free(mrp_zone_t *zone, mrp_resource_t *res, void *userdata)
+{
+ mrp_resmgr_backend_t *backend = (mrp_resmgr_backend_t *)userdata;
+ const char *zonename;
+ mrp_resmgr_resource_t *ar;
+
+ MRP_ASSERT(zone && res && backend, "invalid argument");
+
+ if (!(zonename = mrp_zone_get_name(zone)))
+ zonename = "<unknown>";
+
+ if ((ar = resource_lookup_by_pointer(backend, res))) {
+ ar->decision.new = DECISION_DISCONNECTED;
+ ar->state.new = decision2state[ar->decision.new];
+
+ mrp_debug("free %s of '%s' in zone '%s'",
+ ar->type->name, ar->name, zonename);
+
+ return;
+ }
+
+ mrp_log_error("gam-resource-manager: attempt to free untracked "
+ "resource in zone '%s'", zonename);
+}
+
+static bool backend_advice(mrp_zone_t *zone,mrp_resource_t *res,void *userdata)
+{
+#if 1
+ MRP_UNUSED(zone);
+ MRP_UNUSED(res);
+ MRP_UNUSED(userdata);
+#else
+ mrp_resmgr_backend_t *backend = (mrp_resmgr_backend_t *)userdata;
+ const char *zonename;
+ const char *appid;
+
+ MRP_ASSERT(zone && res && backend, "invalid argument");
+
+ if (!(zonename = mrp_zone_get_name(zone)))
+ zonename = "<unknown>";
+ if (!(appid = get_resource_appid(res)))
+ appid = "<unknown>";
+
+ mrp_debug("audio advice for '%s' in zone '%s'", appid, zonename);
+#endif
+
+ return TRUE;
+}
+
+static void backend_commit(mrp_zone_t *zone, void *userdata)
+{
+ mrp_resmgr_backend_t *backend = (mrp_resmgr_backend_t *)userdata;
+ const char *zonename;
+ // uint32_t zoneid;
+
+ MRP_ASSERT(zone && backend && backend->resmgr, "invalid argument");
+
+ // zoneid = mrp_zone_get_id(zone);
+
+ if (!(zonename = mrp_zone_get_name(zone)))
+ zonename = "<unknown>";
+
+ mrp_debug("audio commit in zone '%s'", zonename);
+
+ commit_decisions(backend);
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, 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.
+ */
+
+#ifndef __MURPHY_GAM_RESOURCE_MANAGER_BACKEND_H__
+#define __MURPHY_GAM_RESOURCE_MANAGER_BACKEND_H__
+
+#include <sys/types.h>
+
+#include <murphy/common/hashtbl.h>
+#include <murphy/resource/data-types.h>
+
+#include "plugin-gam-resource-manager.h"
+
+/* positive values are considered to be resource attribute indices */
+#define MRP_RESMGR_RESOURCE_FIELD_STATE -1
+#define MRP_RESMGR_RESOURCE_FIELD_DECISION_ID -2
+
+#define MRP_RESMGR_RESOURCE_FIELD_INVALID (~(uint32_t)0)
+
+
+mrp_resmgr_backend_t *mrp_resmgr_backend_create(mrp_resmgr_t *resmgr);
+void mrp_resmgr_backend_destroy(mrp_resmgr_backend_t *backend);
+const char **mrp_resmgr_backend_get_decision_names(void);
+
+uint32_t mrp_resmgr_backend_get_resource_connid(mrp_resmgr_resource_t *ar);
+uint32_t mrp_resmgr_backend_get_resource_connno(mrp_resmgr_resource_t *ar);
+int32_t mrp_resmgr_backend_get_resource_state(mrp_resmgr_resource_t *ar);
+int32_t mrp_resmgr_backend_get_resource_decision_id(mrp_resmgr_resource_t *ar);
+
+mrp_resmgr_resource_t *mrp_resmgr_backend_resource_list_entry(
+ mrp_list_hook_t *entry);
+
+uint32_t mrp_resmgr_backend_get_attribute_index(const char *name,
+ mqi_data_type_t type);
+int32_t mrp_resmgr_backend_get_integer_attribute(mrp_resmgr_resource_t *ar,
+ uint32_t idx);
+const char *mrp_resmgr_backend_get_string_attribute(mrp_resmgr_resource_t *ar,
+ uint32_t idx);
+
+#if 0
+int mrp_resmgr_backend_print(mrp_resmgr_backend_t *backend, uint32_t zoneid,
+ char *buf, int len);
+#endif
+
+#endif /* __MURPHY_GAM_RESOURCE_MANAGER_BACKEND_H__ */
--- /dev/null
+/*
+ * Copyright (c) 2014, 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 <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <murphy/common.h>
+
+#include "c5-decision-tree.h"
+
+
+#define ATTRIBUTE_MAX 32
+#define ENUM_MAX 16384
+#define ENUM_BUCKETS 16
+
+
+
+typedef enum state_e state_t;
+typedef struct conf_iter_s conf_iter_t;
+typedef struct attr_value_iter_s attr_value_iter_t;
+typedef struct value_list_item_s value_list_item_t;
+typedef struct value_list_s value_list_t;
+
+enum state_e {
+ START = 0,
+ NAME,
+ VALUE,
+ END
+};
+
+
+struct conf_iter_s {
+ mrp_decision_conf_t *conf;
+ int nattr;
+ mrp_decision_attr_t *attrs[0];
+};
+
+
+struct attr_value_iter_s {
+ mrp_decision_attr_t *attr;
+ int ndesc;
+ mrp_decision_attr_value_desc_t descs[0];
+};
+
+struct value_list_item_s {
+ const char *name;
+ int32_t value;
+};
+
+struct value_list_s {
+ int size;
+ value_list_item_t *items;
+};
+
+static bool conf_finish(mrp_decision_conf_t *, const char *);
+static conf_iter_t *conf_iterator(mrp_decision_conf_t *);
+
+static mrp_decision_attr_t *attr_create(mrp_decision_conf_t*,const char*,int);
+static void attr_destroy(void *, void *);
+static void attr_add_value(mrp_decision_attr_t *, const char *);
+static attr_value_iter_t *attr_value_iterator(mrp_decision_attr_t *);
+static size_t attr_print(mrp_decision_attr_t *, bool, char *, size_t);
+
+static void value_destroy(void *, void *);
+
+static bool tree_parse(mrp_decision_conf_t *, FILE *, size_t *, char *,
+ mrp_decision_node_t **, int);
+static bool tree_parse_terminal_node(mrp_decision_conf_t *, FILE *, size_t *,
+ char *, bool, mrp_decision_node_t **, int);
+static bool tree_parse_test_node(mrp_decision_conf_t *, FILE *, size_t *,
+ char *, int, mrp_decision_node_t **, int);
+
+
+
+static bool property(char **, char **, char **);
+static bool list_item(char **, char **);
+static bool identifier(char **, char **, char *);
+static bool whitespace(char **);
+static bool quoted(char **, char **);
+
+static size_t print_node(mrp_decision_conf_t *, mrp_decision_node_t *,
+ conf_iter_t *, char *, size_t, char *);
+static size_t print_bitmask(mrp_decision_attr_t *, mrp_decision_bitmask_t,
+ char *, size_t);
+
+
+
+mrp_decision_conf_t *mrp_decision_conf_create_from_file(const char *stem)
+{
+ FILE *f;
+ char filnam[1024];
+ char *buf, *p;
+ size_t n;
+ ssize_t linlen;
+ state_t state;
+ char decision[256];
+ char *name;
+ char *value;
+ char sep;
+ size_t lineno;
+ mrp_decision_conf_t *conf;
+ mrp_decision_attr_t *attr;
+ mrp_htbl_config_t aconf;
+ int id;
+
+ if (!stem || !stem[0])
+ return false;
+
+ snprintf(filnam, sizeof(filnam), "%s.names", stem);
+ if (!(f = fopen(filnam, "r"))) {
+ mrp_log_error("gam-resource-manager: failed to open file '%s': %s",
+ filnam, strerror(errno));
+ return NULL;
+ }
+
+ if (!(conf = mrp_allocz(sizeof(mrp_decision_conf_t)))) {
+ mrp_log_error("gam-resource-manager: can't allocate memory for "
+ "'%s' decision configuration", stem);
+ return NULL;
+ }
+ else {
+ aconf.nentry = ATTRIBUTE_MAX;
+ aconf.comp = mrp_string_comp;
+ aconf.hash = mrp_string_hash;
+ aconf.free = attr_destroy;
+ aconf.nbucket = ATTRIBUTE_MAX;
+
+ conf->stem = mrp_strdup(stem);
+ conf->nattr = 0;
+ conf->attrs = mrp_htbl_create(&aconf);
+
+ if (!conf->attrs) {
+ mrp_log_error("gam-resource-manager: failed to create attribute "
+ "hash for '%s' decision configuration", stem);
+ mrp_decision_conf_destroy(conf);
+ return NULL;
+ }
+ }
+
+ state = START;
+ buf = NULL;
+ lineno = 0;
+ attr = NULL;
+ id = 0;
+ decision[0] = 0;
+
+ while ((linlen = getline(&buf, &n, f)) >= 0) {
+ lineno++;
+ p = buf;
+
+ whitespace(&p);
+
+ while (*p) {
+ switch (state) {
+
+ case START:
+ if (!identifier(&p, &name, &sep) || sep != '.')
+ goto failed;
+ mrp_debug("decision = '%s'", name);
+ snprintf(decision, sizeof(decision), "%s", name);
+ state = NAME;
+ whitespace(&p);
+ break;
+
+ case NAME:
+ if (!identifier(&p, &name, &sep) || sep != ':')
+ goto failed;
+ mrp_debug("name = '%s'", name);
+ if (!(attr = attr_create(conf, name, id++)))
+ goto failed;
+ state = VALUE;
+ whitespace(&p);
+ break;
+
+ case VALUE:
+ if (!identifier(&p, &value, &sep) ||
+ (sep != ',' && sep != '.' && sep != 0))
+ goto failed;
+ mrp_debug("value = '%s'", value);
+ if (!strcmp(name, "continuous") && sep != '.')
+ goto failed;
+ attr_add_value(attr, value);
+ if (sep == '.') {
+ state = NAME;
+ attr = NULL;
+ }
+ whitespace(&p);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ free(buf);
+ buf = NULL;
+ } /* while getline */
+
+ if (linlen < 0 && !feof(f)) {
+ mrp_log_error("gam-resource-manager: error during reading "
+ "'%s' file: %s", filnam, strerror(errno));
+ mrp_decision_conf_destroy(conf);
+ return NULL;
+ }
+
+ fclose(f);
+
+ if (!conf_finish(conf, decision)) {
+ mrp_decision_conf_destroy(conf);
+ return NULL;
+ }
+
+ mrp_log_info("mrp-resource-manager: successfully loaded "
+ "decision configuration from file '%s'", filnam);
+
+ return conf;
+
+ failed:
+ mrp_log_error("gam-resource-manager: error in file '%s' line %lu",
+ filnam, lineno);
+ free(buf);
+ fclose(f);
+ mrp_decision_conf_destroy(conf);
+ return NULL;
+}
+
+void mrp_decision_conf_destroy(mrp_decision_conf_t *conf)
+{
+ if (conf) {
+ mrp_log_info("mrp-resource-manager: going to unload "
+ "decision configuration '%s'", conf->stem);
+
+ if (conf->decision_attr && conf->decision_names)
+ mrp_free(conf->decision_names);
+
+ mrp_htbl_destroy(conf->attrs, TRUE);
+
+ mrp_free((void *)conf->stem);
+ mrp_free((void *)conf);
+ }
+}
+
+bool mrp_decision_set_attr_offset(mrp_decision_conf_t *conf,
+ const char *attr_name,
+ size_t offset)
+{
+ mrp_decision_attr_t *attr;
+
+ if (!conf || !attr_name)
+ return false;
+
+ if (!(attr = mrp_htbl_lookup(conf->attrs, (void *)attr_name)))
+ return false;
+
+ attr->offset = offset;
+
+ return true;
+}
+
+ssize_t mrp_decision_attr_list(mrp_decision_conf_t *conf,
+ const char **buf, size_t len)
+{
+ conf_iter_t *it;
+ int i,j,n;
+
+ if (!conf || !buf || len < 1)
+ return -1;
+
+ if ((int)len < conf->nattr)
+ return -1;
+
+ if (!(it = conf_iterator(conf)))
+ return -1;
+
+ for (i = j = 0, n = it->nattr; i < n; i++) {
+ if (conf->decision_attr != it->attrs[i])
+ buf[j++] = it->attrs[i]->name;
+ }
+ buf[j] = NULL;
+
+ mrp_free(it);
+
+ return j;
+}
+
+ssize_t mrp_decision_attr_value_list(mrp_decision_conf_t *conf,
+ const char *attr_name,
+ mrp_decision_attr_value_desc_t *buf,
+ size_t len)
+{
+ mrp_decision_attr_t *attr;
+ attr_value_iter_t *it;
+ int buf_len;
+ int actual_len;
+ size_t size;
+
+ if (!conf || !attr_name || !buf || (buf_len = len) < 1)
+ return -1;
+
+ if (!(attr = mrp_htbl_lookup(conf->attrs, (void *)attr_name)))
+ return -1;
+
+ if (buf_len < attr->nvalue)
+ return -1;
+
+ if (!(it = attr_value_iterator(attr)))
+ return -1;
+
+ actual_len = it->ndesc;
+
+ size = sizeof(mrp_decision_attr_value_desc_t) * actual_len;
+ memcpy(buf, it->descs, size);
+
+ if (buf_len > actual_len) {
+ size = sizeof(mrp_decision_attr_value_desc_t) * (buf_len - it->ndesc);
+ memset(buf + it->ndesc, 0, size);
+ }
+
+ mrp_free(it);
+
+ return actual_len;
+}
+
+
+
+const char *mrp_decision_name(mrp_decision_conf_t *conf, int32_t decision)
+{
+ if (!conf || decision < 0 || decision > conf->decision_attr->nvalue)
+ return "<invalid>";
+
+ return conf->decision_names[decision];
+}
+
+
+int32_t mrp_decision_value_max(mrp_decision_conf_t *conf)
+{
+ if (!conf || !conf->decision_attr)
+ return 0;
+
+ return conf->decision_attr->nvalue;
+}
+
+int32_t mrp_decision_get_integer_attr_value(mrp_decision_conf_t *conf,
+ const char *attr_name,
+ const char *value_name,
+ bool *error)
+{
+ mrp_decision_attr_t *attr;
+ mrp_decision_value_t *value;
+
+ if (error)
+ *error = true;
+
+ if (!conf || !attr_name || !value_name)
+ return 0;
+
+ if (!(attr = mrp_htbl_lookup(conf->attrs, (void *)attr_name)))
+ return -1;
+
+ if (attr->value_type != MRP_DECISION_VALUE_INTEGER)
+ return -1;
+
+ if (!(value = mrp_htbl_lookup(attr->values, (void *)value_name)))
+ return -1;
+
+ if (error)
+ *error = false;
+
+ return value->integer;
+}
+
+
+const char *mrp_decision_get_integer_attr_name(mrp_decision_conf_t *conf,
+ const char *attr_name,
+ int32_t value,
+ bool *error)
+{
+ mrp_decision_attr_t *attr;
+ attr_value_iter_t *it;
+ const char *value_name;
+ int i;
+
+ if (error)
+ *error = true;
+
+ if (!conf || !attr_name)
+ return "<error>";
+
+ if (!(attr = mrp_htbl_lookup(conf->attrs, (void *)attr_name)))
+ return "<unknown attribute>";
+
+ if (attr->value_type != MRP_DECISION_VALUE_INTEGER)
+ return "<not integer attribute>";
+
+ if (!(it = attr_value_iterator(attr)))
+ return "<error>";
+
+ for (i = 0, value_name = "<unknown value>"; i < it->ndesc; i++) {
+ if (it->descs[i].value == value) {
+ value_name = it->descs[i].name;
+ break;
+ }
+ }
+
+ if (i < it->ndesc && error)
+ *error = false;
+
+ return value_name;
+}
+
+
+size_t mrp_decision_conf_print(mrp_decision_conf_t *conf, char *buf,size_t len)
+{
+ conf_iter_t *it;
+ mrp_decision_attr_t *attr;
+ int i;
+ char *p, *e;
+
+ e = (p = buf) + len;
+
+ if (buf) {
+ if (!(it = conf_iterator(conf)))
+ p += snprintf(p, e-p, "<error>");
+ else {
+ p += snprintf(p, e-p, "attributes for '%s'\n", conf->stem);
+
+ for (i = 0; i < it->nattr; i++) {
+ attr = it->attrs[i];
+ p += attr_print(attr, (attr == conf->decision_attr), p, e-p);
+ }
+
+ mrp_free(it);
+ }
+ }
+
+ return p - buf;
+}
+
+
+static bool conf_finish(mrp_decision_conf_t *conf,
+ const char *decision_attr_name)
+{
+ mrp_decision_attr_t *attr;
+ attr_value_iter_t *it;
+ mrp_decision_attr_value_desc_t *dsc;
+ size_t size;
+ const char **tbl;
+ int i, n;
+
+ if (!(attr = mrp_htbl_lookup(conf->attrs, (void *)decision_attr_name))) {
+ mrp_log_error("gam-resoure-manager: can't find decision attribute "
+ "'%s' for '%s'", decision_attr_name, conf->stem);
+ return false;
+ }
+
+ if (attr->nvalue < 1) {
+ mrp_log_error("gam-resource-manager: attribute '%s' in '%s' is "
+ "not suitable for decisions", attr->name, conf->stem);
+ return false;
+ }
+
+ n = attr->nvalue;
+ size = sizeof(const char *) * n;
+
+ if (!(it = attr_value_iterator(attr)) || !(tbl = mrp_allocz(size))) {
+ mrp_free(it);
+ mrp_log_error("gam-resource-manager: can't allocate memory to "
+ "finalize '%s' decision", conf->stem);
+ return false;
+ }
+
+ for (i = 0; i < n; i++) {
+ dsc = it->descs + i;
+
+ if (i != dsc->value) {
+ mrp_log_error("gam-resource-manager: internal error: decision "
+ "values of '%s' are non-continous for '%s' decisions",
+ attr->name, conf->stem);
+ mrp_free(it);
+ mrp_free(tbl);
+ return false;
+ }
+
+ tbl[i] = dsc->name;
+ };
+
+ mrp_free(it);
+
+ conf->decision_attr = attr;
+ conf->decision_names = tbl;
+
+ return true;
+}
+
+
+static int conf_iter_cb(void *key, void *object, void *user_data)
+{
+ conf_iter_t *it = (conf_iter_t *)user_data;
+ mrp_decision_attr_t *attr = (mrp_decision_attr_t *)object;
+
+ MRP_UNUSED(key);
+
+ if (it->nattr >= it->conf->nattr) {
+ mrp_log_error("gam-resource-manager: detected inconsitency while "
+ "iterating configuration of '%s'", it->conf->stem);
+ }
+ else {
+ it->attrs[it->nattr++] = attr;
+ }
+
+ return MRP_HTBL_ITER_MORE;
+}
+
+static conf_iter_t *conf_iterator(mrp_decision_conf_t *conf)
+{
+ conf_iter_t *it;
+ size_t size;
+ mrp_decision_attr_t *tmp;
+ int i,j;
+
+ if (!conf)
+ it = NULL;
+ else {
+ size = sizeof(conf_iter_t) + (sizeof(void *) * conf->nattr);
+
+ if ((it = mrp_allocz(size))) {
+ it->conf = conf;
+
+ mrp_htbl_foreach(conf->attrs, conf_iter_cb, it);
+
+ for (i = 0; i < it->nattr - 1; i++) {
+ for (j = i + 1; j < it->nattr; j++) {
+ if (it->attrs[i]->id > it->attrs[j]->id) {
+ tmp = it->attrs[i];
+ it->attrs[i] = it->attrs[j];
+ it->attrs[j] = tmp;
+ }
+ }
+ }
+ }
+ }
+
+ return it;
+}
+
+
+static mrp_decision_attr_t *attr_create(mrp_decision_conf_t *conf,
+ const char *name, int id)
+{
+ mrp_decision_attr_t *attr;
+
+ if (!conf || !name)
+ attr = NULL;
+ else {
+ if ((attr = mrp_allocz(sizeof(mrp_decision_attr_t)))) {
+ attr->name = mrp_strdup(name);
+ attr->id = id;
+ attr->attr_type = MRP_DECISION_ATTR_CONTINUOUS;
+ attr->value_type = MRP_DECISION_VALUE_INTEGER;
+ attr->nvalue = 0;
+ attr->values = NULL;
+ }
+
+ if (!mrp_htbl_insert(conf->attrs, (void *)attr->name, attr)) {
+ attr_destroy((void *)attr->name, (void *)attr);
+ attr = NULL;
+ }
+
+ conf->nattr++;
+ }
+
+ return attr;
+}
+
+static void attr_destroy(void *key, void *object)
+{
+ mrp_decision_attr_t *attr = (mrp_decision_attr_t *)object;
+
+ MRP_UNUSED(key);
+
+ if (attr->values)
+ mrp_htbl_destroy(attr->values, TRUE);
+
+ mrp_free((void *)attr->name);
+ mrp_free(object);
+}
+
+static void attr_add_value(mrp_decision_attr_t *attr, const char *name)
+{
+ mrp_htbl_config_t vconf;
+ mrp_decision_value_t *value;
+ char *key = NULL;
+
+ if (attr && name) {
+ if (attr->attr_type == MRP_DECISION_ATTR_CONTINUOUS) {
+ vconf.nentry = ENUM_MAX;
+ vconf.comp = mrp_string_comp;
+ vconf.hash = mrp_string_hash;
+ vconf.free = value_destroy;
+ vconf.nbucket = ENUM_BUCKETS;
+
+ attr->attr_type = MRP_DECISION_ATTR_ENUM;
+ attr->nvalue = 0;
+ attr->values = mrp_htbl_create(&vconf);
+ }
+
+ if (!(key = mrp_strdup(name)) || !(value = mrp_allocz(sizeof(*value))))
+ mrp_free((void *)key);
+ else {
+ value->integer = attr->nvalue++;
+ mrp_htbl_insert(attr->values, key, value);
+ }
+ }
+}
+
+static int attr_value_iter_cb(void *key, void *object, void *user_data)
+{
+ attr_value_iter_t *it = (attr_value_iter_t *)user_data;
+ const char *name = (const char *)key;
+ mrp_decision_value_t *value = (mrp_decision_value_t *)object;
+ mrp_decision_attr_value_desc_t *desc;
+
+ if (it->ndesc >= it->attr->nvalue) {
+ mrp_log_error("gam-resource-manager: detected inconsitency while "
+ "iterating decision attribute '%s' for '%s'",
+ name, it->attr->name);
+ }
+ else {
+ desc = it->descs + it->ndesc++;
+ desc->name = name;
+ desc->value = value->integer;
+ }
+
+ return MRP_HTBL_ITER_MORE;
+}
+
+static attr_value_iter_t *attr_value_iterator(mrp_decision_attr_t *attr)
+{
+ attr_value_iter_t *it;
+ mrp_decision_attr_value_desc_t tmp;
+ size_t size;
+ int i,j;
+
+ if (!attr)
+ it = NULL;
+ else {
+ size = sizeof(*it) +
+ (sizeof(mrp_decision_attr_value_desc_t) * attr->nvalue);
+
+ if ((it = mrp_allocz(size))) {
+ it->attr = attr;
+ it->ndesc = 0;
+ mrp_htbl_foreach(attr->values, attr_value_iter_cb, it);
+
+ for (i = 0; i < it->ndesc - 1; i++) {
+ for (j = i + 1; j < it->ndesc; j++) {
+ if (it->descs[i].value > it->descs[j].value) {
+ tmp = it->descs[i];
+ it->descs[i] = it->descs[j];
+ it->descs[j] = tmp;
+ }
+ }
+ }
+ }
+ }
+
+ return it;
+}
+
+static size_t attr_print(mrp_decision_attr_t *attr, bool decision,
+ char *buf, size_t len)
+{
+#define PRINT(args...) \
+ do { if (p < e) p += snprintf(p, e-p, args); } while (0)
+
+ attr_value_iter_t *it;
+ mrp_decision_attr_value_desc_t *dsc;
+ char *p, *e;
+ const char *sep;
+ char nambuf[256];
+ int i;
+
+ e = (p = buf) + len;
+
+ if (attr && p < e) {
+ snprintf(nambuf, sizeof(nambuf), "%2d %s:", attr->id, attr->name);
+ PRINT(" %c %-24s @%03lu ", decision ? '*':' ', nambuf, attr->offset);
+
+ switch (attr->attr_type) {
+
+ case MRP_DECISION_ATTR_ENUM:
+ if (!(it = attr_value_iterator(attr)))
+ PRINT("<error>\n");
+ else {
+ PRINT("{");
+ for (i = 0; i < it->ndesc; i++) {
+ dsc = it->descs + i;
+ sep = (i == 0) ? "" : ((i % 10) ?
+ ", " :
+ ",\n ");
+ PRINT("%s[%d (%s)]", sep, dsc->value, dsc->name);
+ }
+ PRINT("}\n");
+
+ mrp_free(it);
+ }
+ break;
+
+ case MRP_DECISION_ATTR_CONTINUOUS:
+ PRINT("continuous\n");
+ break;
+
+ default:
+ PRINT("<unsupported attribute type %d>\n", attr->attr_type);
+ break;
+ }
+ }
+
+ return p - buf;
+
+#undef PRINT
+}
+
+static void value_destroy(void *key, void *object)
+{
+ mrp_free(key);
+ mrp_free(object);
+}
+
+
+mrp_decision_node_t *mrp_decision_tree_create_from_file(
+ mrp_decision_conf_t *conf,
+ const char *stem)
+{
+ FILE *f;
+ char filnam[1024];
+ char *buf, *p;
+ size_t n;
+ ssize_t linlen;
+ size_t lineno;
+ mrp_decision_node_t *root, *node;
+ mrp_decision_value_type_t vtype;
+ char *name, *value;
+
+ if (!stem)
+ stem = conf->stem;
+
+ snprintf(filnam, sizeof(filnam), "%s.tree", stem);
+ if (!(f = fopen(filnam, "r"))) {
+ printf("failed to open file '%s': %s\n", filnam, strerror(errno));
+ return NULL;
+ }
+
+ vtype = conf->decision_attr->value_type;
+
+ if (!(root = mrp_decision_tree_create(stem, vtype))) {
+ mrp_log_error("gam-resource-manager: failed to create "
+ "decision tree for '%s'", stem);
+ return NULL;
+ }
+
+ lineno = 0;
+ buf = NULL;
+ node = NULL;
+
+ while ((linlen = getline(&buf, &n, f)) >= 0) {
+ lineno++;
+ p = buf;
+
+ whitespace(&p);
+
+ if (!strncmp(p, "type", 4)) {
+ if (!(tree_parse(conf, f, &lineno, buf, &node, 0)))
+ goto failed;
+ if (!(mrp_decision_add_node_to_root(root, node)))
+ goto failed;
+ node = NULL;
+ }
+ else if (property(&p, &name, &value)) {
+ if (!strcmp(name, "id")) {
+ mrp_debug("id: %s", value);
+ }
+ else if (!strcmp(name, "entries")) {
+ mrp_debug("entries: %s", value);
+ }
+ else {
+ goto parse_error;
+ }
+ }
+
+ free(buf);
+ buf = NULL;
+ }
+
+ if (linlen < 0 && !feof(f)) {
+ mrp_log_error("gam-resource-manager: error during reading "
+ "'%s' file: %s", filnam, strerror(errno));
+ goto failed;
+ }
+
+ fclose(f);
+
+ mrp_log_info("mrp-resource-manager: successfully loaded "
+ "decision tree from file '%s'", filnam);
+
+ return root;
+
+ parse_error:
+ mrp_log_error("gam-resource-manager: error in file '%s' line %lu",
+ filnam, lineno);
+ failed:
+ mrp_log_error("gam-resource-manager: failed to parse '%s' file",
+ filnam);
+ free(buf);
+ fclose(f);
+ mrp_decision_tree_destroy(root);
+ mrp_decision_tree_destroy(node);
+ return NULL;
+}
+
+static const char *indent(int depth)
+{
+ static char buf[1024];
+ size_t l = depth * 3;
+ memset(buf, ' ', l);
+ buf[l] = 0;
+ return buf;
+}
+
+static bool tree_parse(mrp_decision_conf_t *conf,
+ FILE *f, size_t *lineno,
+ char *buf,
+ mrp_decision_node_t **node,
+ int depth)
+{
+ char *p = buf;
+ char *name, *value, *e;
+ int type;
+
+ if (!property(&p, &name, &value) || strcmp(name, "type"))
+ return false;
+
+ type = strtol(value, &e, 10);
+
+ if (e == value || *e)
+ return false;
+
+ switch (type) {
+ case 0:
+ return tree_parse_terminal_node(conf, f, lineno, p, false, node, depth);
+
+ case 1:
+ case 2:
+ case 3:
+ return tree_parse_test_node(conf, f, lineno, p, type, node, depth);
+
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+static bool tree_parse_terminal_node(mrp_decision_conf_t *conf,
+ FILE *f, size_t *lineno,
+ char *buf,
+ bool need_empty,
+ mrp_decision_node_t **node,
+ int depth)
+{
+ char *p = buf;
+ char *name, *value;
+ mrp_decision_value_t *vptr;
+ char *decision_name;
+ int32_t decision;
+ bool has_decision;
+ bool has_cases;
+
+ MRP_UNUSED(f);
+ MRP_UNUSED(lineno);
+ MRP_UNUSED(depth);
+
+ has_decision = false;
+ has_cases = false;
+
+ while (*p) {
+ if (!property(&p, &name, &value))
+ break;
+
+ if (!strcmp(name, "class")) {
+ if (!(vptr = mrp_htbl_lookup(conf->decision_attr->values, value)))
+ return false;
+ else {
+ decision_name = value;
+ decision = vptr->integer;
+ has_decision = true;
+ }
+ }
+ if (!strcmp(name, "freq")) {
+ has_cases = true;
+ }
+
+ whitespace(&p);
+ }
+
+ if (has_decision) {
+ if (!need_empty && node) {
+ mrp_debug("%sterminal: %d/%s", indent(depth),
+ decision, decision_name);
+ if (!(*node = mrp_decision_create_terminal_node(vptr)))
+ return false;
+ return true;
+ }
+ if (need_empty && !has_cases)
+ return true;
+ }
+
+ return false;
+}
+
+static bool tree_parse_test_node(mrp_decision_conf_t *conf,
+ FILE *f, size_t *lineno,
+ char *buf,
+ int type,
+ mrp_decision_node_t **node,
+ int depth)
+{
+ mrp_decision_node_t *child;
+ char *p;
+ char *name, *value;
+ mrp_decision_attr_t *attr;
+ int nbr;
+ char *e;
+ size_t n;
+ char *buf2;
+ int listidx;
+ value_list_t *lists, *l;
+ value_list_item_t *iv;
+ mrp_decision_value_t *av;
+ mrp_decision_value_type_t testval_type;
+ mrp_decision_value_t testval;
+ mrp_decision_condition_t testcond;
+ int i,j,k;
+ attr_value_iter_t *ait;
+ char valbuf[4096], *q;
+ size_t size;
+ bool ok, success;
+ char dbgbuf[256];
+
+ p = buf;
+ child = NULL;
+ attr = NULL;
+ nbr = -1;
+ listidx = 0;
+ lists = NULL;
+ buf2 = NULL;
+ ait = NULL;
+ success = false;
+
+ testcond = MRP_DECISION_EQ;
+ testval_type = MRP_DECISION_VALUE_UNKNOWN;
+ memset(&testval, 0, sizeof(testval));
+
+ while (*p) {
+ if (!property(&p, &name, &value))
+ break;
+
+ if (!strcmp(name, "att")) {
+ if (attr)
+ goto finish_parsing;
+
+ if (!(attr = mrp_htbl_lookup(conf->attrs, value)))
+ goto finish_parsing;
+ }
+ else if (!strcmp(name, "forks")) {
+ if (nbr >= 0)
+ goto finish_parsing;
+
+ nbr = strtol(value, &e, 10);
+
+ if (*e || e == value || nbr <= 0 || nbr > 100)
+ goto finish_parsing;
+
+ if (type == 3)
+ lists = mrp_allocz(sizeof(*lists) * nbr);
+ }
+ else if (!strcmp(name, "elts")) {
+ if (!attr || !lists || listidx >= nbr)
+ goto finish_parsing;
+
+ l = lists + listidx++;
+ l->items = mrp_allocz(sizeof(l->items[0]) * attr->nvalue);
+
+ do {
+ if (l->size >= attr->nvalue)
+ goto finish_parsing;
+ if (!(av = mrp_htbl_lookup(attr->values, value)))
+ goto finish_parsing;
+
+ iv = l->items + l->size++;
+ iv->name = value;
+ iv->value = av->integer;
+
+ } while (list_item(&p, &value));
+ }
+
+ whitespace(&p);
+
+ } /* while property */
+
+ if (attr && nbr > 0) {
+ if (type == 1) {
+ if (getline(&buf2, &n, f) < 0)
+ goto finish_parsing;
+
+ if (!tree_parse_terminal_node(conf, f,lineno,buf2, true, NULL, 0))
+ goto finish_parsing;
+
+ free(buf2);
+ buf2 = NULL;
+ nbr--;
+ if (!(ait = attr_value_iterator(attr)))
+ goto finish_parsing;
+ }
+
+ mrp_debug("%stest/%d: '%s'", indent(depth), nbr, attr->name);
+
+ if (!(*node = mrp_decision_create_test_node()))
+ goto finish_parsing;
+
+ for (i=0, buf2=NULL; i < nbr && getline(&buf2,&n,f) >= 0; i++) {
+ (*lineno)++;
+
+ switch (type) {
+
+ case 1:
+ testval_type = MRP_DECISION_VALUE_INTEGER;
+ testval.integer = ait->descs[i].value;
+ testcond = MRP_DECISION_EQ;
+ snprintf(valbuf, sizeof(valbuf), "%s", ait->descs[i].name);
+ break;
+
+ case 2:
+ break;
+
+ case 3:
+ testval_type = MRP_DECISION_VALUE_UNKNOWN;
+ l = lists + i;
+ if (l->size == 1) {
+ testcond = MRP_DECISION_EQ;
+ testval_type = MRP_DECISION_VALUE_INTEGER;
+ testval.integer = l->items[0].value;
+ snprintf(valbuf, sizeof(valbuf), "%s", l->items[0].name);
+ }
+ else {
+ testcond = MRP_DECISION_IN;
+ if (l->size <= (int)MRP_DECISION_BITMASK_WIDTH) {
+ testval_type = MRP_DECISION_VALUE_BITMASK;
+ testval.bitmask = 0;
+ }
+ else {
+ testval_type = MRP_DECISION_ARRAY |
+ MRP_DECISION_VALUE_INTEGER;
+ testval.array.size = l->size;
+ size = sizeof(mrp_decision_value_t) * testval.array.size;
+ testval.array.values = mrp_allocz(size);
+ }
+ e = (q = valbuf) + sizeof(valbuf);
+ for (j = 0; j < l->size; j++) {
+ if (q < e) {
+ q += snprintf(q, e-q, "%s%s",
+ j?",":"", l->items[j].name);
+ }
+ k = l->items[j].value;
+ if (testval_type == MRP_DECISION_VALUE_BITMASK)
+ testval.bitmask |= MRP_DECISION_BIT(k);
+ else
+ testval.array.values[j].integer = k;
+ }
+ }
+ break;
+
+ default:
+ goto finish_parsing;
+ }
+
+ switch (testval_type) {
+ case MRP_DECISION_VALUE_BITMASK:
+ snprintf(dbgbuf, sizeof(dbgbuf), " 0x%x", testval.bitmask);
+ break;
+ case MRP_DECISION_VALUE_INTEGER:
+ snprintf(dbgbuf, sizeof(dbgbuf), " %d", testval.integer);
+ break;
+ default:
+ dbgbuf[0] = 0;
+ }
+ mrp_debug("%s%s %s '%s'%s", indent(depth+1),
+ mrp_decision_condition_str(testcond),
+ mrp_decision_value_type_str(testval_type),
+ valbuf, dbgbuf);
+
+ if (!tree_parse(conf, f, lineno, buf2, &child, depth+2))
+ goto finish_parsing;
+
+ ok = mrp_decision_add_branch_to_test_node(*node, testcond, attr->id,
+ testval_type, &testval,
+ attr->offset, child);
+ if (!ok)
+ goto finish_parsing;
+
+ child = NULL;
+ if ((testval_type & MRP_DECISION_ARRAY))
+ mrp_free(testval.array.values);
+ testval_type = MRP_DECISION_VALUE_UNKNOWN;
+
+ free(buf2);
+ buf2 = NULL;
+ }
+
+ success = true;
+ }
+
+ finish_parsing:
+ if (lists) {
+ for (i = 0; i < nbr; i++)
+ free(lists[i].items);
+ mrp_free(lists);
+ }
+ if ((testval_type & MRP_DECISION_ARRAY))
+ mrp_free(testval.array.values);
+ mrp_decision_tree_destroy(child);
+ mrp_free(ait);
+ free(buf2);
+
+ return success;
+}
+
+
+
+static bool property(char **buf, char **name, char **value)
+{
+ char *p = *buf;
+ char term;
+
+ if (identifier(&p, name, &term) &&
+ term == '=' &&
+ quoted(&p, value))
+ {
+ whitespace(&p);
+ *buf = p;
+ return true;
+ }
+
+ return false;
+}
+
+static bool list_item(char **buf, char **name)
+{
+ char *p = *buf;
+
+ whitespace(&p);
+
+ if (*p++ != ',')
+ return false;
+
+ if (quoted(&p, name)) {
+ *buf = p;
+ return true;
+ }
+
+ return false;
+}
+
+
+static bool identifier(char **buf, char **id, char *term)
+{
+ char *p, *q, c;
+
+ q = *buf;
+
+ whitespace(&q);
+
+ for (p = q; (c = *p); p++) {
+ if (!isalnum(c))
+ break;
+ }
+
+ if (p == q)
+ return false;
+
+ whitespace(&p);
+ if ((*term = *p))
+ *p++ = 0;
+
+ *buf = p;
+ *id = q;
+ return true;
+}
+
+
+static bool whitespace(char **buf)
+{
+ char *p, c;
+
+ for (p = *buf; (c = *p); p++) {
+ if (c != ' ' && c != '\t' && c != '\n')
+ break;
+ }
+
+ *buf = p;
+ return true;
+}
+
+static bool quoted(char **buf, char **string)
+{
+ char *p, *q, c;
+
+ q = *buf;
+
+ whitespace(&q);
+
+ if (*q++ != '"')
+ return false;
+
+ for (p = q; (c = *p); p++) {
+ if (c < 0x20)
+ return -1;
+ if (c == '"' && p[-1] != '\\') {
+ *p++ = 0;
+ *buf = p;
+ *string = q;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+size_t mrp_decision_tree_print(mrp_decision_conf_t *conf,
+ mrp_decision_node_t *node,
+ char *buf, size_t len)
+{
+ conf_iter_t *cit;
+ char *p, *e;
+
+ e = (p = buf) + len;
+
+ if (conf && node && buf && len > 0) {
+ if (!(cit = conf_iterator(conf)))
+ p += snprintf(p, e-p, "<error>\n");
+ else {
+ p += print_node(conf, node, cit, p, e-p, NULL);
+ p += snprintf(p, e-p, "\n");
+ mrp_free(cit);
+ }
+ }
+
+ return p - buf;
+}
+
+
+static size_t print_node(mrp_decision_conf_t *conf,
+ mrp_decision_node_t *node,
+ conf_iter_t *cit,
+ char *buf, size_t len,
+ char *indent)
+{
+#define PRINT(_args...) \
+ do {if (p < e) p += snprintf(p,e-p, _args);} while(0)
+#define PRINT_VALUE(_t,_v) \
+ do {if (p < e) p += mrp_decision_value_print(_t, _v, p,e-p);} while(0)
+#define PRINT_BITMASK(_a,_m) \
+ do {if (p < e) p += print_bitmask(_a, _m, p, e-p);} while(0)
+#define PRINT_NODE(_p,_i) \
+ do {if (p < e) p += print_node(conf, (_p)->node, cit, p,e-p, _i);} while(0)
+
+ static char indent_buf[4096];
+ static char *indent_end = indent_buf + sizeof(indent_buf);
+
+ mrp_decision_root_node_t *root;
+ mrp_decision_test_node_t *test;
+ mrp_decision_terminal_node_t *term;
+ mrp_decision_branch_t *branch;
+ mrp_decision_attr_t *attr;
+ const char *attr_name;
+ int32_t value_idx;
+ attr_value_iter_t *ait;
+ char *p, *e, *new_indent;
+ int32_t decision;
+ size_t i;
+
+ if (!node || !buf)
+ return 0;
+
+ if (!indent) {
+ indent_buf[0] = 0;
+ indent = indent_buf;
+ }
+
+ e = (p = buf) + len;
+
+ switch (node->type) {
+
+ case MRP_DECISION_ROOT_NODE:
+ root = &node->root;
+ PRINT("root of %s (decision type: %s)", root->name,
+ mrp_decision_value_type_str(root->decision_value_type));
+ new_indent = indent;
+ new_indent += snprintf(indent, indent_end-indent, "\n");
+ PRINT_NODE(root, new_indent);
+ *indent = 0;
+ break;
+
+ case MRP_DECISION_TEST_NODE:
+ test = &node->test;
+
+ for (i = 0; i < test->nbranch; i++) {
+ branch = test->branches + i;
+ if (branch->value_id < 0 || branch->value_id >= cit->nattr)
+ PRINT("%s:...<invalid attribute>", indent_buf);
+ else {
+ attr = cit->attrs[branch->value_id];
+ attr_name = attr ? attr->name : "<invalid attribute>";
+ PRINT("%s:...%s %s ", indent_buf, attr_name,
+ mrp_decision_condition_str(branch->condition));
+
+ if (branch->value_type != MRP_DECISION_VALUE_INTEGER) {
+ PRINT_VALUE(branch->value_type, &branch->value);
+ if (branch->value_type == MRP_DECISION_VALUE_BITMASK) {
+ PRINT(" (");
+ PRINT_BITMASK(attr, branch->value.bitmask);
+ PRINT(")");
+ }
+ }
+ else {
+ value_idx = branch->value.integer;
+ if (value_idx < 0 || value_idx >= attr->nvalue ||
+ !(ait = attr_value_iterator(attr)))
+ PRINT("<invalid attribute value>");
+ else {
+ PRINT("%d (%s)", value_idx, ait->descs[value_idx].name);
+ mrp_free(ait);
+ }
+ }
+ }
+ new_indent = indent;
+ new_indent += snprintf(new_indent, indent_end-indent, "%c ",
+ i == test->nbranch-1 ? ' ':':');
+ PRINT_NODE(branch, new_indent);
+ *indent = 0;
+ }
+
+ break;
+
+ case MRP_DECISION_TERMINAL_NODE:
+ term = &node->terminal;
+ decision = term->decision.integer;
+ if (decision < 0 || decision >= conf->decision_attr->nvalue)
+ PRINT(" => decision <invalid value>");
+ else
+ PRINT(" => %s", conf->decision_names[decision]);
+ break;
+
+ default:
+ PRINT("%s<unknown node type %d>\n", indent_buf, node->type);
+ break;
+ }
+
+ return p - buf;
+
+#undef PRINT_VALUE
+#undef PRINT
+}
+
+
+static size_t print_bitmask(mrp_decision_attr_t *attr,
+ mrp_decision_bitmask_t bitmask,
+ char *buf, size_t len)
+{
+ attr_value_iter_t *it;
+ mrp_decision_bitmask_t m;
+ char *p, *e;
+ int i,j;
+ char *sep;
+
+ if (!attr || !buf || len < 1)
+ return 0;
+
+ if (!(it = attr_value_iterator(attr)))
+ return 0;
+
+ e = (p = buf) + len;
+
+ if (!(m = bitmask))
+ p += snprintf(p, e-p, "<empty>");
+ else {
+ for (i = 0, sep = ""; m && i < it->ndesc && p < e; i++, m >>= 1) {
+ if ((m & 1)) {
+ if (it->descs[i].value == i)
+ j = i;
+ else {
+ for (j = 0; j < it->ndesc; j++) {
+ if (it->descs[j].value == i)
+ break;
+ }
+ }
+ if (j < 0 || j >= it->ndesc)
+ p += snprintf(p, e-p, "%s<unknown value %d>", sep, j);
+ else
+ p += snprintf(p, e-p, "%s%s", sep, it->descs[j].name);
+ sep = ",";
+ }
+ }
+ }
+
+ mrp_free(it);
+
+ return p - buf;
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, 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.
+ */
+#ifndef __MRP_C5_DECISION_TREE_H__
+#define __MRP_C5_DECISION_TREE_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <murphy/common/hashtbl.h>
+
+#include "decision-tree.h"
+
+typedef enum mrp_decision_attr_type_e mrp_decision_attr_type_t;
+typedef struct mrp_decision_attr_s mrp_decision_attr_t;
+typedef struct mrp_decision_conf_s mrp_decision_conf_t;
+typedef struct mrp_decision_attr_value_desc_s mrp_decision_attr_value_desc_t;
+
+enum mrp_decision_attr_type_e {
+ MRP_DECISION_ATTR_UNKNOWN = 0,
+ MRP_DECISION_ATTR_ENUM,
+ MRP_DECISION_ATTR_CONTINUOUS,
+};
+
+struct mrp_decision_attr_s {
+ const char *name;
+ int id;
+ mrp_decision_attr_type_t attr_type;
+ mrp_decision_value_type_t value_type;
+ size_t offset;
+ int nvalue;
+ mrp_htbl_t *values;
+};
+
+
+struct mrp_decision_conf_s {
+ const char *stem;
+ int nattr;
+ mrp_htbl_t *attrs;
+ mrp_decision_attr_t *decision_attr;
+ const char **decision_names;
+};
+
+
+struct mrp_decision_attr_value_desc_s {
+ const char *name;
+ int32_t value;
+};
+
+
+mrp_decision_conf_t *mrp_decision_conf_create_from_file(const char *stem);
+void mrp_decision_conf_destroy(mrp_decision_conf_t *conf);
+
+bool mrp_decision_set_attr_offset(mrp_decision_conf_t *conf,
+ const char *attr_name, size_t offset);
+
+ssize_t mrp_decision_attr_list(mrp_decision_conf_t *conf,
+ const char **buf, size_t len);
+ssize_t mrp_decision_attr_value_list(mrp_decision_conf_t *conf,
+ const char *attr_name,
+ mrp_decision_attr_value_desc_t *buf,
+ size_t len);
+
+const char *mrp_decision_name(mrp_decision_conf_t *conf, int32_t decision);
+int32_t mrp_decision_value_max(mrp_decision_conf_t *conf);
+
+int32_t mrp_decision_get_integer_attr_value(mrp_decision_conf_t *conf,
+ const char *attr_name,
+ const char *value_name,
+ bool *error);
+const char *mrp_decision_get_integer_attr_name(mrp_decision_conf_t *conf,
+ const char *attr_name,
+ int32_t value,
+ bool *error);
+
+size_t mrp_decision_conf_print(mrp_decision_conf_t *conf,char *buf,size_t len);
+
+mrp_decision_node_t *mrp_decision_tree_create_from_file(
+ mrp_decision_conf_t *conf,
+ const char *stem);
+
+size_t mrp_decision_tree_print(mrp_decision_conf_t *conf,
+ mrp_decision_node_t *node,
+ char *buf, size_t len);
+
+#endif /* __MRP_C5_DECISION_TREE_H__ */
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "decision-maker.h"
+
+#define CONN_STATE_MASK \
+ (((decision_t)1 << CONN_STATE_BITS) - 1)
+
+#define KEY(_priority,_stamp) \
+ ((_stamp) ? ((((_priority) & 0xff) << 8) | \
+ ((_stamp) & 0xff) ) \
+ : 0)
+
+typedef uint32_t list_key_t;
+
+typedef struct {
+ list_key_t key;
+ entry_t entry;
+ state_t new_state;
+} list_t;
+
+
+static const char *conn_state_names[CONN_STATE_MAX] = {
+ [teardown] = "teardown",
+ [disconnected] = "disconnected",
+ [connected] = "connected",
+ [suspended] = "suspended",
+};
+
+
+static uint32_t source_priority [SOURCE_MAX] = {
+ [wrtApplication] = 1,
+ [icoApplication] = 1,
+ [phoneSource] = 3,
+ [radio] = 1,
+ [microphone] = 3,
+ [navigator] = 2,
+};
+
+static bool mutually_exclusive[SOURCE_MAX][SOURCE_MAX] = {
+ [wrtApplication][icoApplication] = true,
+ [wrtApplication][radio] = true,
+
+ [icoApplication][wrtApplication] = true,
+ [icoApplication][radio] = true,
+
+ [radio][wrtApplication] = true,
+ [radio][icoApplication] = true,
+};
+
+static decision_t set_decision_for_source(source_t source, conn_state_t state)
+{
+ decision_t decision;
+
+ if (source < 0 || source >= SOURCE_MAX)
+ decision = 0;
+ else
+ decision = (((decision_t)state) & CONN_STATE_MASK) <<
+ (source * CONN_STATE_BITS);
+ return decision;
+}
+
+#if 0
+static conn_state_t get_decision_for_source(source_t source, decision_t decision)
+{
+ conn_state_t state;
+
+ if (source < 0 || source >= SOURCE_MAX)
+ state = 0;
+ else
+ state = (decision >> (source * CONN_STATE_BITS)) & CONN_STATE_MASK;
+
+ return state;
+}
+#endif
+
+static void sort_list(list_t *list)
+{
+ list_t tmp;
+ int i,j;
+
+ for (i = 0; i < SOURCE_MAX-1; i++) {
+ for (j = i+1; j < SOURCE_MAX; j++) {
+ if (list[j].key > list[i].key) {
+ tmp = list[j];
+ list[j] = list[i];
+ list[i] = tmp;
+ }
+ }
+ }
+}
+
+
+static void build_sorted_list(entry_t *usecase, list_t *list)
+{
+ list_t *l;
+ stamp_t stamp;
+ uint32_t priority;
+ int i;
+
+ for (i = 0; i < SOURCE_MAX; i++) {
+ stamp = ENTRY_STAMP(usecase[i]);
+ priority = source_priority[i];
+
+ l = list + i;
+
+ l->key = KEY(priority, stamp);
+ l->entry = usecase[i];
+ }
+
+ sort_list(list);
+}
+
+static bool routing_conflict(list_t *list, int i)
+{
+ entry_t entry = list[i].entry;
+ entry_t e;
+ int j;
+
+ if (ENTRY_STAMP(entry) > 0) {
+ for (j = 0; j < i; j++) {
+ e = ENTRY_CONNECTION(list[j].entry);
+
+ if (route_conflicts(entry, e))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool rule_conflict(list_t *list, int i)
+{
+ entry_t entry = list[i].entry;
+ stamp_t stamp = ENTRY_STAMP(entry);
+ conn_t conn = ENTRY_CONNECTION(entry);
+ source_t source = CONNECTION_SOURCE(conn);
+ entry_t e;
+ conn_t c;
+ source_t s;
+ int j;
+
+ if (stamp > 0) {
+ for (j = 0; j < i; j++) {
+ e = list[j].entry;
+ c = ENTRY_CONNECTION(e);
+ s = CONNECTION_SOURCE(c);
+
+ if (ENTRY_STAMP(e) > 0 && list[j].new_state == play) {
+ if (mutually_exclusive[source][s])
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+
+
+static conn_state_t determine_connection_state(list_t *list, int i)
+{
+ entry_t entry;
+ conn_t conn;
+ sink_t sink;
+ conn_state_t ct;
+
+ entry = list[i].entry;
+ ct = teardown;
+
+ if (ENTRY_STAMP(entry) > 0) {
+ conn = ENTRY_CONNECTION(entry);
+ sink = CONNECTION_SINK(conn);
+
+ if (sink == noroute)
+ ct = disconnected;
+ else if (routing_conflict(list, i))
+ ct = disconnected;
+ else if (rule_conflict(list, i))
+ ct = suspended;
+ else
+ ct = connected;
+
+ }
+
+ return ct;
+}
+
+
+decision_t make_decision(entry_t *usecase, source_t source, int max_active)
+{
+ decision_t decision;
+ list_t list[SOURCE_MAX];
+ entry_t entry;
+ conn_t conn;
+ source_t idx;
+ stamp_t stamp;
+ conn_state_t ct;
+ int active;
+ int i;
+
+ build_sorted_list(usecase, list);
+ decision = 0;
+ active = 0;
+
+ for (i = 0; i < SOURCE_MAX; i++) {
+ entry = list[i].entry;
+ stamp = ENTRY_STAMP(entry);
+ conn = ENTRY_CONNECTION(entry);
+ idx = CONNECTION_SOURCE(conn);
+
+ if (active >= max_active || !stamp)
+ ct = teardown;
+ else {
+ ct = determine_connection_state(list, i);
+ active++;
+ }
+
+ if (source == allSources)
+ decision |= set_decision_for_source(idx, ct);
+ else if (source == idx) {
+ decision = ct;
+ break;
+ }
+
+ list[i].new_state = (ct == connected) ? play : stop;
+ } /* for */
+
+#if 0
+ for (i=0; i<SOURCE_MAX; i++) {
+ entry = list[i].entry;
+ conn = ENTRY_CONNECTION(entry);
+ printf("[0x%x %d %s -> %s %s] ",
+ list[i].key,
+ ENTRY_STAMP(entry),
+ get_source_name(CONNECTION_SOURCE(conn)),
+ get_sink_name(CONNECTION_SINK(conn)),
+ ENTRY_STATE(entry) ? "play":"stop");
+ }
+ printf("=> %u\n", decision);
+#endif
+
+ return decision;
+}
+
+size_t print_decision(decision_t decision, source_t source, char *buf, size_t len)
+{
+ size_t l;
+
+ if (source == allSources)
+ l = snprintf(buf, len, "%u", decision);
+ else
+ l = snprintf(buf, len, "%s", get_conn_state_name(decision));
+
+ return l;
+}
+
+const char *get_conn_state_name(conn_state_t ct)
+{
+ if (ct < 0 || ct >= CONN_STATE_MAX)
+ return "<unknown>";
+ return conn_state_names[ct];
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, 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.
+ */
+#ifndef __MRP_DECISION_MAKER_H__
+#define __MRP_DECISION_MAKER_H__
+
+#include "pattern-generator.h"
+
+#define CONN_STATE_BITS 2
+
+typedef enum {
+ teardown = 0, /* 0 */
+ disconnected, /* 1 */
+ connected, /* 2 */
+ suspended, /* 3 */
+
+ CONN_STATE_MAX /* expected to be 4 */
+} conn_state_t;
+
+
+typedef uint32_t decision_t;
+
+decision_t make_decision(entry_t *usecase, source_t source, int max_active);
+size_t print_decision(decision_t decision, source_t source,
+ char *buf, size_t len);
+
+const char *get_conn_state_name(conn_state_t ct);
+
+
+#endif /* __MRP_DECISION_MAKER_H__ */
--- /dev/null
+/*
+ * Copyright (c) 2014, 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 <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <ctype.h>
+
+#include <murphy/common.h>
+#include <breedline/breedline-murphy.h>
+
+#include "decision-tree.h"
+#include "c5-decision-tree.h"
+
+#define INVALID_OFFSET (~(size_t)0)
+
+typedef struct {
+ int32_t route;
+ int32_t stamp;
+ int32_t state;
+} source_attr_t;
+
+typedef struct {
+ source_attr_t wrtApplication;
+ source_attr_t icoApplication;
+ source_attr_t phone;
+ source_attr_t radio;
+ source_attr_t microphone;
+ source_attr_t navigator;
+} usecase_vector_t;
+
+typedef struct {
+ const char *name;
+ size_t offset;
+} offset_def_t;
+
+typedef struct {
+ const char *name;
+ size_t stamp_offset;
+ size_t route_offset;
+ size_t state_offset;
+ mrp_decision_conf_t *conf;
+ mrp_decision_tree_t *tree;
+ struct {
+ int32_t value;
+ const char *str;
+ bool valid;
+ int32_t stamp;
+ int32_t state;
+ } decision;
+} source_t;
+
+typedef struct {
+ const char *prognam;
+ int max_active;
+ mrp_mainloop_t *ml;
+ brl_t *brl;
+ int nsource;
+ source_t *sources;
+ mrp_decision_conf_t *default_conf;
+ usecase_vector_t usecase;
+} user_data_t;
+
+
+#define OFFSET_DEF(_src,_attr,_fld) \
+ { # _src #_attr, MRP_OFFSET(usecase_vector_t, _src._fld) }
+#define LIST_END \
+ { NULL, 0 }
+#define SOURCE(_src) \
+ OFFSET_DEF(_src, Route, route), \
+ OFFSET_DEF(_src, Stamp, stamp), \
+ OFFSET_DEF(_src, State, state)
+
+static offset_def_t offset_defs[] = {
+ SOURCE( wrtApplication ),
+ SOURCE( icoApplication ),
+ SOURCE( phone ),
+ SOURCE( radio ),
+ SOURCE( microphone ),
+ SOURCE( navigator ),
+ LIST_END
+};
+
+#undef SOURCE
+#undef LIST_END
+#undef OFFSET_DEF
+
+
+static bool whitespace(char **buf)
+{
+ char *p, *q, c;
+
+ for (p = q = *buf; (c = *p); p++) {
+ if (c != ' ' && c != '\t' && c != '\n')
+ break;
+ }
+
+ *buf = p;
+
+ return *p == 0 || p > q;
+}
+
+static bool identifier(char **buf, char *id, size_t len)
+{
+ char *p = *buf;
+ char *q, *e, c;
+
+ whitespace(&p);
+
+ if (!isalpha(*(q = p)))
+ return false;
+
+ while ((c = *p)) {
+ if (c == ' ' || c == '\t' || c == '\n')
+ break;
+ if (!isalnum(c) && c != '_' && c != '-')
+ return false;
+ p++;
+ }
+
+ if (p > q && (p-q) < ((int)len-1)) {
+ e = p;
+
+ if (whitespace(&p)) {
+ strncpy(id, q, (e-q));
+ id[(e-q)] = 0;
+
+ *buf = p;
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool integer(char **buf, int32_t *integer, char *string, size_t len)
+{
+ char *p = *buf;
+ char *e;
+ size_t l;
+
+ whitespace(&p);
+
+
+ *integer = strtol(p, &e, 10);
+
+ if (e > p) {
+ l = e - p;
+
+ if (whitespace(&e)) {
+ if (string && len > 0 && len >= l) {
+ strncpy(string, p, l);
+ string[l] = 0;
+ }
+
+ *buf = e;
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+static bool token(char **buf, const char *tkn)
+{
+ char *p = *buf;
+ size_t l = strlen(tkn);
+
+ whitespace(&p);
+
+ if (!strncmp(p, tkn, l)) {
+ p += l;
+ if (whitespace(&p)) {
+ *buf = p;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool end_of_line(char **buf)
+{
+ char *p = *buf;
+
+ if (whitespace(&p) && *p == 0) {
+ *buf = p;
+ return true;
+ }
+
+ return false;
+}
+
+static source_t *find_source(user_data_t *ud, const char *srcnam)
+{
+ source_t *src;
+ int i;
+
+ for (i = 0; i < ud->nsource; i++) {
+ src = ud->sources + i;
+
+ if (!strcmp(srcnam, src->name))
+ return(src);
+ }
+
+ return NULL;
+}
+
+static size_t find_offset(user_data_t *ud, const char *attrnam)
+{
+ offset_def_t *d;
+
+ MRP_UNUSED(ud);
+
+ for (d = offset_defs; (d->name); d++) {
+ if (!strcmp(attrnam, d->name))
+ return d->offset;
+ }
+
+ return INVALID_OFFSET;
+}
+
+
+static void show_conf(user_data_t *ud, const char *srcnam)
+{
+ source_t *src;
+ char buf[32768];
+
+ brl_hide_prompt(ud->brl);
+
+ if (!(src = find_source(ud, srcnam)))
+ printf("don't know anything about '%s' source\n", srcnam);
+ else {
+ mrp_decision_conf_print(src->conf, buf, sizeof(buf));
+ printf("\n%s\n", buf);
+ }
+
+ brl_show_prompt(ud->brl);
+}
+
+static void show_tree(user_data_t *ud, const char *srcnam)
+{
+ source_t *src;
+ char buf[32768];
+
+ brl_hide_prompt(ud->brl);
+
+ if (!(src = find_source(ud, srcnam)))
+ printf("don't know anything about '%s' source\n", srcnam);
+ else {
+ mrp_decision_tree_print(src->conf, src->tree, buf, sizeof(buf));
+ printf("\n%s\n", buf);
+ }
+
+ brl_show_prompt(ud->brl);
+}
+
+static void show_usecase(user_data_t *ud)
+{
+ mrp_decision_conf_t *conf;
+ usecase_vector_t *usecase;
+ offset_def_t *d;
+ int32_t value;
+ const char *vnam;
+ char buf[256];
+
+ brl_hide_prompt(ud->brl);
+
+ if (!(conf = ud->default_conf))
+ printf("\ncan't find any valid source configuration\n\n");
+ else {
+ printf("\n");
+
+ usecase = &ud->usecase;
+
+ for (d = offset_defs; (d->name); d++) {
+ if ((d - offset_defs) && !((d - offset_defs) % 3))
+ printf("\n");
+
+ value = *(int32_t *)((char *)usecase + d->offset);
+ vnam = mrp_decision_get_integer_attr_name(conf, d->name,value, NULL);
+
+ snprintf(buf, sizeof(buf), "%s:", d->name);
+ printf("%-24s %d (%s)\n", buf, value, vnam);
+ }
+
+ printf("\n");
+ }
+
+ brl_show_prompt(ud->brl);
+}
+
+
+static void show_sources(user_data_t *ud)
+{
+ int i;
+
+ brl_hide_prompt(ud->brl);
+
+ printf("\n");
+
+ if (ud->nsource <= 0)
+ printf("<no source available>\n");
+ else {
+ for (i = 0; i < ud->nsource; i++)
+ printf("%s\n", ud->sources[i].name);
+ }
+
+ printf("\n");
+
+ brl_show_prompt(ud->brl);
+}
+
+
+static void show_help(user_data_t *ud)
+{
+ brl_hide_prompt(ud->brl);
+ printf("\nAvailable commands:\n"
+ " show usecase\n"
+ " show sources\n"
+ " show <source> {conf|tree}\n"
+ " set <source> {route|stamp|state} <value>\n"
+ " set * {route|state} <value>\n"
+ " decide\n"
+ " shift stamps <value>\n"
+ " reset stamps\n"
+ " normalise\n"
+ " apply\n"
+ " exit\n\n");
+
+ brl_show_prompt(ud->brl);
+}
+
+static void show_cmd(user_data_t *ud, const char *cmd)
+{
+ char *p = (char *)cmd;
+ char srcnam[256];
+
+ if (whitespace(&p)) {
+ if (token (&p, "usecase") &&
+ end_of_line (&p ) )
+ {
+ show_usecase(ud);
+ return;
+ }
+ else if (token (&p, "sources") &&
+ end_of_line (&p ) )
+ {
+ show_sources(ud);
+ return;
+ }
+ else if (identifier (&p, srcnam, sizeof(srcnam))) {
+ if (token (&p, "conf") &&
+ end_of_line (&p ) )
+ {
+ show_conf(ud, srcnam);
+ return;
+ }
+ else if (token (&p, "tree") &&
+ end_of_line (&p ) )
+ {
+ show_tree(ud, srcnam);
+ return;
+ }
+ }
+ }
+
+ brl_hide_prompt(ud->brl);
+ printf("\nSyntax error. syntax of 'show' command:\n"
+ " show usecase\n"
+ " show sources\n"
+ " show <source> {conf|tree}\n\n");
+ brl_show_prompt(ud->brl);
+}
+
+
+static void set_usecase_attribute(user_data_t *ud, const char *srcnam,
+ const char *attrnam, const char *attrval)
+{
+ source_t *src;
+ int32_t value;
+ size_t offset;
+ char fullnam[256];
+ bool error;
+
+ brl_hide_prompt(ud->brl);
+
+ if (!(src = find_source(ud, srcnam)))
+ printf("don't know anything about '%s' source\n", srcnam);
+ else {
+ snprintf(fullnam, sizeof(fullnam), "%s%s", srcnam, attrnam);
+ value = mrp_decision_get_integer_attr_value(src->conf, fullnam,
+ attrval, &error);
+ offset = find_offset(ud, fullnam);
+
+ if (error || offset == INVALID_OFFSET)
+ printf("invalid attribute '%s' or value '%s'\n", fullnam, attrval);
+ else
+ *(int32_t *)((char *)&ud->usecase + offset) = value;
+ }
+
+ brl_show_prompt(ud->brl);
+}
+
+static void set_cmd(user_data_t *ud, const char *cmd)
+{
+ char *p = (char *)cmd;
+ char srcnam[256];
+ char attrval[256];
+ int32_t stamp;
+ int i;
+
+
+ if (whitespace (&p)) {
+ if (token(&p, "*")) {
+ if (token (&p, "route" ) &&
+ identifier (&p, attrval, sizeof(attrval)) &&
+ end_of_line (&p ) )
+ {
+ for (i = 0; i < ud->nsource; i++) {
+ set_usecase_attribute(ud, ud->sources[i].name,
+ "Route", attrval);
+ }
+ return;
+ }
+ if (token (&p, "state" ) &&
+ identifier (&p, attrval, sizeof(attrval)) &&
+ end_of_line (&p ) )
+ {
+ for (i = 0; i < ud->nsource; i++) {
+ set_usecase_attribute(ud, ud->sources[i].name,
+ "State", attrval);
+ }
+ return;
+ }
+ }
+ if (identifier (&p, srcnam, sizeof(srcnam))) {
+ if (token (&p, "route" ) &&
+ identifier (&p, attrval, sizeof(attrval)) &&
+ end_of_line (&p ) )
+ {
+ set_usecase_attribute(ud, srcnam, "Route", attrval);
+ return;
+ }
+ if (token (&p, "stamp" ) &&
+ integer (&p, &stamp, attrval, sizeof(attrval)) &&
+ end_of_line (&p ) )
+ {
+ set_usecase_attribute(ud, srcnam, "Stamp", attrval);
+ return;
+ }
+ if (token (&p, "state" ) &&
+ identifier (&p, attrval, sizeof(attrval)) &&
+ end_of_line (&p ) )
+ {
+ set_usecase_attribute(ud, srcnam, "State", attrval);
+ return;
+ }
+ }
+ }
+
+ brl_hide_prompt(ud->brl);
+ printf("\nSyntax error. syntax of 'set' command:\n"
+ " set <source> {route|stamp|state} <value>\n"
+ " set * {route|state} <value>\n\n");
+ brl_show_prompt(ud->brl);
+}
+
+
+static void decide(user_data_t *ud)
+{
+ mrp_decision_value_type_t type;
+ mrp_decision_value_t *decision;
+ source_t *src;
+ mrp_decision_conf_t *conf;
+ int32_t stop, pause, play;
+ size_t offs;
+ char buf[256];
+ int i;
+
+
+ for (i = 0; i < ud->nsource; i++) {
+ src = ud->sources + i;
+ conf = src->conf;
+
+ snprintf(buf, sizeof(buf), "%sState", src->name);
+
+ stop = mrp_decision_get_integer_attr_value(conf, buf, "stop", NULL);
+ pause = mrp_decision_get_integer_attr_value(conf, buf, "pause", NULL);
+ play = mrp_decision_get_integer_attr_value(conf, buf, "play", NULL);
+
+ if (!mrp_decision_make(src->tree, &ud->usecase, &type, &decision)) {
+ src->decision.value = 0;
+ src->decision.str = "<failed>";
+ src->decision.valid = false;
+ }
+ else {
+ src->decision.value = decision->integer;
+ src->decision.str = mrp_decision_name(src->conf, decision->integer);
+ src->decision.valid = true;
+
+ offs = src->stamp_offset;
+ src->decision.stamp = *(int32_t *)((char *)&ud->usecase + offs);
+
+ if (!strcmp(src->decision.str, "disconnected"))
+ src->decision.state = stop;
+ else if (!strcmp(src->decision.str, "connected"))
+ src->decision.state = play;
+ else if (!strcmp(src->decision.str, "suspended"))
+ src->decision.state = pause;
+ else {
+ src->decision.stamp = 0;
+ src->decision.state = stop;
+ }
+ }
+ } /* for */
+}
+
+static void decide_cmd(user_data_t *ud, const char *cmd)
+{
+ source_t *src;
+ bool stamp_error;
+ size_t ioffs, joffs;
+ int32_t istamp, jstamp, stamp_max;
+ uint32_t stamp_mask, full_mask;
+ int32_t new_stamp, new_state;
+ int32_t old_stamp, old_state;
+ char nambuf[256];
+ char valbuf[256];
+ char statebuf[256];
+ char stampbuf[256];
+ const char *old_name, *new_name;
+ int i,j;
+ bool ok;
+
+ MRP_UNUSED(cmd);
+
+ brl_hide_prompt(ud->brl);
+
+
+ if (ud->nsource < 1)
+ printf("\nthere are no valid sources\n\n");
+ else {
+ printf("\n");
+
+ stamp_error = false;
+ stamp_mask = 0;
+ stamp_max = 0;
+
+ for (i = 0; i < ud->nsource; i++) {
+ ioffs = ud->sources[i].stamp_offset;
+ istamp = *(int32_t *)((char *)&ud->usecase + ioffs);
+
+ if (istamp > 0) {
+ if (istamp > stamp_max)
+ stamp_max = istamp;
+
+ stamp_mask |= (uint32_t)1 << (istamp - 1);
+ }
+
+ for (j = i + 1; j < ud->nsource; j++) {
+ joffs = ud->sources[j].stamp_offset;
+ jstamp = *(int32_t *)((char *)&ud->usecase + joffs);
+
+ if (istamp > 0 && istamp == jstamp) {
+ printf("stamp %d occurs multiple times\n", istamp);
+ stamp_error = true;
+ }
+ }
+ }
+
+ if (stamp_max > 0) {
+ full_mask = ((uint32_t)1 << stamp_max) - 1;
+
+ if (stamp_mask != full_mask) {
+ printf("stamps are not continuous\n");
+ stamp_error = true;
+ }
+ }
+
+
+ if (!stamp_error) {
+ decide(ud);
+
+ for (i = 0; i < ud->nsource; i++) {
+ src = ud->sources + i;
+
+ old_stamp = *(int32_t*)((char*)&ud->usecase+src->stamp_offset);
+ old_state = *(int32_t*)((char*)&ud->usecase+src->state_offset);
+
+ new_state = src->decision.state;
+ new_stamp = src->decision.stamp;
+
+ statebuf[0] = 0;
+ stampbuf[0] = 0;
+
+ if (src->decision.valid && old_state != new_state) {
+ snprintf(nambuf, sizeof(nambuf), "%sState", src->name);
+ old_name = mrp_decision_get_integer_attr_name(src->conf,
+ nambuf,
+ old_state,
+ &ok);
+ new_name = mrp_decision_get_integer_attr_name(src->conf,
+ nambuf,
+ new_state,
+ &ok);
+ snprintf(statebuf, sizeof(statebuf), "%d (%s) => %d (%s)",
+ old_state, old_name, new_state, new_name);
+ }
+
+ if (src->decision.valid && old_stamp != new_stamp) {
+ snprintf(stampbuf, sizeof(stampbuf),"%d => %d",
+ old_stamp, new_stamp);
+ }
+
+ snprintf(nambuf, sizeof(nambuf), "%s:",
+ src->name);
+ snprintf(valbuf, sizeof(valbuf), "%d (%s)",
+ src->decision.value, src->decision.str);
+
+ printf("%-24s %-18s %-24s %s\n",
+ nambuf, valbuf, statebuf, stampbuf);
+ }
+ }
+
+ printf("\n");
+ }
+
+ brl_show_prompt(ud->brl);
+}
+
+
+static void shift_cmd(user_data_t *ud, const char *cmd)
+{
+ char *p = (char *)cmd;
+ int32_t shift;
+ size_t stamp_offset;
+ int32_t *stamp_ptr;
+ int32_t stamp;
+ int i;
+
+ if (ud->max_active < 2) {
+ brl_hide_prompt(ud->brl);
+ printf("\nshift is not allowed if maximum 1 stream can be active\n\n");
+ brl_show_prompt(ud->brl);
+ }
+ else {
+ if (whitespace (&p ) &&
+ token (&p, "stamps" ) &&
+ integer (&p, &shift, NULL,0) &&
+ end_of_line (&p ) )
+ {
+ if (shift > -ud->max_active &&
+ shift != 0 &&
+ shift < ud->max_active )
+ {
+ for (i = 0; i < ud->nsource; i++) {
+ stamp_offset = ud->sources[i].stamp_offset;
+ stamp_ptr = (int32_t*)((char*)&ud->usecase + stamp_offset);
+
+ if ((stamp = *stamp_ptr) > 0) {
+ stamp += shift;
+
+ if (stamp < 0 || stamp > ud->max_active)
+ stamp = 0;
+
+ *stamp_ptr = stamp;
+ }
+ } /* for */
+
+ show_usecase(ud);
+
+ return;
+ }
+ }
+ }
+
+ brl_hide_prompt(ud->brl);
+ printf("\nSyntax error. syntax of 'shift' command:\n"
+ " shift stamps <value>\n"
+ "where\n"
+ " <value> should be in the range of [%-d:-1] or [1:%d]\n\n",
+ -(ud->max_active - 1), (ud->max_active - 1));
+ brl_show_prompt(ud->brl);
+}
+
+static void reset_cmd(user_data_t *ud, const char *cmd)
+{
+ char *p = (char *)cmd;
+ size_t stamp_offset;
+ int32_t *stamp_ptr;
+ int i;
+
+ if (whitespace (&p ) &&
+ token (&p, "stamps" ) &&
+ end_of_line (&p ) )
+ {
+ for (i = 0; i < ud->nsource; i++) {
+ stamp_offset = ud->sources[i].stamp_offset;
+ stamp_ptr = (int32_t*)((char*)&ud->usecase + stamp_offset);
+
+ *stamp_ptr = 0;
+ }
+
+ show_usecase(ud);
+
+ return;
+ }
+
+ brl_hide_prompt(ud->brl);
+ printf("\nSyntax error. syntax of 'reset' command:\n"
+ " reset stamps\n\n");
+ brl_show_prompt(ud->brl);
+}
+
+static void normalise(user_data_t *ud)
+{
+ source_t *src;
+ size_t route_offset, stamp_offset, state_offset;
+ int32_t *route_ptr, *stamp_ptr, *state_ptr;
+ int nptr;
+ int32_t *ptrs[ud->nsource];
+ int32_t *tmp;
+ int i, j;
+
+ for (nptr = 0, i = 0; i < ud->nsource; i++) {
+ src = ud->sources + i;
+
+ route_offset = src->route_offset;
+ stamp_offset = src->stamp_offset;
+ state_offset = src->state_offset;
+
+ route_ptr = (int32_t *)((char *)&ud->usecase + route_offset);
+ stamp_ptr = (int32_t *)((char *)&ud->usecase + stamp_offset);
+ state_ptr = (int32_t *)((char *)&ud->usecase + state_offset);
+
+ if (*stamp_ptr > 0)
+ ptrs[nptr++] = stamp_ptr;
+ else {
+ *route_ptr = 0;
+ *stamp_ptr = 0;
+ *state_ptr = 0;
+ }
+ }
+
+ for (i = 0; i < nptr-1; i++) {
+ for (j = i + 1; j < nptr; j++) {
+ if (*(ptrs[i]) > *(ptrs[j])) {
+ tmp = ptrs[i];
+ ptrs[i] = ptrs[j];
+ ptrs[j] = tmp;
+ }
+ }
+ }
+
+ for (i = 0; i < nptr; i++)
+ *(ptrs[i]) = i+1;
+}
+
+static void normalise_cmd(user_data_t *ud, const char *cmd)
+{
+ char *p = (char *)cmd;
+
+ if (end_of_line (&p)) {
+ normalise(ud);
+
+ show_usecase(ud);
+
+ return;
+ }
+
+ brl_hide_prompt(ud->brl);
+ printf("\nSyntax error. syntax of 'normalise' command:\n"
+ " normalise\n\n");
+ brl_show_prompt(ud->brl);
+}
+
+static void apply_cmd(user_data_t *ud, const char *cmd)
+{
+ char *p = (char *)cmd;
+ source_t *src;
+ int32_t *stamp_ptr, *state_ptr;
+ int i, n;
+
+ if (end_of_line (&p)) {
+ for (n = i = 0; i < ud->nsource; i++) {
+ src = ud->sources + i;
+
+ if (src->decision.valid) {
+ src->decision.valid = false;
+
+ stamp_ptr = (int32_t*)((char*)&ud->usecase + src->stamp_offset);
+ state_ptr = (int32_t*)((char*)&ud->usecase + src->state_offset);
+
+ if (*stamp_ptr != src->decision.stamp) {
+ *stamp_ptr = src->decision.stamp;
+ n++;
+ }
+
+ if (*state_ptr != src->decision.state) {
+ *state_ptr = src->decision.state;
+ n++;
+ }
+ }
+ }
+
+ if (n == 0) {
+ brl_hide_prompt(ud->brl);
+ printf("\nnothing has been changed\n\n");
+ brl_show_prompt(ud->brl);
+ }
+ else {
+ normalise(ud);
+ show_usecase(ud);
+ }
+
+ return;
+ }
+
+ brl_hide_prompt(ud->brl);
+ printf("\nSyntax error. syntax of 'apply' command:\n"
+ " apply\n\n");
+ brl_show_prompt(ud->brl);
+}
+
+static void input_handler(brl_t *brl, const char *input, void *user_data)
+{
+ user_data_t *ud = (user_data_t *)user_data;
+
+ MRP_UNUSED(brl);
+
+ brl_add_history(ud->brl, input);
+
+ if (input == NULL || !strcmp(input, "exit")) {
+ mrp_mainloop_quit(ud->ml, 0);
+ return;
+ }
+
+ if (strlen(input) == 0)
+ return;
+
+ if (!strcmp(input, "help")) {
+ show_help(ud);
+ }
+ else if (!strncmp(input, "set", 3)) {
+ set_cmd(ud, input+3);
+ }
+ else if (!strncmp(input, "show", 4)) {
+ show_cmd(ud, input+4);
+ }
+ else if (!strncmp(input, "decide", 6)) {
+ decide_cmd(ud, input+4);
+ }
+ else if (!strncmp(input, "shift", 5)) {
+ shift_cmd(ud, input+5);
+ }
+ else if (!strncmp(input, "reset", 5)) {
+ reset_cmd(ud, input+5);
+ }
+ else if (!strncmp(input, "normalise", 9)) {
+ normalise_cmd(ud, input+9);
+ }
+ else if (!strncmp(input, "apply", 5)) {
+ apply_cmd(ud, input+5);
+ }
+ else {
+ show_help(ud);
+ }
+}
+
+
+static void signal_handler(mrp_sighandler_t *h, int signum, void *user_data)
+{
+ mrp_mainloop_t *ml = mrp_get_sighandler_mainloop(h);
+
+ MRP_UNUSED(user_data);
+
+ switch (signum) {
+ case SIGINT:
+ printf("Got SIGINT\n");
+ if (ml != NULL)
+ mrp_mainloop_quit(ml, 0);
+ else
+ exit(0);
+ break;
+ }
+}
+
+static void input_create(user_data_t *ud, const char *prompt)
+{
+ if (!(ud->ml = mrp_mainloop_create())) {
+ printf("failed to create mainloop\n");
+ exit(1);
+ }
+
+ mrp_add_sighandler(ud->ml, SIGINT, signal_handler, NULL);
+
+ ud->brl = brl_create_with_murphy(fileno(stdin), prompt, ud->ml,
+ input_handler, ud);
+ if (!ud->brl) {
+ printf("failed to create breedline\n");
+ exit(1);
+ }
+
+ brl_show_prompt(ud->brl);
+}
+
+static void input_destroy(user_data_t *ud)
+{
+ if (ud) {
+ if (ud->brl)
+ brl_destroy(ud->brl);
+ if (ud->ml)
+ mrp_mainloop_destroy(ud->ml);
+ }
+}
+
+static void input_process(user_data_t *ud)
+{
+ if (ud && ud->ml)
+ mrp_mainloop_run(ud->ml);
+}
+
+static void sources_create(user_data_t *ud, const char *prefix)
+{
+ mrp_decision_conf_t *conf;
+ mrp_decision_tree_t *tree;
+ offset_def_t *d1, *d2;
+ source_t *src;
+ char srcnam[256];
+ size_t srcnamlen;
+ char stem[1024];
+ size_t offset;
+ char *p;
+ size_t dlen;
+ int idx;
+ size_t size;
+ int i;
+ int errcnt;
+
+ memset(srcnam, 0, sizeof(srcnam));
+
+ conf = NULL;
+ tree = NULL;
+
+ for (srcnamlen = 0, d1 = offset_defs; (d1->name); d1++) {
+
+ offset = d1->offset;
+
+ if ((p = strstr(d1->name, "Route"))) {
+ dlen = p - d1->name;
+
+ if (dlen >= sizeof(srcnam) - 1) {
+ printf("skipping source with too long name\n");
+ continue;
+ }
+
+ if (srcnamlen == dlen && !strncmp(srcnam, d1->name, dlen))
+ continue;
+
+ /* seems to be new source name */
+ srcnamlen = dlen;
+
+ strncpy(srcnam, d1->name, dlen);
+ srcnam[dlen] = 0;
+
+ if (prefix) {
+ snprintf(stem, sizeof(stem), "%s-%s-%d",
+ prefix, srcnam, ud->max_active);
+ }
+ else {
+ snprintf(stem, sizeof(stem), "%s-%d",
+ srcnam, ud->max_active);
+ }
+
+
+ if (!(conf = mrp_decision_conf_create_from_file(stem)))
+ goto failed;
+
+ for (errcnt = 0, d2 = offset_defs; d2->name; d2++) {
+ if (!mrp_decision_set_attr_offset(conf, d2->name, d2->offset)) {
+ errcnt++;
+ printf("failed to set offset of '%s' for source %s\n",
+ d2->name, srcnam);
+ }
+ }
+
+ if (errcnt > 0)
+ goto failed;
+
+ if (!(tree = mrp_decision_tree_create_from_file(conf, NULL)))
+ goto failed;
+
+ idx = ud->nsource++;
+ size = sizeof(source_t) * ud->nsource;
+
+ if (!(ud->sources = mrp_realloc(ud->sources, size))) {
+ printf("failed to (re)allocate memory for %s source", srcnam);
+ ud->nsource = 0;
+ goto failed;
+ }
+
+ src = ud->sources + idx;
+
+ memset(src, 0, sizeof(source_t));
+ src->name = mrp_strdup(srcnam);
+ src->route_offset = offset;
+ src->conf = conf;
+ src->tree = tree;
+
+ if (!ud->default_conf)
+ ud->default_conf = conf;
+
+ conf = NULL;
+ tree = NULL;
+
+ continue;
+
+ failed:
+ if (tree) {
+ mrp_decision_tree_destroy(tree);
+ tree = NULL;
+ }
+ if (conf) {
+ mrp_decision_conf_destroy(conf);
+ conf = NULL;
+ }
+ } /* if Route */
+ else if ((p = strstr(d1->name, "Stamp"))) {
+ dlen = p - d1->name;
+
+ for (i = 0; i < ud->nsource; i++) {
+ src = ud->sources + i;
+ if (!strncmp(src->name, d1->name, dlen)) {
+ src->stamp_offset = offset;
+ break;
+ }
+ }
+ } /* if Stamp */
+ else if ((p = strstr(d1->name, "State"))) {
+ dlen = p - d1->name;
+
+ for (i = 0; i < ud->nsource; i++) {
+ src = ud->sources + i;
+ if (!strncmp(src->name, d1->name, dlen)) {
+ src->state_offset = offset;
+ break;
+ }
+ }
+ }
+ } /* for */
+}
+
+
+int main(int argc, char **argv)
+{
+ user_data_t ud;
+ const char *prefix;
+ int max_active;
+ const char *prompt;
+
+ MRP_UNUSED(argc);
+
+ prompt = "decision-tester";
+ prefix = "gam";
+ max_active = 4;
+
+ memset(&ud, 0, sizeof(ud));
+ ud.prognam = basename(argv[0]);
+ ud.max_active = max_active;
+
+ sources_create(&ud, prefix);
+ input_create(&ud, prompt);
+
+ input_process(&ud);
+
+ printf("Exiting now ...\n");
+
+ input_destroy(&ud);
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, 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 <murphy/common.h>
+#include <breedline/breedline-murphy.h>
+
+#include "decision-tree.h"
+
+
+static mrp_decision_value_t *traverse_tree(mrp_decision_node_t *, void *);
+static bool test_condition(mrp_decision_branch_t *, void *);
+
+static void copy_value(mrp_decision_value_type_t, mrp_decision_value_t *,
+ mrp_decision_value_t *);
+static void destroy_value(mrp_decision_value_type_t,
+ mrp_decision_value_t *);
+
+
+mrp_decision_tree_t *mrp_decision_tree_create(const char *name,
+ mrp_decision_value_type_t decision_value_type)
+{
+ mrp_decision_node_t *tree;
+
+ if (!name || decision_value_type < 0 ||
+ decision_value_type >= MRP_DECISION_VALUE_BASIC_TYPE_MAX)
+ {
+ return NULL;
+ }
+
+ if ((tree = mrp_allocz(sizeof(mrp_decision_root_node_t)))) {
+ tree->root.type = MRP_DECISION_ROOT_NODE;
+ tree->root.name = mrp_strdup(name);
+ tree->root.decision_value_type = decision_value_type;
+ tree->root.node = NULL;
+ }
+
+ return tree;
+}
+
+
+void mrp_decision_tree_destroy(mrp_decision_tree_t *node)
+{
+ mrp_decision_branch_t *branch;
+ size_t i;
+
+ if (node) {
+ switch (node->type) {
+
+ case MRP_DECISION_ROOT_NODE:
+ mrp_decision_tree_destroy(node->root.node);
+ mrp_free((void *)node->root.name);
+ break;
+
+ case MRP_DECISION_TEST_NODE:
+ for (i = 0; i < node->test.nbranch; i++) {
+ branch = node->test.branches + i;
+
+ destroy_value(branch->value_type, &branch->value);
+ mrp_decision_tree_destroy(branch->node);
+ }
+ mrp_free(node->test.branches);
+ break;
+
+ case MRP_DECISION_TERMINAL_NODE:
+ break;
+
+ default:
+ return;
+ }
+
+ mrp_free(node);
+ }
+}
+
+mrp_decision_node_t *
+mrp_decision_create_terminal_node(mrp_decision_value_t *decision)
+{
+ mrp_decision_node_t *node;
+
+ if (!decision)
+ return NULL;
+
+ if ((node = mrp_allocz(sizeof(mrp_decision_terminal_node_t)))) {
+ node->terminal.type = MRP_DECISION_TERMINAL_NODE;
+ node->terminal.decision = *decision;
+ }
+
+ return node;
+}
+
+
+mrp_decision_node_t *mrp_decision_create_test_node(void)
+{
+ mrp_decision_node_t *node;
+
+ if ((node = mrp_allocz(sizeof(mrp_decision_test_node_t)))) {
+ node->terminal.type = MRP_DECISION_TEST_NODE;
+ }
+
+ return node;
+}
+
+bool mrp_decision_add_node_to_root(mrp_decision_node_t *root,
+ mrp_decision_node_t *node)
+{
+ if (!root || !node)
+ return false;
+
+ if (root->type != MRP_DECISION_ROOT_NODE || root->root.node)
+ return false;
+
+ root->root.node = node;
+
+ return true;
+}
+
+bool mrp_decision_add_branch_to_test_node(mrp_decision_node_t *test_node,
+ mrp_decision_condition_t condition,
+ int value_id,
+ mrp_decision_value_type_t value_type,
+ mrp_decision_value_t *value,
+ size_t offset,
+ mrp_decision_node_t *node)
+{
+ mrp_decision_branch_t *branch;
+ size_t size;
+ size_t i;
+
+ if (!test_node || test_node->type != MRP_DECISION_TEST_NODE ||
+ !value || !node)
+ {
+ return false;
+ }
+
+ i = test_node->test.nbranch++;
+ size = sizeof(mrp_decision_branch_t) * test_node->test.nbranch;
+ test_node->test.branches = mrp_realloc(test_node->test.branches, size);
+
+ branch = test_node->test.branches + i;
+ memset(branch, 0, sizeof(mrp_decision_branch_t));
+
+ branch->condition = condition;
+ branch->value_id = value_id;
+ branch->value_type = value_type;
+ branch->offset = offset;
+ branch->node = node;
+
+ copy_value(value_type, value, &branch->value);
+
+ return true;
+}
+
+
+
+bool mrp_decision_make(mrp_decision_tree_t *node, void *input,
+ mrp_decision_value_type_t *decision_value_type,
+ mrp_decision_value_t **decision_value)
+{
+ if (!node || node->type != MRP_DECISION_ROOT_NODE ||
+ !input || !decision_value)
+ {
+ return false;
+ }
+
+ if (decision_value_type)
+ *decision_value_type = MRP_DECISION_VALUE_UNKNOWN;
+
+ if ((*decision_value = traverse_tree(node->root.node, input))) {
+ if (decision_value_type)
+ *decision_value_type = node->root.decision_value_type;
+
+ return true;
+ }
+
+ return false;
+}
+
+
+const char *mrp_decision_value_type_str(mrp_decision_value_type_t type)
+{
+ switch (type) {
+ case MRP_DECISION_VALUE_INTEGER:
+ return "integer";
+ case MRP_DECISION_VALUE_UNSIGND:
+ return "unsigned";
+ case MRP_DECISION_VALUE_FLOATING:
+ return "floating";
+ case MRP_DECISION_VALUE_STRING:
+ return "string";
+ case MRP_DECISION_VALUE_BITMASK:
+ return "bitmask";
+ case MRP_DECISION_ARRAY_INTEGER:
+ return "integer array";
+ case MRP_DECISION_ARRAY_UNSIGND:
+ return "unsigned array";
+ case MRP_DECISION_ARRAY_FLOATING:
+ return "floating array";
+ case MRP_DECISION_ARRAY_STRING:
+ return "string array";
+ default:
+ return "<unknown value type>";
+ }
+}
+
+const char *mrp_decision_condition_str(mrp_decision_condition_t cond)
+{
+ switch (cond) {
+ case MRP_DECISION_GT: return ">";
+ case MRP_DECISION_GE: return ">=";
+ case MRP_DECISION_EQ: return "=";
+ case MRP_DECISION_LE: return "<=";
+ case MRP_DECISION_LT: return "<";
+ case MRP_DECISION_IN: return "in";
+ default: return "<unknown condition>";
+ }
+}
+
+size_t mrp_decision_value_print(mrp_decision_value_type_t type,
+ mrp_decision_value_t *value,
+ char *buf, size_t len)
+{
+#define ELLIPSIS " ... "
+#define PRINT(args...) do {if (p<h) p += snprintf(p, h-p, args); } while(0)
+#define PRINT_ELLIPSIS do {if (p<e) p += snprintf(p, e-p, ELLIPSIS);} while(0)
+#define PRINT_LISTSTART do {if (p<e) p += snprintf(p, e-p, "["); } while(0)
+#define PRINT_LISTEND do {if (p<e) p += snprintf(p, e-p, "]"); } while(0)
+
+
+ mrp_decision_value_type_t basic_type;
+ mrp_decision_value_t *v;
+ char *p, *e, *h;
+ size_t i, n;
+
+ if (len < sizeof(ELLIPSIS) + 3)
+ return 0;
+
+ h = (e = (p = buf) + len) - (sizeof(ELLIPSIS) + 1);
+
+ if (!(type & MRP_DECISION_ARRAY)) {
+ switch (type) {
+ case MRP_DECISION_VALUE_INTEGER: PRINT("%d", value->integer ); break;
+ case MRP_DECISION_VALUE_UNSIGND: PRINT("%u", value->unsignd ); break;
+ case MRP_DECISION_VALUE_FLOATING: PRINT("%lf", value->floating); break;
+ case MRP_DECISION_VALUE_STRING: PRINT("'%s'",value->string ); break;
+ case MRP_DECISION_VALUE_BITMASK: PRINT("0x%x",value->bitmask ); break;
+ default: PRINT("<unknown value type>"); break;
+ }
+ }
+ else {
+ basic_type = MRP_DECISION_VALUE_BASIC(type);
+ n = value->array.size;
+ v = value->array.values;
+
+ PRINT_LISTSTART;
+
+ for (i = 0; i < n; i++) {
+ if (p >= h) {
+ PRINT_ELLIPSIS;
+ break;
+ }
+
+ if (i > 0)
+ PRINT(", ");
+
+ p += mrp_decision_value_print(basic_type, v+i, p, e-p);
+ }
+
+ PRINT_LISTEND;
+ }
+
+ return p - buf;
+
+#undef PRINT_LISTEND
+#undef PRINT_LISTSTART
+#undef PRINT_ELLIPSIS
+#undef PRINT
+#undef ELLIPSIS
+}
+
+
+static mrp_decision_value_t *traverse_tree(mrp_decision_node_t *node,
+ void *input)
+{
+ mrp_decision_branch_t *branch;
+ size_t i, n;
+
+ if (node && input) {
+ switch (node->type) {
+
+ case MRP_DECISION_TERMINAL_NODE:
+ return &node->terminal.decision;
+ break;
+
+ case MRP_DECISION_TEST_NODE:
+ for (i = 0, n = node->test.nbranch, branch = node->test.branches;
+ i < n;
+ i++, branch++)
+ {
+ if (test_condition(branch, input))
+ return traverse_tree(branch->node, input);
+ }
+ return NULL;
+
+ default:
+ return NULL;
+ }
+ }
+
+ return NULL;
+}
+
+
+static bool test_condition(mrp_decision_branch_t *branch, void *input)
+{
+#define INPUT_VALUE(_t) (*(_t *)(((char *)input) + branch->offset))
+
+ uint32_t bitidx;
+ mrp_decision_bitmask_t bit;
+ mrp_decision_value_t *value;
+ int32_t integer;
+ uint32_t unsignd;
+ double floating;
+ const char *string;
+ size_t i;
+
+ if (!branch || !input)
+ return false;
+
+ switch (branch->condition) {
+
+ case MRP_DECISION_GT:
+ switch (branch->value_type) {
+ case MRP_DECISION_VALUE_INTEGER:
+ return INPUT_VALUE(int32_t) > branch->value.integer;
+ case MRP_DECISION_VALUE_UNSIGND:
+ return INPUT_VALUE(uint32_t) > branch->value.unsignd;
+ case MRP_DECISION_VALUE_FLOATING:
+ return INPUT_VALUE(double) > branch->value.floating;
+ default:
+ return false;
+ }
+
+ case MRP_DECISION_GE:
+ switch (branch->value_type) {
+ case MRP_DECISION_VALUE_INTEGER:
+ return INPUT_VALUE(int32_t) >= branch->value.integer;
+ case MRP_DECISION_VALUE_UNSIGND:
+ return INPUT_VALUE(uint32_t) >= branch->value.unsignd;
+ case MRP_DECISION_VALUE_FLOATING:
+ return INPUT_VALUE(double) >= branch->value.floating;
+ default:
+ return false;
+ }
+
+ case MRP_DECISION_EQ:
+ switch (branch->value_type) {
+ case MRP_DECISION_VALUE_INTEGER:
+ return INPUT_VALUE(int32_t) == branch->value.integer;
+ case MRP_DECISION_VALUE_UNSIGND:
+ return INPUT_VALUE(uint32_t) == branch->value.unsignd;
+ case MRP_DECISION_VALUE_FLOATING:
+ return INPUT_VALUE(double) == branch->value.floating;
+ case MRP_DECISION_VALUE_STRING:
+ return strcmp(INPUT_VALUE(char *), branch->value.string);
+ default:
+ return false;
+ }
+
+ case MRP_DECISION_LE:
+ switch (branch->value_type) {
+ case MRP_DECISION_VALUE_INTEGER:
+ return INPUT_VALUE(int32_t) <= branch->value.integer;
+ case MRP_DECISION_VALUE_UNSIGND:
+ return INPUT_VALUE(uint32_t) <= branch->value.unsignd;
+ case MRP_DECISION_VALUE_FLOATING:
+ return INPUT_VALUE(double) <= branch->value.floating;
+ default:
+ return false;
+ }
+
+ case MRP_DECISION_LT:
+ switch (branch->value_type) {
+ case MRP_DECISION_VALUE_INTEGER:
+ return INPUT_VALUE(int32_t) < branch->value.integer;
+ case MRP_DECISION_VALUE_UNSIGND:
+ return INPUT_VALUE(uint32_t) < branch->value.unsignd;
+ case MRP_DECISION_VALUE_FLOATING:
+ return INPUT_VALUE(double) < branch->value.floating;
+ default:
+ return false;
+ }
+
+ case MRP_DECISION_IN:
+ if ((branch->value_type & MRP_DECISION_ARRAY)) {
+
+ integer = 0;
+ unsignd = 0;
+ floating = 0;
+ string = "";
+
+ switch ((branch->value_type & 0xff)) {
+ case MRP_DECISION_VALUE_INTEGER:
+ integer = INPUT_VALUE(int32_t);
+ break;
+ case MRP_DECISION_VALUE_UNSIGND:
+ unsignd = INPUT_VALUE(uint32_t);
+ break;
+ case MRP_DECISION_VALUE_FLOATING:
+ floating = INPUT_VALUE(double);
+ break;
+ case MRP_DECISION_VALUE_STRING:
+ string = INPUT_VALUE(char *);
+ break;
+ default:
+ return false;
+ }
+ for (i = 0; i < branch->value.array.size; i++) {
+ value = branch->value.array.values + i;
+ switch ((branch->value_type & 0xff)) {
+ case MRP_DECISION_VALUE_INTEGER:
+ if (integer == value->integer)
+ return true;
+ break;
+ case MRP_DECISION_VALUE_UNSIGND:
+ if (unsignd == value->unsignd)
+ return true;
+ break;
+ case MRP_DECISION_VALUE_FLOATING:
+ if (floating == value->floating)
+ return true;
+ break;
+ case MRP_DECISION_VALUE_STRING:
+ if (!strcmp(string, value->string))
+ return true;
+ break;
+ default:
+ return false;
+ }
+ } /* for i */
+ return false;
+ }
+ else {
+ if (branch->value_type == MRP_DECISION_VALUE_BITMASK) {
+ bitidx = INPUT_VALUE(int32_t);
+
+ if (bitidx >= MRP_DECISION_BITMASK_WIDTH)
+ return false;
+
+ bit = MRP_DECISION_BIT(bitidx);
+
+ return (bit & branch->value.bitmask) ? true : false;
+ }
+ }
+ return false;
+ }
+
+ return false;
+}
+
+static void copy_value(mrp_decision_value_type_t type,
+ mrp_decision_value_t *src,
+ mrp_decision_value_t *dst)
+{
+ mrp_decision_value_type_t basic_type;
+ mrp_decision_value_t *src_values;
+ mrp_decision_value_t *dst_values;
+ size_t i, n;
+
+ if (!(type & MRP_DECISION_ARRAY)) {
+ if (type == MRP_DECISION_VALUE_STRING)
+ dst->string = mrp_strdup(src->string);
+ else
+ *dst = *src;
+ }
+ else {
+ n = src->array.size;
+
+ dst->array.size = n;
+ dst->array.values = mrp_allocz(sizeof(dst->array.values[0]) * n);
+
+ basic_type = MRP_DECISION_VALUE_BASIC(type);
+ src_values = src->array.values;
+ dst_values = dst->array.values;
+
+ for (i = 0; i < n; i++)
+ copy_value(basic_type, src_values + i, dst_values + i);
+ }
+}
+
+
+static void destroy_value(mrp_decision_value_type_t type,
+ mrp_decision_value_t *value)
+{
+ mrp_decision_value_type_t basic_type;
+ size_t i;
+
+ if (!(type & MRP_DECISION_ARRAY)) {
+ if (type == MRP_DECISION_VALUE_STRING)
+ mrp_free((void *)value->string);
+ }
+ else {
+ basic_type = MRP_DECISION_VALUE_BASIC(type);
+
+ for (i = 0; i < value->array.size; i++)
+ destroy_value(basic_type, value->array.values + i);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, 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.
+ */
+#ifndef __MRP_DECISION_TREE_H__
+#define __MRP_DECISION_TREE_H__
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#include <murphy/common/macros.h>
+
+#define MRP_DECISION_BITMASK_WIDTH (sizeof(mrp_decision_bitmask_t) * 8)
+#define MRP_DECISION_BIT(b) ((mrp_decision_bitmask_t)1 << (b))
+#define MRP_DECISION_VALUE_BASIC(v) ((v) & 0xff)
+
+typedef enum mrp_decision_value_type_e mrp_decision_value_type_t;
+typedef enum mrp_decision_node_type_e mrp_decision_node_type_t;
+typedef enum mrp_decision_condition_e mrp_decision_condition_t;
+
+typedef union mrp_decision_value_u mrp_decision_value_t;
+typedef struct mrp_decision_branch_s mrp_decision_branch_t;
+typedef struct mrp_decision_root_node_s mrp_decision_root_node_t;
+typedef struct mrp_decision_test_node_s mrp_decision_test_node_t;
+typedef struct mrp_decision_terminal_node_s mrp_decision_terminal_node_t;
+typedef union mrp_decision_node_u mrp_decision_node_t;
+typedef union mrp_decision_node_u mrp_decision_tree_t;
+
+typedef uint32_t mrp_decision_bitmask_t;
+
+enum mrp_decision_value_type_e {
+ MRP_DECISION_VALUE_UNKNOWN = -1,
+ MRP_DECISION_VALUE_INTEGER = 0,
+ MRP_DECISION_VALUE_UNSIGND,
+ MRP_DECISION_VALUE_FLOATING,
+ MRP_DECISION_VALUE_STRING,
+ MRP_DECISION_VALUE_BASIC_TYPE_MAX,
+
+ MRP_DECISION_VALUE_BITMASK = MRP_DECISION_VALUE_BASIC_TYPE_MAX,
+
+ MRP_DECISION_ARRAY = 0x100,
+
+ MRP_DECISION_ARRAY_INTEGER = (MRP_DECISION_ARRAY |
+ MRP_DECISION_VALUE_INTEGER),
+ MRP_DECISION_ARRAY_UNSIGND = (MRP_DECISION_ARRAY |
+ MRP_DECISION_VALUE_UNSIGND),
+ MRP_DECISION_ARRAY_FLOATING = (MRP_DECISION_ARRAY |
+ MRP_DECISION_VALUE_FLOATING),
+ MRP_DECISION_ARRAY_STRING = (MRP_DECISION_ARRAY |
+ MRP_DECISION_VALUE_STRING),
+};
+
+union mrp_decision_value_u {
+ int32_t integer;
+ uint32_t unsignd;
+ double floating;
+ mrp_decision_bitmask_t bitmask;
+ const char *string;
+ struct {
+ size_t size;
+ mrp_decision_value_t *values;
+ } array;
+};
+
+enum mrp_decision_condition_e {
+ MRP_DECISION_GT,
+ MRP_DECISION_GE,
+ MRP_DECISION_LE,
+ MRP_DECISION_EQ,
+ MRP_DECISION_LT,
+ MRP_DECISION_IN,
+};
+
+struct mrp_decision_branch_s {
+ mrp_decision_condition_t condition;
+ int value_id;
+ mrp_decision_value_type_t value_type;
+ mrp_decision_value_t value;
+ size_t offset;
+ mrp_decision_node_t *node;
+};
+
+enum mrp_decision_node_type_e {
+ MRP_DECISION_UNKNOWN_NODE = 0,
+ MRP_DECISION_ROOT_NODE,
+ MRP_DECISION_TEST_NODE,
+ MRP_DECISION_TERMINAL_NODE
+};
+
+struct mrp_decision_root_node_s {
+ mrp_decision_node_type_t type;
+ const char *name;
+ mrp_decision_value_type_t decision_value_type;
+ mrp_decision_node_t *node;
+};
+
+struct mrp_decision_test_node_s {
+ mrp_decision_node_type_t type;
+ size_t nbranch;
+ mrp_decision_branch_t *branches;
+};
+
+struct mrp_decision_terminal_node_s {
+ mrp_decision_node_type_t type;
+ mrp_decision_value_t decision;
+};
+
+union mrp_decision_node_u {
+ mrp_decision_node_type_t type;
+ mrp_decision_root_node_t root;
+ mrp_decision_test_node_t test;
+ mrp_decision_terminal_node_t terminal;
+};
+
+
+mrp_decision_tree_t *mrp_decision_tree_create(const char *name,
+ mrp_decision_value_type_t decision_value_type);
+void mrp_decision_tree_destroy(mrp_decision_tree_t *tree);
+
+mrp_decision_node_t *mrp_decision_create_terminal_node(
+ mrp_decision_value_t *decision);
+mrp_decision_node_t *mrp_decision_create_test_node(void);
+
+bool mrp_decision_add_node_to_root(mrp_decision_tree_t *tree,
+ mrp_decision_node_t *node);
+bool mrp_decision_add_branch_to_test_node(mrp_decision_node_t *test_node,
+ mrp_decision_condition_t condition,
+ int value_id,
+ mrp_decision_value_type_t value_type,
+ mrp_decision_value_t *value,
+ size_t offset,
+ mrp_decision_node_t *node);
+
+
+bool mrp_decision_make(mrp_decision_tree_t *tree, void *input,
+ mrp_decision_value_type_t *decision_value_type,
+ mrp_decision_value_t **decision_value);
+
+
+const char *mrp_decision_value_type_str(mrp_decision_value_type_t type);
+const char *mrp_decision_condition_str(mrp_decision_condition_t cond);
+
+size_t mrp_decision_value_print(mrp_decision_value_type_t type,
+ mrp_decision_value_t *value,
+ char *buf, size_t len);
+
+
+#endif /* __MRP_DECISION_TREE_H__ */
--- /dev/null
+/*
+ * Copyright (c) 2014, 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 <sys/time.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <libgen.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "pattern-generator.h"
+#include "decision-maker.h"
+
+#define CONNECTION(_source, _sink) \
+ (((conn_t)((_source) & 0xff) << 8) | ((conn_t)((_sink) & 0xff)))
+
+#define INVALID_ENTRY (~(entry_t)0)
+#define ENTRY(_source, _sink, _state, _stamp) \
+ (((entry_t)(CONNECTION(_source, _sink) << 16)) | \
+ (((entry_t)(_stamp) & 0xff) << 8) | \
+ (((entry_t)(_state)) & 0x0f))
+
+
+typedef struct {
+ sink_t sink;
+ conn_t conflict[SOURCE_MAX + 1];
+} conn_def_t [SINK_MAX];
+
+typedef struct {
+ int bits;
+ int8_t bitseq[SOURCE_MAX];
+} stamp_pattern_t;
+
+typedef struct {
+ int pattern;
+ int active;
+ uint32_t sequence;
+} index_t;
+
+
+static const char *source_names[SOURCE_MAX] = {
+ "wrtApplication",
+ "icoApplication",
+ "phone",
+ "radio",
+ "microphone",
+ "navigator",
+};
+
+static const char *sink_names[SINK_MAX] = {
+ "noroute",
+ "phone",
+ "btHeadset",
+ "usbHeadset",
+ "speakers",
+ "wiredHeadset",
+ "voiceRecognition",
+};
+
+static const char *state_names[STATE_MAX] = {
+ "stop",
+ "pause",
+ "play",
+};
+
+
+static conn_def_t conn_defs[SOURCE_MAX] = {
+ [wrtApplication] = {
+ [noroute] = { noroute, {} },
+ [btHeadset] = { btHeadset, {} },
+ [usbHeadset] = { usbHeadset, {} },
+ [speakers] = { speakers, { CONNECTION(wrtApplication, wiredHeadset) }},
+ [wiredHeadset] = { wiredHeadset, { CONNECTION(wrtApplication, speakers) }},
+ },
+ [icoApplication] = {
+ [noroute] = { noroute, {} },
+ [btHeadset] = { btHeadset, {} },
+ [usbHeadset] = { usbHeadset, {} },
+ [speakers] = { speakers, { CONNECTION(icoApplication, wiredHeadset),
+ CONNECTION(phoneSource, speakers),
+ CONNECTION(phoneSource, wiredHeadset) }},
+ [wiredHeadset] = { wiredHeadset, { CONNECTION(icoApplication, speakers),
+ CONNECTION(phoneSource, speakers),
+ CONNECTION(phoneSource, wiredHeadset) }},
+ },
+ [phoneSource] = {
+ [noroute] = { noroute, {} },
+ [btHeadset] = { btHeadset, { CONNECTION(phoneSource, usbHeadset),
+ CONNECTION(phoneSource, speakers),
+ CONNECTION(phoneSource, wiredHeadset) }},
+ [usbHeadset] = { usbHeadset, { CONNECTION(phoneSource, btHeadset),
+ CONNECTION(phoneSource, speakers),
+ CONNECTION(phoneSource, wiredHeadset) }},
+ [speakers] = { speakers, { CONNECTION(phoneSource, btHeadset),
+ CONNECTION(phoneSource, usbHeadset),
+ CONNECTION(icoApplication, speakers),
+ CONNECTION(icoApplication, wiredHeadset),
+ CONNECTION(phoneSource, wiredHeadset) }},
+ [wiredHeadset] = { wiredHeadset, { CONNECTION(phoneSource, btHeadset),
+ CONNECTION(phoneSource, usbHeadset),
+ CONNECTION(icoApplication, speakers),
+ CONNECTION(icoApplication, wiredHeadset),
+ CONNECTION(phoneSource, speakers) }},
+ },
+ [radio] = {
+ [noroute] = { noroute, {} },
+ [btHeadset] = { btHeadset, { CONNECTION(radio, usbHeadset) }},
+ [usbHeadset] = { usbHeadset, { CONNECTION(radio, btHeadset) }},
+ [speakers] = { speakers, {} },
+ [wiredHeadset] = { wiredHeadset, {} },
+ },
+ [microphone] = {
+ [noroute] = { noroute, {} },
+ [phoneSink] = { phoneSink, { CONNECTION(microphone, voiceRecognition) }},
+ [voiceRecognition] = { voiceRecognition, { CONNECTION(microphone, phoneSink) }}
+ },
+ [navigator] = {
+ [noroute] = { noroute, {} },
+ [speakers] = { speakers, { CONNECTION(navigator, wiredHeadset) }},
+ [wiredHeadset] = { wiredHeadset, { CONNECTION(navigator, speakers) }}
+ },
+};
+
+static uint32_t factorial[9] = { 0, 1, 2, 6, 24, 120, 720, 5040, 40320 };
+
+static int npattern[SOURCE_MAX+1];
+static stamp_pattern_t patterns[SOURCE_MAX+1][1024];
+static int nsequence[SOURCE_MAX+1];
+static uint8_t *sequences[SOURCE_MAX+1];
+static int nindex[SOURCE_MAX+1];
+static index_t indices[SOURCE_MAX+1][100000];
+
+#define DECISION_SPACE_DIMENSION (1 << (SOURCE_MAX * CONN_STATE_BITS))
+static bool decisions[DECISION_SPACE_DIMENSION];
+static uint32_t pattern_counter;
+static uint32_t decision_counter;
+
+static FILE *data;
+static FILE *names;
+
+
+static sink_t next_sink(source_t source, sink_t sink)
+{
+ while (++sink < SINK_MAX) {
+ if (conn_defs[source][sink].sink == sink) {
+ break;
+ }
+ }
+ return sink;
+}
+
+static bool next_entry(entry_t *usecase, source_t source, stamp_t stamp, entry_t *cursor)
+{
+ entry_t entry, new_entry, new_cursor;
+ conn_t conn;
+ sink_t sink;
+ state_t state;
+
+ if (source < 0 || source >= SOURCE_MAX)
+ return false;
+
+ if ((entry = *cursor) == INVALID_ENTRY)
+ return false;
+
+ if (stamp == 0) {
+ new_entry = ENTRY(source, noroute, stop, 0);
+ new_cursor = INVALID_ENTRY;
+ }
+ else {
+ conn = ENTRY_CONNECTION(entry);
+ state = ENTRY_STATE(entry);
+ sink = CONNECTION_SINK(conn);
+
+ for (;;) {
+ if (state >= STATE_MAX) {
+ *cursor = INVALID_ENTRY;
+ return false;
+ }
+
+ if (sink >= SINK_MAX) {
+ state++;
+ sink = 0;
+ continue;
+ }
+
+ if (sink == noroute && state != stop) {
+ sink = next_sink(source, sink);
+ continue;
+ }
+
+ new_entry = ENTRY(source, sink, state, stamp);
+
+ sink = next_sink(source, sink);
+ new_cursor = ENTRY(source, sink, state, stamp);
+
+ break;
+ }
+ }
+
+ *cursor = new_cursor;
+ usecase[source] = new_entry;
+
+ return true;
+}
+
+
+static void populate_active_patterns(void)
+{
+#define BIT(b) ((int)1 << (b))
+
+ stamp_pattern_t *p;
+ int n;
+ int i,j,k;
+ int cnt;
+ int8_t bitseq[SOURCE_MAX];
+
+ for (i = 1; i < SOURCE_MAX; i++) {
+ for (n = 0, k = 0; n < BIT(SOURCE_MAX); n++) {
+ memset(bitseq, -1, sizeof(bitseq));
+ for (j = 0, cnt = 0; j < SOURCE_MAX; j++) {
+ if (n & BIT(j))
+ bitseq[j] = cnt++;
+ }
+ if (cnt <= i) {
+ p = &patterns[i][k++];
+ p->bits = cnt;
+ memcpy(p->bitseq, bitseq, sizeof(bitseq));
+ }
+ }
+ npattern[i] = k;
+ }
+
+#undef BIT
+}
+
+static void populate_sequences(void)
+{
+ static uint32_t max[9] = { 0, 1, 4, 27, 256, 3125, 46656, 823543, 16777216 };
+ static uint8_t seqs[(SOURCE_MAX +1) * (40320 *SOURCE_MAX)];
+
+ uint8_t *sp;
+ uint32_t i, j, k, n, v, s;
+ bool valid;
+
+ nsequence[0] = 1;
+ sequences[0] = seqs;
+
+ for (i = 1, sp = seqs + 1; i <= SOURCE_MAX; i++) {
+ sequences[i] = sp;
+
+ for (n = 0; n < max[i]; n++) {
+ for (j = 0, v = n, valid = true; j < i && valid; j++, v /= i) {
+ sp[j] = s = (v % i) + 1;
+ for (k = 0; k < j; k++) {
+ if (s == sp[k]) {
+ valid = false;
+ break;
+ }
+ }
+ }
+ if (valid)
+ sp += (SOURCE_MAX + 1);
+ }
+
+ nsequence[i] = (sp - sequences[i]) / (SOURCE_MAX + 1);
+ }
+}
+
+static uint32_t seqno_max(int max_active)
+{
+ if (max_active > 8 || max_active > SOURCE_MAX)
+ return 0;
+
+ return nindex[max_active];
+}
+
+
+static void populate_indices(void)
+{
+ stamp_pattern_t *pattern;
+ int i,j;
+ int active;
+ uint32_t cnt, combinations, k;
+ index_t *idx;
+
+ for (i = 1; i <= SOURCE_MAX; i++) {
+ idx = &indices[i][0];
+ for (cnt = 0, j = 0; j < npattern[i]; j++) {
+ pattern = &patterns[i][j];
+ active = pattern->bits;
+ combinations = factorial[pattern->bits];
+ cnt += combinations;
+ for (k = 0; k < combinations; k++, idx++) {
+ idx->pattern = j;
+ idx->active = active;
+ idx->sequence = k;
+ }
+ }
+ nindex[i] = cnt;
+ }
+}
+
+
+static stamp_t source_stamp(uint32_t seqno, source_t source, int max_active)
+{
+ stamp_pattern_t *pattern;
+ int active;
+ int8_t *bitseq;
+ index_t *idx;
+ uint8_t *seq;
+
+ if (max_active <= 0)
+ return 0;
+
+ if (max_active > SOURCE_MAX)
+ max_active = SOURCE_MAX;
+
+ if (seqno >= seqno_max(max_active))
+ return 0;
+
+ idx = &indices[max_active][seqno];
+
+ pattern = &patterns[max_active][idx->pattern];
+ active = pattern->bits;
+ bitseq = pattern->bitseq;
+
+ if (bitseq[source] < 0)
+ return 0;
+
+ seq = sequences[active] + (idx->sequence * (SOURCE_MAX + 1));
+
+ return seq[bitseq[source]];
+}
+
+static bool valid_usecase(entry_t *usecase)
+{
+ entry_t entry;
+ stamp_t stamp;
+ state_t state;
+ conn_t conn;
+ sink_t sink;
+ int i;
+
+ for (i = 0; i < SOURCE_MAX; i++) {
+ entry = usecase[i];
+ stamp = ENTRY_STAMP(entry);
+ state = ENTRY_STATE(entry);
+ conn = ENTRY_CONNECTION(entry);
+ sink = CONNECTION_SINK(conn);
+
+ if (!stamp && (sink != noroute || state != stop))
+ return false;
+ }
+
+ return true;
+}
+
+static void generate_usecases(int max_active,
+ source_t source,
+ entry_t *usecase,
+ entry_t *cursor,
+ stamp_t *stamp,
+ uint32_t seqno,
+ source_t idx)
+{
+ decision_t decision;
+ char ubuf[256];
+ char dbuf[64];
+
+ if (idx == SOURCE_MAX) {
+ if (valid_usecase(usecase)) {
+ decision = make_decision(usecase, source, max_active);
+
+ print_usecase(usecase, ubuf,sizeof(ubuf));
+ print_decision(decision, source, dbuf,sizeof(dbuf));
+
+ fprintf(data, "%s %s\n", ubuf, dbuf);
+
+ decisions[decision] = true;
+ pattern_counter++;
+ }
+ }
+ else {
+ while (next_entry(usecase, idx, stamp[idx], &cursor[idx])) {
+ cursor[idx+1] = 0;
+ generate_usecases(max_active, source, usecase,
+ cursor, stamp, seqno, idx+1);
+ }
+ }
+}
+
+
+static size_t print_entry(entry_t entry, char *buf, size_t len)
+{
+ conn_t conn;
+ sink_t sink;
+ stamp_t stamp;
+ state_t state;
+ const char *sink_name, *state_name;
+
+ conn = ENTRY_CONNECTION(entry);
+ state = ENTRY_STATE(entry);
+ stamp = ENTRY_STAMP(entry);
+ sink = CONNECTION_SINK(conn);
+
+ sink_name = (sink >= 0 && sink < SINK_MAX) ?
+ sink_names[sink] : "<unknown>";
+ state_name = (state >= 0 && state < STATE_MAX) ?
+ state_names[state] : "<unknown>";
+
+ return snprintf(buf, len, "%s,%u,%s, ", sink_name, stamp, state_name);
+}
+
+
+void initialize_pattern_generator(const char *stem,
+ int max_active,
+ source_t source)
+{
+ const char *srcnam;
+ char data_file[1024];
+ char names_file[1024];
+
+ if (source == allSources) {
+ snprintf(data_file, sizeof(data_file), "%s-%d.data",
+ stem, max_active);
+ snprintf(names_file, sizeof(names_file), "%s-%d.names",
+ stem, max_active);
+ }
+ else {
+ srcnam = get_source_name(source);
+ snprintf(data_file, sizeof(data_file), "%s-%s-%d.data",
+ stem, srcnam, max_active);
+ snprintf(names_file, sizeof(names_file), "%s-%s-%d.names",
+ stem, srcnam, max_active);
+ }
+
+ if (!(data = fopen(data_file, "w+"))) {
+ printf("failed to open file '%s': %s\n", data_file, strerror(errno));
+ exit(errno);
+ }
+
+ if (!(names = fopen(names_file, "w+"))) {
+ printf("failed to open file '%s': %s\n", names_file, strerror(errno));
+ exit(errno);
+ }
+
+ printf("populating '%s' and '%s' files\n", data_file, names_file);
+
+ populate_active_patterns();
+ populate_sequences();
+ populate_indices();
+}
+
+void generate_patterns(int max_active, int source)
+{
+ uint32_t seqno;
+ entry_t cursor[SOURCE_MAX];
+ stamp_t stamp[SOURCE_MAX];
+ usecase_t usecase;
+ source_t idx;
+
+ for (seqno = 0; seqno < seqno_max(max_active); seqno++) {
+ memset(cursor, 0, sizeof(cursor));
+ memset(usecase, 0, sizeof(usecase));
+
+ for (idx = 0; idx < SOURCE_MAX; idx++) {
+ stamp[idx] = source_stamp(seqno, idx, max_active);
+ }
+
+ generate_usecases(max_active, source, usecase, cursor, stamp, seqno, 0);
+ }
+}
+
+void generate_names(int max_active, int source)
+{
+ const char *srcnam;
+ sink_t sink;
+ char feature[256];
+ int i,j;
+ char *sep;
+
+
+ fprintf(names, "decision.\n\n");
+
+ for (i = 0; i < SOURCE_MAX; i++) {
+ if ((srcnam = source_names[i])) {
+ /* route */
+ snprintf(feature, sizeof(feature), "%sRoute:", srcnam);
+ fprintf(names, "%-24s noroute", feature);
+ for (j = 1; j < SINK_MAX; j++) {
+ if ((sink = conn_defs[i][j].sink) != noroute)
+ fprintf(names, ", %s", sink_names[j]);
+ }
+ fprintf(names, ".\n");
+
+ /* stamp */
+ snprintf(feature, sizeof(feature), "%sStamp:", srcnam);
+ if (1) {
+ fprintf(names, "%-24s 0", feature);
+ for (j = 0; j < max_active; j++)
+ fprintf(names, ", %d", j+1);
+ fprintf(names, ".\n");
+ }
+ else {
+ fprintf(names, "%-24s continuous.\n", feature);
+ }
+
+ /* state */
+ snprintf(feature, sizeof(feature), "%sState:", srcnam);
+ fprintf(names, "%-24s stop, pause, play.\n\n", feature);
+ }
+ }
+
+ snprintf(feature, sizeof(feature), "decision:");
+ fprintf(names, "%-24s ", feature);
+
+ if (source == allSources) {
+ for (i = j = 0, sep = ""; i < DECISION_SPACE_DIMENSION; i++) {
+ if (decisions[i]) {
+ decision_counter++;
+ if (j && !(j % 10))
+ sep = ",\n ";
+ fprintf(names, "%s%d", sep, i);
+ sep = ", ";
+ j++;
+ }
+ }
+ }
+ else {
+ for (i = 0, sep = ""; i < CONN_STATE_MAX; i++) {
+ if (decisions[i]) {
+ decision_counter++;
+ fprintf(names, "%s%s", sep, get_conn_state_name(i));
+ sep = ", ";
+ }
+ }
+ }
+
+ fprintf(names, ".\n");
+}
+
+
+size_t print_usecase(entry_t *usecase, char *buf, size_t len)
+{
+ source_t source;
+ char *p, *e;
+
+ e = (p = buf) + len;
+
+ for (source = 0; source < SOURCE_MAX && p < e; source++)
+ p += print_entry(usecase[source], p, e-p);
+
+ return p - buf;
+}
+
+
+bool route_conflicts(entry_t entry, conn_t conn)
+{
+ conn_t c;
+ source_t source;
+ sink_t sink;
+ conn_t *conflict;
+ int i;
+
+ if (CONNECTION_SINK(conn) == noroute)
+ return false;
+
+ c = ENTRY_CONNECTION(entry);
+ source = CONNECTION_SOURCE(c);
+ sink = CONNECTION_SINK(c);
+
+ conflict = conn_defs[source][sink].conflict;
+
+ for (i = 0; conflict[i]; i++) {
+ if (conn == conflict[i])
+ return true;
+ }
+
+ return false;
+}
+
+const char *get_source_name(source_t source)
+{
+ if (source == allSources)
+ return "allSources";
+ if (source < 0 || source >= SOURCE_MAX)
+ return "<unknown source>";
+ return source_names[source];
+}
+
+const char *get_sink_name(sink_t sink)
+{
+ if (sink == allSinks)
+ return "allSinks";
+ if (sink < 0 || sink >= SINK_MAX)
+ return "<unknown sink>";
+ return sink_names[sink];
+}
+
+static void usage(int argc, char **argv, int status)
+{
+ (void)argc;
+
+ printf("Usage: %s stem max_active_sources [source]\n"
+ "\twhere\n"
+ "\t stem is the name for .data and .names files\n"
+ "\t range for max_active_sources (1 - %d)\n"
+ "\t the source the decisions are done for [optional]\n",
+ basename(argv[0]), SOURCE_MAX);
+
+ if (status)
+ exit(status);
+}
+
+double get_time_stamp(void)
+{
+ struct timeval tv;
+
+ if (gettimeofday(&tv, NULL) < 0) {
+ printf("failed to get time stamp: %s\n", strerror(errno));
+ exit(errno);
+ }
+
+ return (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0;
+}
+
+int main(int argc, char **argv)
+{
+ char *stem;
+ int max_active;
+ int source;
+ char *e;
+ double start, end;
+
+ if (argc > 4 || argc < 3)
+ usage(argc, argv, EINVAL);
+
+ stem = argv[1];
+ max_active = strtol(argv[2], &e, 10);
+
+ if (max_active < 1 || max_active >= SOURCE_MAX || *e || e == argv[2])
+ usage(argc, argv, EINVAL);
+
+ if (argc == 3)
+ source = allSources;
+ else {
+ if (isdigit(argv[3][0])) {
+ source = strtol(argv[3], &e, 10);
+
+ if (*e || e == argv[3])
+ source = SOURCE_MAX;
+ }
+ else if (isalpha(argv[3][0])) {
+ for (source = 0; source < SOURCE_MAX; source++) {
+ if (!strcmp(get_source_name(source), argv[3]))
+ break;
+ }
+ }
+ else {
+ source = SOURCE_MAX;
+ }
+ }
+
+ if (source < -1 || source >= SOURCE_MAX)
+ usage(argc, argv, EINVAL);
+
+ start = get_time_stamp();
+
+ initialize_pattern_generator(stem, max_active, source);
+ generate_patterns(max_active, source);
+ generate_names(max_active, source);
+
+ end = get_time_stamp();
+
+ printf("generated %u patterns with %u different decisions "
+ "in %.3lf seconds\n",
+ pattern_counter, decision_counter, end - start);
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, 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.
+ */
+#ifndef __MRP_PATTERN_GENERATOR_H__
+#define __MRP_PATTERN_GENERATOR_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+
+
+typedef enum {
+ allSources = -1,
+ wrtApplication = 0,
+ icoApplication,
+ phoneSource,
+ radio,
+ microphone,
+ navigator,
+ SOURCE_MAX
+} source_t;
+
+typedef enum {
+ allSinks = -1,
+ noroute = 0,
+ phoneSink,
+ btHeadset,
+ usbHeadset,
+ speakers,
+ wiredHeadset,
+ voiceRecognition,
+ SINK_MAX
+} sink_t;
+
+typedef enum {
+ stop = 0,
+ pause,
+ play,
+ STATE_MAX
+} state_t;
+
+
+#define CONNECTION_SOURCE(_conn) \
+ (((_conn) >> 8) & 0xff)
+#define CONNECTION_SINK(_conn) \
+ ((_conn) & 0xff)
+
+typedef uint16_t conn_t;
+
+typedef uint8_t stamp_t; /* SOURCE_MAX must be smaller than 8 */
+
+#define ENTRY_CONNECTION(_entry) \
+ ((conn_t)(((_entry) >> 16) & 0xffff))
+#define ENTRY_STATE(_entry) \
+ ((state_t)(_entry) & 0x0f)
+#define ENTRY_STAMP(_entry) \
+ ((stamp_t)(((_entry) >> 8) & 0xff))
+
+typedef uint32_t entry_t;
+
+typedef entry_t usecase_t [SOURCE_MAX];
+
+
+void initialize_pattern_generator(const char *stemy, int max_active,
+ source_t source);
+void generate_patterns(int max_active, int source);
+void generate_names(int max_active, int source);
+
+size_t print_usecase(entry_t *usecase, char *buf, size_t len);
+
+bool route_conflicts(entry_t entry, conn_t conn);
+
+const char *get_source_name(source_t source);
+const char *get_sink_name(sink_t sink);
+
+
+#endif /* __MRP_PATTERN_GENERATOR_H__ */
--- /dev/null
+/*
+ * Copyright (c) 2014, 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 <errno.h>
+
+#include <lualib.h>
+#include <lauxlib.h>
+
+#include <murphy/common.h>
+#include <murphy/common/debug.h>
+#include <murphy/core/plugin.h>
+#include <murphy/core/console.h>
+#include <murphy/core/event.h>
+#include <murphy/core/context.h>
+#include <murphy/core/lua-bindings/murphy.h>
+
+#include <murphy-db/mqi.h>
+
+#include <murphy/resource/config-api.h>
+#include <murphy/resource/manager-api.h>
+#include <murphy/resource/client-api.h>
+#include <murphy/resource/protocol.h>
+
+#include "plugin-gam-resource-manager.h"
+#include "backend.h"
+#include "source.h"
+#include "sink.h"
+#include "usecase.h"
+
+typedef struct dependency_s dependency_t;
+
+enum {
+ CONFDIR,
+ PREFIX,
+ DECISION_NAMES,
+ MAX_ACTIVE,
+};
+
+struct dependency_s {
+ const char *db_table_name;
+ mrp_resmgr_dependency_cb_t callback;
+ bool changed;
+};
+
+struct mrp_resmgr_s {
+ mrp_plugin_t *plugin;
+
+ mrp_resmgr_config_t *config;
+ mrp_event_watch_t *w;
+ mrp_resmgr_backend_t *backend;
+ mrp_resmgr_sources_t *sources;
+ mrp_resmgr_sinks_t *sinks;
+ mrp_resmgr_usecase_t *usecase;
+
+ size_t ndepend;
+ dependency_t *depends;
+};
+
+static int resource_update_cb(mrp_scriptlet_t *, mrp_context_tbl_t *);
+static void add_depenedencies_to_resolver(mrp_resmgr_t *);
+
+static void print_resources_cb(mrp_console_t *, void *, int, char **);
+static void print_usecase_cb(mrp_console_t *, void *, int, char **);
+
+static mrp_resmgr_config_t *config_create(mrp_plugin_t *);
+static void config_destroy(mrp_resmgr_config_t *);
+
+static void event_cb(mrp_event_watch_t *, int, mrp_msg_t *, void *);
+static int subscribe_events(mrp_resmgr_t *);
+static void unsubscribe_events(mrp_resmgr_t *);
+
+
+
+MRP_CONSOLE_GROUP(manager_group, "gam", NULL, NULL, {
+ MRP_TOKENIZED_CMD("resources", print_resources_cb, FALSE,
+ "resources", "prints managed resources",
+ "prints the resources managed by "
+ "gam-resource-manager."),
+ MRP_TOKENIZED_CMD("usecase", print_usecase_cb, FALSE,
+ "usecase", "prints the usecase values",
+ "prints the usecase values that are used "
+ "for making routing/playback right decisions "
+ "by gam-resource-manager."),
+});
+
+static mrp_resmgr_t *resmgr_data;
+
+mrp_resmgr_config_t *mrp_resmgr_get_config(mrp_resmgr_t *resmgr)
+{
+ return resmgr->config;
+}
+
+mrp_resmgr_backend_t *mrp_resmgr_get_backend(mrp_resmgr_t *resmgr)
+{
+ return resmgr->backend;
+}
+
+
+mrp_resmgr_sources_t *mrp_resmgr_get_sources(mrp_resmgr_t *resmgr)
+{
+ return resmgr->sources;
+}
+
+mrp_resmgr_sinks_t *mrp_resmgr_get_sinks(mrp_resmgr_t *resmgr)
+{
+ return resmgr->sinks;
+}
+
+mrp_resmgr_usecase_t *mrp_resmgr_get_usecase(mrp_resmgr_t *resmgr)
+{
+ return resmgr->usecase;
+}
+
+
+
+void mrp_resmgr_register_dependency(mrp_resmgr_t *resmgr,
+ const char *db_table_name,
+ mrp_resmgr_dependency_cb_t callback)
+{
+ size_t size;
+ char dependency[512];
+ int idx;
+
+ MRP_ASSERT(resmgr && db_table_name, "invalid argument");
+
+ snprintf(dependency, sizeof(dependency), "$%s", db_table_name);
+
+ idx = resmgr->ndepend++;
+ size = resmgr->ndepend * sizeof(dependency_t);
+
+ if (!(resmgr->depends = mrp_realloc(resmgr->depends, size)) ||
+ !(resmgr->depends[idx].db_table_name = mrp_strdup(dependency)))
+ {
+ mrp_log_error("gam-resource-manager: failed to allocate memory "
+ "for resource dependencies");
+ resmgr->ndepend = 0;
+ resmgr->depends = NULL;
+ return;
+ }
+
+ resmgr->depends[idx].callback = callback;
+}
+
+
+
+static int resource_update_cb(mrp_scriptlet_t *script, mrp_context_tbl_t *ctbl)
+{
+ mrp_resmgr_t *resmgr = (mrp_resmgr_t *)script->data;
+ uint32_t zoneid;
+ size_t i;
+ bool recalc;
+
+ MRP_UNUSED(ctbl);
+
+ MRP_ASSERT(resmgr, "invalid argument");
+
+ printf("### %s() called\n", __FUNCTION__);
+
+ for (recalc = false, i = 0; i < resmgr->ndepend; i++)
+ recalc |= resmgr->depends[i].callback(resmgr);
+
+ if (recalc) {
+ printf("=> recalc resource allocations!\n");
+
+ for (zoneid = 0; zoneid < mrp_zone_count(); zoneid++)
+ mrp_resource_owner_recalc(zoneid);
+ }
+
+ return TRUE;
+}
+
+static void add_depenedencies_to_resolver(mrp_resmgr_t *resmgr)
+{
+ static const char *target = "_gam_resources";
+ static mrp_interpreter_t resource_updater = {
+ { NULL, NULL },
+ "gam_resource_updater",
+ NULL,
+ NULL,
+ NULL,
+ resource_update_cb,
+ NULL
+ };
+
+ mrp_plugin_t *plugin;
+ mrp_context_t *ctx;
+ mrp_resolver_t *resolver;
+ char buf[2048];
+ const char *deps[256];
+ size_t i,ndep;
+ char *p, *e;
+ int ok;
+
+ MRP_ASSERT(resmgr, "invalid argument");
+
+ plugin = resmgr->plugin;
+
+ if (!(ctx = plugin->ctx) || !(resolver = ctx->r))
+ return;
+
+ if (!(ndep = resmgr->ndepend) || !resmgr->depends)
+ return;
+
+ MRP_ASSERT(ndep < MRP_ARRAY_SIZE(deps), "dependency overflow");
+
+ for (e = (p = buf) + sizeof(buf), i = 0; i < ndep; i++) {
+ deps[i] = resmgr->depends[i].db_table_name;
+
+ if (p < e)
+ p += snprintf(p, e-p, " %s", resmgr->depends[i].db_table_name);
+ }
+
+ printf("%s:%s\n\tresource_recalc()\n\n", target, buf);
+
+ ok = mrp_resolver_add_prepared_target(resolver, target, deps, ndep,
+ &resource_updater, NULL, resmgr);
+ if (!ok) {
+ mrp_log_error("gam-resource-manager: failed to install "
+ "resolver target '%s'", target);
+ }
+}
+
+
+static void print_resources_cb(mrp_console_t *c, void *user_data,
+ int argc, char **argv)
+{
+ MRP_UNUSED(c);
+ MRP_UNUSED(user_data);
+ MRP_UNUSED(argc);
+ MRP_UNUSED(argv);
+
+ printf("Resources managed by gam-resource-manager:\n");
+
+ printf("\n");
+}
+
+static void print_usecase_cb(mrp_console_t *c, void *user_data,
+ int argc, char **argv)
+{
+ mrp_resmgr_t *resmgr;
+ char buf[16384];
+
+ MRP_UNUSED(c);
+ MRP_UNUSED(user_data);
+ MRP_UNUSED(argc);
+ MRP_UNUSED(argv);
+
+ if ((resmgr = resmgr_data)) {
+ mrp_usecase_print(resmgr->usecase, buf, sizeof(buf));
+ printf("Current usecase:\n%s\n", buf);
+ }
+}
+
+
+static mrp_resmgr_config_t *config_create(mrp_plugin_t *plugin)
+{
+ mrp_plugin_arg_t *args = plugin->args;
+ mrp_resmgr_config_t *config;
+
+ if ((config = mrp_allocz(sizeof(mrp_resmgr_config_t)))) {
+ config->confdir = mrp_strdup(args[CONFDIR].str);
+ config->prefix = mrp_strdup(args[PREFIX].str);
+ config->confnams = mrp_strdup(args[DECISION_NAMES].str);
+ config->max_active = args[MAX_ACTIVE].i32;
+ }
+
+ return config;
+}
+
+static void config_destroy(mrp_resmgr_config_t *config)
+{
+ if (config) {
+ mrp_free((void *)config->confdir);
+ mrp_free((void *)config->prefix);
+ mrp_free(config);
+ }
+}
+
+
+static void event_cb(mrp_event_watch_t *w, int id, mrp_msg_t *event_data,
+ void *user_data)
+{
+ mrp_plugin_t *plugin = (mrp_plugin_t *)user_data;
+#if 0
+ mrp_plugin_arg_t *args = plugin->args;
+#endif
+ mrp_resmgr_t *resmgr = (mrp_resmgr_t *)plugin->data;
+ const char *event = mrp_get_event_name(id);
+ uint16_t tag_inst = MRP_PLUGIN_TAG_INSTANCE;
+ uint16_t tag_name = MRP_PLUGIN_TAG_PLUGIN;
+ const char *inst;
+ const char *name;
+ int success;
+
+ MRP_UNUSED(w);
+
+ mrp_log_info("%s: got event 0x%x (%s):", plugin->instance, id, event);
+
+ if (resmgr && event) {
+ if (!strcmp(event, MRP_PLUGIN_EVENT_STARTED)) {
+ success = mrp_msg_get(event_data,
+ MRP_MSG_TAG_STRING(tag_inst, &inst),
+ MRP_MSG_TAG_STRING(tag_name, &name),
+ MRP_MSG_END);
+ if (success) {
+ if (!strcmp(inst, plugin->instance)) {
+ /* initialize here */
+ }
+ }
+ } /* if PLUGIN_STARTED */
+ }
+}
+
+static int subscribe_events(mrp_resmgr_t *resmgr)
+{
+ mrp_plugin_t *plugin = resmgr->plugin;
+ mrp_event_mask_t events;
+
+ mrp_set_named_events(&events,
+ MRP_PLUGIN_EVENT_LOADED,
+ MRP_PLUGIN_EVENT_STARTED,
+ MRP_PLUGIN_EVENT_FAILED,
+ MRP_PLUGIN_EVENT_STOPPING,
+ MRP_PLUGIN_EVENT_STOPPED,
+ MRP_PLUGIN_EVENT_UNLOADED,
+ NULL);
+
+ resmgr->w = mrp_add_event_watch(&events, event_cb, plugin);
+
+ return (resmgr->w != NULL);
+}
+
+
+static void unsubscribe_events(mrp_resmgr_t *resmgr)
+{
+ if (resmgr->w) {
+ mrp_del_event_watch(resmgr->w);
+ resmgr->w = NULL;
+ }
+}
+
+
+
+static int manager_init(mrp_plugin_t *plugin)
+{
+ mrp_resmgr_t *resmgr;
+
+ mrp_log_info("%s() called for GAM resource manager instance '%s'...",
+ __FUNCTION__, plugin->instance);
+
+
+ if (!(resmgr = mrp_allocz(sizeof(*resmgr)))) {
+ mrp_log_error("Failed to allocate private data for GAM resource "
+ "manager plugin instance %s.", plugin->instance);
+ return FALSE;
+ }
+
+ resmgr->plugin = plugin;
+ resmgr->config = config_create(plugin);
+ resmgr->backend = mrp_resmgr_backend_create(resmgr);
+ resmgr->sources = mrp_resmgr_sources_create(resmgr);
+ resmgr->sinks = mrp_resmgr_sinks_create(resmgr);
+ resmgr->usecase = mrp_resmgr_usecase_create(resmgr);
+
+ plugin->data = resmgr;
+ resmgr_data = resmgr;
+
+ subscribe_events(resmgr);
+ mqi_open();
+ add_depenedencies_to_resolver(resmgr);
+
+ /*******************************/
+ mrp_resmgr_sink_add(resmgr, "speakers" , 0, NULL);
+ mrp_resmgr_sink_add(resmgr, "wiredHeadset" , 0, NULL);
+ mrp_resmgr_sink_add(resmgr, "usbHeadset" , 0, NULL);
+ mrp_resmgr_sink_add(resmgr, "btHeadset" , 0, NULL);
+ mrp_resmgr_sink_add(resmgr, "voiceRecognition", 0, NULL);
+
+ mrp_resmgr_source_add(resmgr, "wrtApplication", 0);
+ mrp_resmgr_source_add(resmgr, "icoApplication", 0);
+ mrp_resmgr_source_add(resmgr, "phone" , 0);
+ mrp_resmgr_source_add(resmgr, "radio" , 0);
+ mrp_resmgr_source_add(resmgr, "microphone" , 0);
+ mrp_resmgr_source_add(resmgr, "navigator" , 0);
+ /*******************************/
+
+ return TRUE;
+}
+
+
+static void manager_exit(mrp_plugin_t *plugin)
+{
+ mrp_resmgr_t *resmgr;
+ size_t i;
+
+ mrp_log_info("%s() called for GAM resource manager instance '%s'...",
+ __FUNCTION__, plugin->instance);
+
+ if ((resmgr = plugin->data) && resmgr_data == resmgr) {
+ unsubscribe_events(resmgr);
+
+ for (i = 0; i < resmgr->ndepend; i++)
+ mrp_free((void *)resmgr->depends[i].db_table_name);
+ mrp_free((void *)resmgr->depends);
+
+ mrp_resmgr_backend_destroy(resmgr->backend);
+ mrp_resmgr_sources_destroy(resmgr->sources);
+ mrp_resmgr_sinks_destroy(resmgr->sinks);
+ mrp_resmgr_usecase_destroy(resmgr->usecase);
+ config_destroy(resmgr->config);
+
+ mrp_free(resmgr);
+
+ resmgr_data = NULL;
+ }
+}
+
+
+#define MANAGER_DESCRIPTION "Plugin to implement GAM resources"
+#define MANAGER_HELP "Maybe later ..."
+#define MANAGER_VERSION MRP_VERSION_INT(0, 0, 1)
+#define MANAGER_AUTHORS "Janos Kovacs <jankovac503@gmail.com>"
+
+#define STRING_ARG(_id,_n,_d) MRP_PLUGIN_ARGIDX(_id, STRING, _n, _d)
+#define INTEGER_ARG(_id,_n,_d) MRP_PLUGIN_ARGIDX(_id, INT32, _n, _d)
+
+static mrp_plugin_arg_t arg_defs[] = {
+ STRING_ARG (CONFDIR , "config_dir" , MRP_RESMGR_DEFAULT_CONFDIR),
+ STRING_ARG (PREFIX , "prefix" , MRP_RESMGR_DEFAULT_PREFIX ),
+ STRING_ARG (DECISION_NAMES, "decision_names", MRP_RESMGR_DEFAULT_NAMES ),
+ INTEGER_ARG (MAX_ACTIVE , "max_active" , 1 ),
+};
+
+#undef INTEGER_ARG
+#undef STRING_ARG
+
+MURPHY_REGISTER_PLUGIN("gam-resource-manager",
+ MANAGER_VERSION,
+ MANAGER_DESCRIPTION,
+ MANAGER_AUTHORS,
+ MANAGER_HELP,
+ MRP_SINGLETON,
+ manager_init,
+ manager_exit,
+ arg_defs, MRP_ARRAY_SIZE(arg_defs),
+ NULL, 0,
+ NULL, 0,
+ &manager_group);
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ *
+ */
--- /dev/null
+/*
+ * Copyright (c) 2014, 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.
+ */
+
+#ifndef __MURPHY_GAM_RESOURCE_MANAGER_H__
+#define __MURPHY_GAM_RESOURCE_MANAGER_H__
+
+#include <murphy/resource/data-types.h>
+
+#define MRP_RESMGR_PLAYBACK_RESOURCE "audio_playback"
+#define MRP_RESMGR_RECORDING_RESOURCE "audio_recording"
+
+#define MRP_RESMGR_SOURCE_STATE_TABLE "audio_manager_sources"
+#define MRP_RESMGR_SINK_STATE_TABLE "audio_manager_sinks"
+
+#define MRP_RESMGR_DEFAULT_CONFDIR "/etc/murphy/gam_config"
+#define MRP_RESMGR_DEFAULT_PREFIX "gam"
+#define MRP_RESMGR_DEFAULT_NAMES MRP_RESMGR_DEFAULT_PREFIX
+#define MRP_RESMGR_RESOURCE_MAX 256
+#define MRP_RESMGR_SOURCE_MAX 64
+#define MRP_RESMGR_SINK_MAX 64
+#define MRP_RESMGR_USECASE_SIZE_MAX 128
+
+#define MRP_RESMGR_RESOURCE_BUCKETS (MRP_RESMGR_RESOURCE_MAX / 4)
+#define MRP_RESMGR_SOURCE_BUCKETS (MRP_RESMGR_SOURCE_MAX / 4)
+#define MRP_RESMGR_SINK_BUCKETS (MRP_RESMGR_SINK_MAX / 4)
+#define MRP_RESMGR_USECASE_SIZE_BUCKETS (MRP_RESMGR_USECASE_SIZE_MAX / 4)
+
+#define MRP_RESMGR_RESOURCE_TYPE_PLAYBACK 0
+#define MRP_RESMGR_RESOURCE_TYPE_RECORDING 1
+#define MRP_RESMGR_RESOURCE_TYPE_MAX 2
+
+typedef struct mrp_resmgr_s mrp_resmgr_t;
+typedef struct mrp_resmgr_config_s mrp_resmgr_config_t;
+typedef struct mrp_resmgr_backend_s mrp_resmgr_backend_t;
+typedef struct mrp_resmgr_resource_s mrp_resmgr_resource_t;
+typedef struct mrp_resmgr_sources_s mrp_resmgr_sources_t;
+typedef struct mrp_resmgr_source_s mrp_resmgr_source_t;
+typedef struct mrp_resmgr_sinks_s mrp_resmgr_sinks_t;
+typedef struct mrp_resmgr_sink_s mrp_resmgr_sink_t;
+typedef struct mrp_resmgr_usecase_s mrp_resmgr_usecase_t;
+
+typedef bool (*mrp_resmgr_dependency_cb_t)(mrp_resmgr_t *);
+
+struct mrp_resmgr_config_s {
+ const char *confdir;
+ const char *prefix;
+ const char *confnams;
+ int max_active;
+};
+
+void mrp_resmgr_register_dependency(mrp_resmgr_t *resmgr,
+ const char *db_table_name,
+ mrp_resmgr_dependency_cb_t callback);
+
+mrp_resmgr_config_t *mrp_resmgr_get_config(mrp_resmgr_t *resmgr);
+mrp_resmgr_backend_t *mrp_resmgr_get_backend(mrp_resmgr_t *resmgr);
+mrp_resmgr_sources_t *mrp_resmgr_get_sources(mrp_resmgr_t *resmgr);
+mrp_resmgr_sinks_t *mrp_resmgr_get_sinks(mrp_resmgr_t *resmgr);
+mrp_resmgr_usecase_t *mrp_resmgr_get_usecase(mrp_resmgr_t *resmgr);
+
+#endif /* __MURPHY_GAM_RESOURCE_MANAGER_H__ */
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ *
+ */
--- /dev/null
+/*
+ * Copyright (c) 2014, 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 <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <murphy/common.h>
+
+#include <murphy-db/mqi.h>
+
+#include "sink.h"
+#include "source.h"
+#include "c5-decision-tree.h"
+
+#define COLUMN_MAX 4
+
+typedef struct gam_sink_s gam_sink_t;
+typedef struct table_s table_t;
+typedef struct row_s row_t;
+typedef struct colum_def_s column_def_t;
+
+struct table_s {
+ mqi_handle_t handle;
+ mqi_column_desc_t cols[COLUMN_MAX+1];
+};
+
+struct row_s {
+ int32_t id;
+ const char *name;
+ int32_t available;
+ int32_t visible;
+};
+
+struct colum_def_s {
+ char *name;
+ mqi_data_type_t type;
+ int offset;
+};
+
+struct mrp_resmgr_sinks_s {
+ mrp_resmgr_t *resmgr;
+ struct {
+ mrp_htbl_t *by_name;
+ mrp_htbl_t *by_id;
+ } lookup;
+ table_t state_table;
+};
+
+struct gam_sink_s {
+ const char *name;
+ uint16_t id;
+};
+
+
+struct mrp_resmgr_sink_s {
+ mrp_resmgr_sinks_t *sinks;
+ gam_sink_t gam_sink;
+ mrp_htbl_t *decision_ids;
+ bool available;
+};
+
+static bool register_gam_id(mrp_resmgr_sink_t *, uint16_t);
+
+static void sink_free(void *, void *);
+
+static int hash_compare(const void *, const void *);
+static uint32_t id_hash_function(const void *);
+static uint32_t ptr_hash_function(const void *);
+
+static bool sink_status_changed_cb(mrp_resmgr_t *);
+static mqi_handle_t get_table_handle(mrp_resmgr_sinks_t *);
+
+
+
+mrp_resmgr_sinks_t *mrp_resmgr_sinks_create(mrp_resmgr_t *resmgr)
+{
+ mrp_resmgr_sinks_t *sinks;
+ mrp_htbl_config_t ncfg, icfg;
+
+ MRP_ASSERT(resmgr, "invalid argument");
+
+ memset(&ncfg, 0, sizeof(ncfg));
+ ncfg.nentry = MRP_RESMGR_SINK_MAX;
+ ncfg.comp = mrp_string_comp;
+ ncfg.hash = mrp_string_hash;
+ ncfg.free = sink_free;
+ ncfg.nbucket = MRP_RESMGR_SINK_BUCKETS;
+
+ memset(&icfg, 0, sizeof(icfg));
+ icfg.nentry = MRP_RESMGR_SINK_MAX;
+ icfg.comp = hash_compare;
+ icfg.hash = id_hash_function;
+ icfg.free = NULL;
+ icfg.nbucket = MRP_RESMGR_SINK_BUCKETS;
+
+ if ((sinks = mrp_allocz(sizeof(mrp_resmgr_sinks_t)))) {
+ sinks->resmgr = resmgr;
+ sinks->lookup.by_name = mrp_htbl_create(&ncfg);
+ sinks->lookup.by_id = mrp_htbl_create(&icfg);
+ sinks->state_table.handle = MQI_HANDLE_INVALID;
+
+ mrp_resmgr_register_dependency(resmgr, MRP_RESMGR_SINK_STATE_TABLE,
+ sink_status_changed_cb);
+ }
+
+ return sinks;
+}
+
+void mrp_resmgr_sinks_destroy(mrp_resmgr_sinks_t *sinks)
+{
+ if (sinks) {
+ mrp_htbl_destroy(sinks->lookup.by_id, false);
+ mrp_htbl_destroy(sinks->lookup.by_name, true);
+ mrp_free(sinks);
+ }
+}
+
+mrp_resmgr_sink_t *mrp_resmgr_sink_add(mrp_resmgr_t *resmgr,
+ const char *name,
+ int32_t id,
+ mrp_resmgr_source_t *source)
+{
+ mrp_resmgr_config_t *config;
+ mrp_resmgr_sinks_t *sinks;
+ mrp_resmgr_sink_t *sink;
+ char *name_dup;
+ mrp_htbl_config_t cfg;
+
+ MRP_ASSERT(resmgr && name, "invalid argument");
+
+ config = mrp_resmgr_get_config(resmgr);
+ sinks = mrp_resmgr_get_sinks(resmgr);
+
+ MRP_ASSERT(config && sinks, "internal error");
+
+ if (!(sink = mrp_resmgr_sink_find_by_name(resmgr, name))) {
+
+ /* new sink */
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.nentry = MRP_RESMGR_SOURCE_MAX;
+ cfg.comp = hash_compare;
+ cfg.hash = ptr_hash_function;
+ cfg.free = NULL;
+ cfg.nbucket = MRP_RESMGR_SOURCE_BUCKETS;
+
+ if ((sink = mrp_allocz(sizeof(mrp_resmgr_sink_t))) &&
+ (name_dup = mrp_strdup(name)))
+ {
+ sink->sinks = sinks;
+ sink->gam_sink.name = name_dup;
+ sink->decision_ids = mrp_htbl_create(&cfg);
+
+ if (!mrp_htbl_insert(sinks->lookup.by_name, name_dup, sink)) {
+ mrp_log_error("gam-resource-manager: attempt to add sink "
+ "'%s' multiple times", name_dup);
+
+ sink_free((void *)sink->gam_sink.name, (void *)sink);
+ sink = NULL;
+ }
+ }
+ }
+
+ if (sink) {
+ if (!source) {
+ /* id is a gam sink ID */
+ register_gam_id(sink, id);
+ }
+ else {
+ /* id is the enumeration of the source in the decision conf */
+ if (!(mrp_htbl_insert(sink->decision_ids, source, NULL + (id+1)))){
+ mrp_log_error("gam-resource-manager: attempt to add id %d "
+ "multiple time for source '%s'",
+ id, mrp_resmgr_source_get_name(source));
+ }
+ }
+ }
+
+ return sink;
+}
+
+mrp_resmgr_sink_t *mrp_resmgr_sink_find_by_name(mrp_resmgr_t *resmgr,
+ const char *name)
+{
+ mrp_resmgr_sinks_t *sinks;
+
+ MRP_ASSERT(resmgr && name, "invalid argument");
+
+ if (!(sinks = mrp_resmgr_get_sinks(resmgr)) || !(sinks->lookup.by_name))
+ return NULL;
+
+ return mrp_htbl_lookup(sinks->lookup.by_name, (void *)name);
+}
+
+
+mrp_resmgr_sink_t *mrp_resmgr_sink_find_by_gam_id(mrp_resmgr_t *resmgr,
+ uint16_t gam_id)
+{
+ mrp_resmgr_sinks_t *sinks;
+
+ MRP_ASSERT(resmgr, "invalid argument");
+
+ if (!(sinks = mrp_resmgr_get_sinks(resmgr)) || !(sinks->lookup.by_id))
+ return NULL;
+
+ return mrp_htbl_lookup(sinks->lookup.by_id, NULL + gam_id);
+}
+
+
+const char *mrp_resmgr_sink_get_name(mrp_resmgr_sink_t *sink)
+{
+ MRP_ASSERT(sink, "invalid argument");
+
+ return sink->gam_sink.name;
+}
+
+bool mrp_resmgr_sink_get_availability(mrp_resmgr_sink_t *sink)
+{
+ if (!sink)
+ return false;
+
+ return sink->available;
+}
+
+
+int32_t mrp_resmgr_sink_get_decision_id(mrp_resmgr_sink_t *sink,
+ mrp_resmgr_source_t *source)
+{
+ void *void_id;
+
+ if (!sink || !source)
+ return -1;
+
+ if (!(void_id = mrp_htbl_lookup(sink->decision_ids, source)))
+ return -1;
+
+ return (void_id - NULL) - 1;
+}
+
+static bool register_gam_id(mrp_resmgr_sink_t *sink, uint16_t gam_id)
+{
+ mrp_resmgr_sinks_t *sinks;
+
+ if (!(sinks = sink->sinks))
+ return false;
+
+ if (!gam_id || gam_id == sink->gam_sink.id)
+ return true;
+
+ if (sink->gam_sink.id) {
+ mrp_log_error("gam-resource-manager: attempt to reset "
+ "gam ID of '%s'", sink->gam_sink.name);
+ return false;
+ }
+
+ if (!mrp_htbl_insert(sinks->lookup.by_id, NULL+gam_id, sink)) {
+ mrp_log_error("gam-resource-manager: attempt to add "
+ "sink %d multiple times", gam_id);
+ return false;
+ }
+
+ sink->gam_sink.id = gam_id;
+
+ mrp_debug("assign id %d to sink '%s'", gam_id, sink->gam_sink.name);
+
+
+ return true;
+}
+
+static void sink_free(void *key, void *object)
+{
+ mrp_resmgr_sink_t *sink = (mrp_resmgr_sink_t *)object;
+
+ MRP_ASSERT(key && object, "internal error");
+ MRP_ASSERT(sink->gam_sink.name == (const char *)key, "corrupt data");
+
+ mrp_htbl_destroy(sink->decision_ids, false);
+
+ mrp_free((void *)sink->gam_sink.name);
+
+ free(sink);
+}
+
+static int hash_compare(const void *key1, const void *key2)
+{
+ if (key1 < key2)
+ return -1;
+ if (key1 > key2)
+ return 1;
+ return 0;
+}
+
+static uint32_t id_hash_function(const void *key)
+{
+ return (uint32_t)(key - (const void *)0);
+}
+
+static uint32_t ptr_hash_function(const void *key)
+{
+ return (uint32_t)(((size_t)key >> 4) & 0xffffffff);
+}
+
+static bool sink_status_changed_cb(mrp_resmgr_t *resmgr)
+{
+ mrp_resmgr_sinks_t *sinks;
+ mrp_resmgr_sink_t *sink;
+ mqi_handle_t h;
+ int i, n;
+ row_t rows[MRP_RESMGR_SOURCE_MAX];
+ row_t *r;
+ int change_count;
+
+ MRP_ASSERT(resmgr, "invalid argument");
+
+ printf("### %s() called\n", __FUNCTION__);
+
+ if (!(sinks = mrp_resmgr_get_sinks(resmgr)) ||
+ !sinks->lookup.by_name)
+ return false;
+
+ if ((h = get_table_handle(sinks)) == MQI_HANDLE_INVALID) {
+ mrp_log_error("gam-resource-manager: can't update status changes: "
+ "database error");
+ return false;
+ }
+
+ memset(rows, 0, sizeof(rows));
+
+ if ((n = MQI_SELECT(sinks->state_table.cols, h, MQI_ALL, rows)) < 0) {
+ mrp_log_error("gam-resource-manager: select on table '%s' failed: %s",
+ MRP_RESMGR_SINK_STATE_TABLE, strerror(errno));
+ return false;
+ }
+
+ if (n == 0)
+ return false;
+
+ for (change_count = i = 0; i < n; i++) {
+ r = rows + i;
+
+ if (!r->visible)
+ continue;
+
+ if ((sink = mrp_htbl_lookup(sinks->lookup.by_name, (void *)r->name))) {
+ register_gam_id(sink, r->id);
+
+ if (( r->available && !sink->available) ||
+ (!r->available && sink->available) )
+ {
+ sink->available = r->available;
+ change_count++;
+
+ mrp_debug("%s become %savailable", sink->gam_sink.name,
+ sink->available ? "":"un");
+ }
+ }
+ }
+
+ return change_count > 0;
+}
+
+
+static mqi_handle_t get_table_handle(mrp_resmgr_sinks_t *sinks)
+{
+#define COLUMN(_n, _t) { # _n, mqi_ ## _t, MQI_OFFSET(row_t, _n) }
+
+ static column_def_t col_defs[COLUMN_MAX] = {
+ COLUMN( id , integer ),
+ COLUMN( name , string ),
+ COLUMN( available, integer ),
+ COLUMN( visible , integer ),
+ };
+
+ mqi_handle_t h;
+ column_def_t *def;
+ mqi_column_desc_t *desc;
+ int i;
+
+ if (sinks->state_table.handle == MQI_HANDLE_INVALID) {
+ h = mqi_get_table_handle(MRP_RESMGR_SINK_STATE_TABLE);
+
+ if (h != MQI_HANDLE_INVALID) {
+ sinks->state_table.handle = h;
+
+ for (i = 0; i < COLUMN_MAX; i++) {
+ def = col_defs + i;
+ desc = sinks->state_table.cols + i;
+
+ if ((desc->cindex = mqi_get_column_index(h, def->name)) < 0) {
+ mrp_log_error("gam-resource-manager: can't find column "
+ "'%s' in table '%s'", def->name,
+ MRP_RESMGR_SINK_STATE_TABLE);
+ sinks->state_table.handle = MQI_HANDLE_INVALID;
+ break;
+ }
+
+ desc->offset = def->offset;
+ }
+
+ desc = sinks->state_table.cols + i;
+ desc->cindex = -1;
+ desc->offset = -1;
+ }
+
+ }
+
+ return sinks->state_table.handle;
+
+#undef COLUMN
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, 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.
+ */
+
+#ifndef __MURPHY_GAM_RESOURCE_MANAGER_SINK_H__
+#define __MURPHY_GAM_RESOURCE_MANAGER_SINK_H__
+
+#include "plugin-gam-resource-manager.h"
+
+
+mrp_resmgr_sinks_t *mrp_resmgr_sinks_create(mrp_resmgr_t *resmgr);
+void mrp_resmgr_sinks_destroy(mrp_resmgr_sinks_t *sinks);
+
+mrp_resmgr_sink_t *mrp_resmgr_sink_find_by_name(mrp_resmgr_t *resmgr,
+ const char *name);
+mrp_resmgr_sink_t *mrp_resmgr_sink_find_by_gam_id(mrp_resmgr_t *resmgr,
+ uint16_t gam_id);
+
+const char *mrp_resmgr_sink_get_name(mrp_resmgr_sink_t *sink);
+bool mrp_resmgr_sink_get_availability(mrp_resmgr_sink_t *sink);
+int32_t mrp_resmgr_sink_get_decision_id(mrp_resmgr_sink_t *sink,
+ mrp_resmgr_source_t *source);
+
+mrp_resmgr_sink_t *mrp_resmgr_sink_add(mrp_resmgr_t *resmgr,
+ const char *gam_name,
+ int32_t id,
+ mrp_resmgr_source_t *source);
+
+
+#endif /* __MURPHY_GAM_RESOURCE_MANAGER_SINK_H__ */
--- /dev/null
+/*
+ * Copyright (c) 2014, 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 <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <murphy/common.h>
+
+#include <murphy-db/mqi.h>
+
+#include "source.h"
+#include "usecase.h"
+#include "backend.h"
+
+#define COLUMN_MAX 4
+
+typedef struct gam_source_s gam_source_t;
+typedef struct table_s table_t;
+typedef struct row_s row_t;
+typedef struct colum_def_s column_def_t;
+
+struct table_s {
+ mqi_handle_t handle;
+ mqi_column_desc_t cols[COLUMN_MAX+1];
+};
+
+struct row_s {
+ int32_t id;
+ const char *name;
+ int32_t available;
+ int32_t visible;
+};
+
+struct colum_def_s {
+ char *name;
+ mqi_data_type_t type;
+ int offset;
+};
+
+
+struct mrp_resmgr_sources_s {
+ mrp_resmgr_t *resmgr;
+ struct {
+ mrp_htbl_t *by_name;
+ mrp_htbl_t *by_id;
+ } lookup;
+ mrp_decision_conf_t *decision_conf;
+ table_t state_table;
+};
+
+struct gam_source_s {
+ const char *name;
+ uint16_t id;
+};
+
+
+struct mrp_resmgr_source_s {
+ mrp_resmgr_sources_t *sources;
+ gam_source_t gam_source;
+ mrp_list_hook_t resources;
+ mrp_decision_tree_t *decision_tree;
+ bool available;
+};
+
+
+static bool register_gam_id(mrp_resmgr_source_t *, uint16_t);
+
+static mrp_decision_conf_t *load_decision_conf(const char *);
+static bool decision_values_match(mrp_decision_conf_t *);
+
+static void source_free(void *, void *);
+static int id_hash_compare(const void *, const void *);
+static uint32_t id_hash_function(const void *);
+
+static bool source_status_changed_cb(mrp_resmgr_t *);
+static mqi_handle_t get_table_handle(mrp_resmgr_sources_t *);
+
+
+mrp_resmgr_sources_t *mrp_resmgr_sources_create(mrp_resmgr_t *resmgr)
+{
+ mrp_resmgr_config_t *config;
+ mrp_resmgr_sources_t *sources;
+ mrp_htbl_config_t ncfg, icfg;
+ char stem[1024];
+
+ MRP_ASSERT(resmgr, "invalid argument");
+
+ config = mrp_resmgr_get_config(resmgr);
+ snprintf(stem, sizeof(stem), "%s/%s", config->confdir, config->confnams);
+
+ memset(&ncfg, 0, sizeof(ncfg));
+ ncfg.nentry = MRP_RESMGR_SOURCE_MAX;
+ ncfg.comp = mrp_string_comp;
+ ncfg.hash = mrp_string_hash;
+ ncfg.free = source_free;
+ ncfg.nbucket = MRP_RESMGR_SOURCE_BUCKETS;
+
+ memset(&icfg, 0, sizeof(icfg));
+ icfg.nentry = MRP_RESMGR_SOURCE_MAX;
+ icfg.comp = id_hash_compare;
+ icfg.hash = id_hash_function;
+ icfg.free = NULL;
+ icfg.nbucket = MRP_RESMGR_SOURCE_BUCKETS;
+
+ if ((sources = mrp_allocz(sizeof(mrp_resmgr_sources_t)))) {
+ sources->resmgr = resmgr;
+ sources->lookup.by_name = mrp_htbl_create(&ncfg);
+ sources->lookup.by_id = mrp_htbl_create(&icfg);
+ sources->decision_conf = load_decision_conf(stem);
+ sources->state_table.handle = MQI_HANDLE_INVALID;
+
+ mrp_resmgr_register_dependency(resmgr, MRP_RESMGR_SOURCE_STATE_TABLE,
+ source_status_changed_cb);
+ }
+
+ return sources;
+}
+
+
+void mrp_resmgr_sources_destroy(mrp_resmgr_sources_t *sources)
+{
+ if (sources) {
+ mrp_decision_conf_destroy(sources->decision_conf);
+
+ mrp_htbl_destroy(sources->lookup.by_id, false);
+ mrp_htbl_destroy(sources->lookup.by_name, true);
+
+ mrp_free(sources);
+ }
+}
+
+mrp_decision_conf_t *mrp_resmgr_sources_get_decision_conf(mrp_resmgr_t *resmgr)
+{
+ mrp_resmgr_sources_t *sources;
+
+ if (!resmgr || !(sources = mrp_resmgr_get_sources(resmgr)))
+ return NULL;
+
+ return sources->decision_conf;
+}
+
+mrp_resmgr_source_t *mrp_resmgr_source_add(mrp_resmgr_t *resmgr,
+ const char *gam_name,
+ uint16_t gam_id)
+{
+#define ATTR_MAX MRP_RESMGR_USECASE_SIZE_MAX
+
+ mrp_resmgr_config_t *config;
+ mrp_resmgr_sources_t *sources;
+ mrp_resmgr_usecase_t *usecase;
+ mrp_resmgr_source_t *src;
+ char *gam_name_dup;
+ mrp_decision_conf_t *dc;
+ ssize_t nattr, i;
+ const char *attrs[ATTR_MAX];
+ ssize_t offs;
+ char stem[1024];
+
+ MRP_ASSERT(resmgr && gam_name, "invalid argument");
+
+ config = mrp_resmgr_get_config(resmgr);
+ sources = mrp_resmgr_get_sources(resmgr);
+ usecase = mrp_resmgr_get_usecase(resmgr);
+
+ MRP_ASSERT(config && sources && usecase, "internal error");
+
+ if (!(src = mrp_resmgr_source_find_by_name(resmgr, gam_name))) {
+ snprintf(stem, sizeof(stem), "%s/%s-%s-%d", config->confdir,
+ config->prefix, gam_name, config->max_active);
+
+ dc = sources->decision_conf;
+ nattr = mrp_decision_attr_list(dc, attrs, ATTR_MAX);
+
+ if (dc && nattr > 0 &&
+ (src = mrp_allocz(sizeof(mrp_resmgr_source_t))) &&
+ (gam_name_dup = mrp_strdup(gam_name)))
+ {
+ src->sources = sources;
+ src->gam_source.name = gam_name_dup;
+ src->gam_source.id = gam_id;
+ mrp_list_init(&src->resources);
+
+ if (!mrp_htbl_insert(sources->lookup.by_name, gam_name_dup, src)) {
+ mrp_log_error("gam-resource-manager: attempt to add source "
+ "'%s' multiple times", gam_name_dup);
+ goto failed;
+ }
+
+ for (i = 0; i < nattr; i++) {
+ offs = mrp_resmgr_usecase_add_attribute(usecase,src,attrs[i]);
+
+ if (offs < 0) {
+ mrp_log_error("gam-resource-manager: failed to add "
+ "attribute '%s' to source '%s'",
+ attrs[i], gam_name);
+ }
+ else {
+ if (!mrp_decision_set_attr_offset(dc, attrs[i], offs)) {
+ mrp_log_error("gam-resource-manager: failed to set "
+ "offset for attribute '%s' in source "
+ "'%s'", attrs[i], gam_name);
+ }
+ }
+ }
+
+ src->decision_tree = mrp_decision_tree_create_from_file(dc, stem);
+
+ if (!src->decision_tree) {
+ mrp_log_error("gam-resource-manager: source '%s' "
+ "is nonfunctional", gam_name);
+ }
+ }
+ }
+
+ if (src) {
+ register_gam_id(src, gam_id);
+ }
+
+ return src;
+
+ failed:
+ if (src)
+ source_free((void *)src->gam_source.name, (void *)src);
+ return NULL;
+
+#undef ATTR_MAX
+}
+
+mrp_resmgr_source_t *mrp_resmgr_source_find_by_name(mrp_resmgr_t *resmgr,
+ const char *gam_name)
+{
+ mrp_resmgr_sources_t *sources;
+
+ MRP_ASSERT(resmgr && gam_name, "invalid argument");
+
+ if (!(sources = mrp_resmgr_get_sources(resmgr)) ||
+ !(sources->lookup.by_name))
+ {
+ return NULL;
+ }
+
+ return mrp_htbl_lookup(sources->lookup.by_name, (void *)gam_name);
+}
+
+
+mrp_resmgr_source_t *mrp_resmgr_source_find_by_id(mrp_resmgr_t *resmgr,
+ uint16_t gam_id)
+{
+ mrp_resmgr_sources_t *sources;
+
+ MRP_ASSERT(resmgr, "invalid argument");
+
+ if (!(sources = mrp_resmgr_get_sources(resmgr)) ||
+ !(sources->lookup.by_id))
+ {
+ return NULL;
+ }
+
+ return mrp_htbl_lookup(sources->lookup.by_id, NULL + gam_id);
+}
+
+
+
+
+const char *mrp_resmgr_source_get_name(mrp_resmgr_source_t *src)
+{
+ if (!src)
+ return "<invalid>";
+
+ return src->gam_source.name;
+}
+
+bool mrp_resmgr_source_get_availability(mrp_resmgr_source_t *src)
+{
+ if (!src)
+ return false;
+
+ return src->available;
+}
+
+
+mrp_resmgr_resource_t *mrp_resmgr_source_get_resource(mrp_resmgr_source_t *src,
+ uint32_t connno)
+{
+ mrp_list_hook_t *entry, *n;
+ mrp_resmgr_resource_t *ar;
+
+ MRP_ASSERT(src, "invalid argument");
+
+ mrp_list_foreach(&src->resources, entry, n) {
+ ar = mrp_resmgr_backend_resource_list_entry(entry);
+ if (connno == mrp_resmgr_backend_get_resource_connno(ar))
+ return ar;
+ }
+
+ return NULL;
+}
+
+bool mrp_resmgr_source_add_resource(mrp_resmgr_source_t *src,
+ mrp_list_hook_t *ar_source_link)
+{
+ mrp_resmgr_resource_t *ar, *ar2;
+ uint32_t connno, connno2;
+ mrp_list_hook_t *entry, *n;
+ mrp_list_hook_t *insert_after;
+ bool success;
+
+ MRP_ASSERT(src && ar_source_link, "invalid argument");
+
+ ar = mrp_resmgr_backend_resource_list_entry(ar_source_link);
+ connno = mrp_resmgr_backend_get_resource_connno(ar);
+
+ success = true;
+ insert_after = &src->resources;
+
+ mrp_list_foreach(&src->resources, entry, n) {
+ ar2 = mrp_resmgr_backend_resource_list_entry(entry);
+ connno2 = mrp_resmgr_backend_get_resource_connno(ar2);
+
+ if (connno2 == connno) {
+ success = false;
+ break;
+ }
+
+ if (connno2 < connno)
+ insert_after = entry;
+ }
+
+ if (success)
+ mrp_list_insert_after(insert_after, ar_source_link);
+
+ return success;
+}
+
+int32_t mrp_resmgr_source_make_decision(mrp_resmgr_source_t *src)
+{
+ mrp_resmgr_t *resmgr;
+ mrp_resmgr_sources_t *sources;
+ mrp_resmgr_usecase_t *usecase;
+ void *input;
+ mrp_decision_value_type_t type;
+ mrp_decision_value_t *value;
+ int32_t decision;
+
+ MRP_ASSERT(src && src->sources && src->sources->resmgr,"invalid argument");
+
+ sources = src->sources;
+ resmgr = sources->resmgr;
+ usecase = mrp_resmgr_get_usecase(resmgr);
+ input = mrp_resmgr_usecase_get_decision_input(usecase);
+
+ if (!mrp_decision_make(src->decision_tree, input, &type, &value))
+ decision = -1;
+ else
+ decision = value->integer;
+
+ return decision;
+}
+
+static bool register_gam_id(mrp_resmgr_source_t *src, uint16_t gam_id)
+{
+ mrp_resmgr_sources_t *sources;
+
+ if (!(sources = src->sources))
+ return false;
+
+ if (!gam_id || gam_id == src->gam_source.id)
+ return true;
+
+ if (src->gam_source.id) {
+ mrp_log_error("gam-resource-manager: attempt to reset "
+ "gam ID of '%s'", src->gam_source.name);
+ return false;
+ }
+
+ if (!mrp_htbl_insert(sources->lookup.by_id, NULL+gam_id, src)) {
+ mrp_log_error("gam-resource-manager: attempt to add source "
+ "%d multiple times", gam_id);
+ return false;
+ }
+
+ src->gam_source.id = gam_id;
+
+ mrp_debug("assign id %d to source '%s'", gam_id, src->gam_source.name);
+
+ return true;
+}
+
+static mrp_decision_conf_t *load_decision_conf(const char *stem)
+{
+ mrp_decision_conf_t *conf;
+
+ if (!(conf = mrp_decision_conf_create_from_file(stem))) {
+ mrp_log_error("gam-resource-manager: can't load "
+ "decision conf file %s.names", stem);
+ }
+ else if (!decision_values_match(conf)) {
+ mrp_log_error("gam-resource-manager: decision values in conf file "
+ "%s.name do not match their builtin counterpart", stem);
+
+ mrp_decision_conf_destroy(conf);
+ conf = NULL;
+ }
+
+ return conf;
+}
+
+static bool decision_values_match(mrp_decision_conf_t *conf)
+{
+ const char **names = mrp_resmgr_backend_get_decision_names();
+ int32_t i;
+
+ if (!conf)
+ return false;
+
+ for (i = 0; names[i]; i++) {
+ if (strcmp(names[i], mrp_decision_name(conf, i)))
+ return false;
+ }
+
+ return (i > 0 && i == mrp_decision_value_max(conf));
+}
+
+static void source_free(void *key, void *object)
+{
+ mrp_resmgr_source_t *src = (mrp_resmgr_source_t *)object;
+
+ MRP_ASSERT(key && object, "internal error");
+ MRP_ASSERT(src->gam_source.name == (const char *)key, "corrupt data");
+ MRP_ASSERT(mrp_list_empty(&src->resources), "resource list not empty");
+
+ mrp_decision_tree_destroy(src->decision_tree);
+
+ mrp_free((void *)src->gam_source.name);
+
+ mrp_free(src);
+}
+
+static int id_hash_compare(const void *key1, const void *key2)
+{
+ if (key1 < key2)
+ return -1;
+ if (key1 > key2)
+ return 1;
+ return 0;
+}
+
+static uint32_t id_hash_function(const void *key)
+{
+ return (uint32_t)(key - (const void *)0);
+}
+
+
+static bool source_status_changed_cb(mrp_resmgr_t *resmgr)
+{
+ mrp_resmgr_sources_t *sources;
+ mrp_resmgr_source_t *src;
+ mqi_handle_t h;
+ int i, n;
+ row_t rows[MRP_RESMGR_SOURCE_MAX];
+ row_t *r;
+ int change_count;
+
+ MRP_ASSERT(resmgr, "invalid argument");
+
+ printf("### %s() called\n", __FUNCTION__);
+
+ if (!(sources = mrp_resmgr_get_sources(resmgr)) ||
+ !sources->lookup.by_name)
+ return false;
+
+ if ((h = get_table_handle(sources)) == MQI_HANDLE_INVALID) {
+ mrp_log_error("gam-resource-manager: can't update status changes: "
+ "database error");
+ return false;
+ }
+
+ memset(rows, 0, sizeof(rows));
+
+ if ((n = MQI_SELECT(sources->state_table.cols, h, MQI_ALL, rows)) < 0) {
+ mrp_log_error("gam-resource-manager: select on table '%s' failed: %s",
+ MRP_RESMGR_SOURCE_STATE_TABLE, strerror(errno));
+ return false;
+ }
+
+ if (n == 0)
+ return false;
+
+ for (change_count = i = 0; i < n; i++) {
+ r = rows + i;
+
+ if (!r->visible)
+ continue;
+
+ if ((src = mrp_htbl_lookup(sources->lookup.by_name, (void *)r->name))){
+ register_gam_id(src, r->id);
+
+ if (( r->available && !src->available) ||
+ (!r->available && src->available) )
+ {
+ src->available = r->available;
+ change_count++;
+
+ mrp_debug("%s become %savailable", src->gam_source.name,
+ src->available ? "":"un");
+ }
+ }
+ }
+
+ return change_count > 0;
+}
+
+static mqi_handle_t get_table_handle(mrp_resmgr_sources_t *sources)
+{
+#define COLUMN(_n, _t) { # _n, mqi_ ## _t, MQI_OFFSET(row_t, _n) }
+
+ static column_def_t col_defs[COLUMN_MAX] = {
+ COLUMN( id , integer ),
+ COLUMN( name , string ),
+ COLUMN( available, integer ),
+ COLUMN( visible , integer ),
+ };
+
+ mqi_handle_t h;
+ column_def_t *def;
+ mqi_column_desc_t *desc;
+ int i;
+
+ if (sources->state_table.handle == MQI_HANDLE_INVALID) {
+ h = mqi_get_table_handle(MRP_RESMGR_SOURCE_STATE_TABLE);
+
+ if (h != MQI_HANDLE_INVALID) {
+ sources->state_table.handle = h;
+
+ for (i = 0; i < COLUMN_MAX; i++) {
+ def = col_defs + i;
+ desc = sources->state_table.cols + i;
+
+ if ((desc->cindex = mqi_get_column_index(h, def->name)) < 0) {
+ mrp_log_error("gam-resource-manager: can't find column "
+ "'%s' in table '%s'", def->name,
+ MRP_RESMGR_SOURCE_STATE_TABLE);
+ sources->state_table.handle = MQI_HANDLE_INVALID;
+ break;
+ }
+
+ desc->offset = def->offset;
+ }
+
+ desc = sources->state_table.cols + i;
+ desc->cindex = -1;
+ desc->offset = -1;
+ }
+
+ }
+
+ return sources->state_table.handle;
+
+#undef COLUMN
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, 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.
+ */
+
+#ifndef __MURPHY_GAM_RESOURCE_MANAGER_SOURCE_H__
+#define __MURPHY_GAM_RESOURCE_MANAGER_SOURCE_H__
+
+#include "plugin-gam-resource-manager.h"
+#include "c5-decision-tree.h"
+
+
+mrp_resmgr_sources_t *mrp_resmgr_sources_create(mrp_resmgr_t *resmgr);
+void mrp_resmgr_sources_destroy(mrp_resmgr_sources_t *sources);
+
+mrp_decision_conf_t *mrp_resmgr_sources_get_decision_conf(mrp_resmgr_t *resmgr);
+
+mrp_resmgr_source_t *mrp_resmgr_source_add(mrp_resmgr_t *resmgr,
+ const char *gam_name,
+ uint16_t gam_id);
+mrp_resmgr_source_t *mrp_resmgr_source_find_by_name(mrp_resmgr_t *resmgr,
+ const char *gam_name);
+mrp_resmgr_source_t *mrp_resmgr_source_find_by_id(mrp_resmgr_t *resmgr,
+ uint16_t gam_id);
+
+const char *mrp_resmgr_source_get_name(mrp_resmgr_source_t *src);
+bool mrp_resmgr_source_get_availability(mrp_resmgr_source_t *src);
+
+mrp_resmgr_resource_t *mrp_resmgr_source_get_resource(mrp_resmgr_source_t *src,
+ uint32_t connno);
+
+bool mrp_resmgr_source_add_resource(mrp_resmgr_source_t *src,
+ mrp_list_hook_t *ar_source_link);
+int32_t mrp_resmgr_source_make_decision(mrp_resmgr_source_t *src);
+
+
+#endif /* __MURPHY_GAM_RESOURCE_MANAGER_SOURCE_H__ */
--- /dev/null
+/*
+ * Copyright (c) 2014, 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 <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <murphy/common.h>
+
+#include "usecase.h"
+#include "source.h"
+#include "sink.h"
+#include "backend.h"
+#include "c5-decision-tree.h"
+
+typedef enum attr_type_e attr_type_t;
+
+typedef struct update_s update_t;
+typedef struct attr_def_s attr_def_t;
+typedef struct entry_iterator_s entry_iterator_t;
+typedef struct entry_descr_s entry_descr_t;
+
+struct mrp_resmgr_usecase_s {
+ mrp_resmgr_t *resmgr;
+ size_t size;
+ int32_t *vector;
+ uint32_t nentry;
+ mrp_htbl_t *entries;
+ int nupdate;
+ update_t *updates;
+ int nstamp;
+ uint32_t *stamps;
+};
+
+
+struct update_s {
+ mrp_resmgr_source_t *source;
+ uint32_t connno;
+ int32_t attr_idx;
+ uint32_t vector_idx;
+ bool stamp;
+};
+
+enum attr_type_e {
+ REGULAR = 0,
+ STAMP,
+ ROUTE
+};
+
+struct attr_def_s {
+ const char *suffix;
+ size_t len;
+ const char *name;
+ int32_t idx;
+ attr_type_t type;
+};
+
+struct entry_descr_s {
+ const char *name;
+ int update_idx;
+};
+
+struct entry_iterator_s {
+ int maxentry;
+ int nentry;
+ entry_descr_t descs[0];
+};
+
+
+#define ATTR(_s,_n,_id,_b) { _s,sizeof(_s)-1,_n,_id,_b }
+#define ATTR_END { NULL, 0, NULL, 0, false }
+
+static attr_def_t attr_defs[] = {
+ ATTR( "Route", "sink_id", MRP_RESMGR_RESOURCE_FIELD_DECISION_ID, ROUTE ),
+ ATTR( "Stamp", "stamp" , 0 , STAMP ),
+ ATTR( "State", "state" , MRP_RESMGR_RESOURCE_FIELD_STATE , REGULAR ),
+ ATTR_END
+};
+
+#undef ATTR_END
+#undef ATTR
+
+
+
+static void hash_free(void *, void *);
+
+bool parse_name(const char *, const char **, uint32_t *, attr_def_t **,
+ char *, int);
+
+static uint32_t add_update_to_usecase(mrp_resmgr_usecase_t *, int32_t,
+ uint32_t, attr_type_t);
+static uint32_t add_entry_to_vector(mrp_resmgr_usecase_t *);
+static void add_stamp_to_usecase(mrp_resmgr_usecase_t *, uint32_t);
+static void register_sink_ids(mrp_resmgr_usecase_t *, const char *,
+ mrp_resmgr_source_t *);
+
+static void normalise_stamps(int32_t *vector, int nstamp, uint32_t *stamps);
+
+
+static entry_iterator_t *entry_iterator(mrp_resmgr_usecase_t *usecase);
+
+
+
+mrp_resmgr_usecase_t *mrp_resmgr_usecase_create(mrp_resmgr_t *resmgr)
+{
+ mrp_resmgr_usecase_t *usecase;
+ mrp_htbl_config_t cfg;
+ MRP_ASSERT(resmgr, "invalid argument");
+
+ cfg.nentry = MRP_RESMGR_USECASE_SIZE_MAX;
+ cfg.comp = mrp_string_comp;
+ cfg.hash = mrp_string_hash;
+ cfg.free = hash_free;
+ cfg.nbucket = MRP_RESMGR_USECASE_SIZE_BUCKETS;
+
+ if ((usecase = mrp_allocz(sizeof(mrp_resmgr_usecase_t)))) {
+ usecase->resmgr = resmgr;
+ usecase->size = 0;
+ usecase->vector = NULL;
+ usecase->entries = mrp_htbl_create(&cfg);
+ }
+
+ return usecase;
+}
+
+void mrp_resmgr_usecase_destroy(mrp_resmgr_usecase_t *usecase)
+{
+ if (usecase) {
+ mrp_htbl_destroy(usecase->entries, true);
+ mrp_free(usecase->updates);
+ mrp_free(usecase->vector);
+ mrp_free(usecase);
+ }
+}
+
+
+ssize_t mrp_resmgr_usecase_add_attribute(mrp_resmgr_usecase_t *usecase,
+ mrp_resmgr_source_t *source,
+ const char *name)
+{
+ const char *srcnam;
+ uint32_t connno;
+ attr_def_t *atd;
+ ssize_t offs;
+ void *void_idx;
+ int32_t attr_idx;
+ uint32_t idx;
+ uint32_t vect_idx;
+ uint32_t upd_idx;
+ update_t *upd;
+ char buf[256];
+
+ MRP_ASSERT(usecase && source && name, "invalid attribute");
+
+ offs = -1;
+ atd = NULL;
+
+ if (parse_name(name, &srcnam, &connno, &atd, buf,sizeof(buf))) {
+
+ if (!(void_idx = mrp_htbl_lookup(usecase->entries, (void *)name))) {
+ if ((attr_idx = atd->idx) >= 0) {
+ idx = mrp_resmgr_backend_get_attribute_index(atd->name,
+ mqi_integer);
+ if (idx != MRP_RESMGR_RESOURCE_FIELD_INVALID)
+ attr_idx = idx;
+ else {
+ mrp_log_error("gam-resource-manager: can't obtain index "
+ "for resource attribute '%s'", atd->name);
+ goto out;
+ }
+ }
+
+ vect_idx = add_entry_to_vector(usecase);
+ upd_idx = add_update_to_usecase(usecase, attr_idx, vect_idx,
+ atd->type);
+ upd = usecase->updates + upd_idx;
+ void_idx = NULL + (upd_idx + 1);
+
+ if (!mrp_htbl_insert(usecase->entries,mrp_strdup(name),void_idx)) {
+ mrp_log_error("gam-resource-manager: failed to insert into "
+ "hashtable usecase attribute '%s'", name);
+ }
+
+ if (atd->type == STAMP)
+ add_stamp_to_usecase(usecase, vect_idx);
+ }
+ else {
+ upd_idx = (void_idx - NULL) - 1;
+ upd = usecase->updates + upd_idx;
+
+ MRP_ASSERT(usecase->updates && (int)upd_idx < usecase->nupdate,
+ "corrupt data structures");
+
+ vect_idx = upd->vector_idx;
+ }
+
+ if (!strcmp(srcnam, mrp_resmgr_source_get_name(source))) {
+ upd->source = source;
+ upd->connno = connno;
+ }
+
+ if (atd && atd->type == ROUTE)
+ register_sink_ids(usecase, name, source);
+
+ offs = sizeof(usecase->vector[0]) * vect_idx;
+ }
+
+ out:
+ return offs;
+}
+
+
+
+
+void mrp_resmgr_usecase_update(mrp_resmgr_usecase_t *usecase)
+{
+ update_t *upd;
+ mrp_resmgr_resource_t *ar;
+ int32_t *val;
+ int32_t idx;
+ int i;
+
+ MRP_ASSERT(usecase, "invalid argument");
+
+ for (i =0; i < usecase->nupdate; i++) {
+ upd = usecase->updates + i;
+ val = usecase->vector + upd->vector_idx;
+
+ if (!(ar = mrp_resmgr_source_get_resource(upd->source, upd->connno)))
+ *val = 0;
+ else {
+ if ((idx = upd->attr_idx) >= 0)
+ *val = mrp_resmgr_backend_get_integer_attribute(ar, idx);
+ else {
+ switch (idx) {
+ case MRP_RESMGR_RESOURCE_FIELD_STATE:
+ *val = mrp_resmgr_backend_get_resource_state(ar);
+ break;
+ case MRP_RESMGR_RESOURCE_FIELD_DECISION_ID:
+ *val = mrp_resmgr_backend_get_resource_decision_id(ar);
+ break;
+ default:
+ *val = 0;
+ break;
+ }
+ }
+ }
+ }
+
+ normalise_stamps(usecase->vector, usecase->nstamp, usecase->stamps);
+}
+
+void *mrp_resmgr_usecase_get_decision_input(mrp_resmgr_usecase_t *usecase)
+{
+ if (!usecase)
+ return NULL;
+
+ return (void *)usecase->vector;
+}
+
+
+size_t mrp_usecase_print(mrp_resmgr_usecase_t *usecase, char *buf, size_t len)
+{
+#define PRINT(args...) do { if (p<e) p += snprintf(p, e-p, args); } while(0)
+
+ mrp_decision_conf_t *conf;
+ entry_iterator_t *it;
+ entry_descr_t *desc;
+ const char *name;
+ update_t *upd;
+ int32_t value;
+ const char *value_str;
+ char *p, *e;
+ char nbuf[256];
+ bool er;
+ int i;
+
+ conf = mrp_resmgr_sources_get_decision_conf(usecase->resmgr);
+
+ snprintf(buf, len, "<no entries>");
+
+ e = (p = buf) + len;
+
+ if (usecase && buf && len > 0 && (it = entry_iterator(usecase))) {
+ for (i = 0; i < it->nentry; i++) {
+ desc = it->descs + i;
+ name = desc->name;
+ upd = usecase->updates + desc->update_idx;
+ value = usecase->vector[upd->vector_idx];
+
+ snprintf(nbuf, sizeof(nbuf), "%s:", name);
+
+ value_str = mrp_decision_get_integer_attr_name(conf,name,value,&er);
+
+ PRINT("%-24s %s (%d)\n", nbuf, value_str, value);
+ }
+
+ mrp_free(it);
+ }
+
+ return p - buf;
+
+#undef PRINT
+}
+
+
+static void hash_free(void *key, void *object)
+{
+ MRP_UNUSED(object);
+ mrp_free(key);
+}
+
+/*
+ * the syntax of a regular attribute name is as follows:
+ *
+ * - source name, eg. navigator
+ *
+ * - optional digits specifying the connection number
+ * For the first connection, no digits are presents.
+ * Numbering of subsequent connections start from 2.
+ *
+ * - suffix that actually defines the type of the attribute
+ * suffix names and the associated type definitions are
+ * in the filed_defs[] array.
+ */
+bool parse_name(const char *name, const char **source, uint32_t *connno,
+ attr_def_t **attrdef, char *buf, int len)
+{
+ attr_def_t *d;
+ char *suffix;
+ char *p;
+ uint32_t n;
+ int l;
+
+ MRP_ASSERT(name && source && connno && attrdef && buf && len > 0,
+ "invalid arument");
+
+ *source = NULL;
+ *connno = 0;
+ *attrdef = NULL;
+
+ if (len < (l = strlen(name)) + 1)
+ return false;
+
+ memcpy(buf, name, l+1);
+ buf[l] = 0;
+
+
+ for (d = attr_defs; d->suffix; d++) {
+ if ((suffix = strstr(buf, d->suffix)) && !suffix[d->len]) {
+ *suffix = 0;
+
+ for(n = 0, p = suffix - 1; p >= buf && isdigit(*p); p++)
+ ;
+ if (++p < suffix) {
+ if ((n = strtoul(p, NULL, 10)) < 2)
+ return false;
+ *p = 0;
+ }
+
+ if (p <= buf)
+ return false;
+
+ *source = buf;
+ *connno = n;
+ *attrdef = d;
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+static uint32_t add_update_to_usecase(mrp_resmgr_usecase_t *usecase,
+ int32_t attr_idx,
+ uint32_t vector_idx,
+ attr_type_t type)
+{
+ uint32_t i = usecase->nupdate++;
+ size_t size = sizeof(update_t) * usecase->nupdate;
+ update_t *u;
+
+ usecase->updates = mrp_realloc(usecase->updates, size);
+
+ MRP_ASSERT(usecase->updates, "can't allocate memory");
+
+ u = usecase->updates + i;
+ u->source = NULL;
+ u->connno = 0;
+ u->attr_idx = attr_idx;
+ u->vector_idx = vector_idx;
+ u->stamp = (type == STAMP);
+
+ return i;
+}
+
+static uint32_t add_entry_to_vector(mrp_resmgr_usecase_t *usecase)
+{
+ uint32_t idx = usecase->nentry++;
+ size_t size = sizeof(int32_t) * usecase->nentry;
+
+ usecase->vector = mrp_realloc(usecase->vector, size);
+
+ MRP_ASSERT(usecase->vector, "can't allocate memory");
+
+ usecase->vector[idx] = 0;
+
+ return idx;
+}
+
+static void add_stamp_to_usecase(mrp_resmgr_usecase_t *usecase,
+ uint32_t vector_idx)
+{
+ uint32_t idx = usecase->nstamp++;
+ size_t size = sizeof(uint32_t) * usecase->nstamp;
+
+ usecase->stamps = mrp_realloc(usecase->stamps, size);
+
+ MRP_ASSERT(usecase->stamps, "can't allocate memory");
+
+ usecase->stamps[idx] = vector_idx;
+}
+
+
+static void register_sink_ids(mrp_resmgr_usecase_t *usecase,
+ const char *attrnam,
+ mrp_resmgr_source_t *source)
+{
+ mrp_resmgr_t *resmgr;
+ mrp_decision_conf_t *conf;
+ ssize_t i, nvalue;
+ mrp_decision_attr_value_desc_t values[MRP_RESMGR_SINK_MAX];
+ mrp_decision_attr_value_desc_t *dsc;
+
+ resmgr = usecase->resmgr;
+
+ if (source) {
+ conf = mrp_resmgr_sources_get_decision_conf(usecase->resmgr);
+ nvalue = mrp_decision_attr_value_list(conf, attrnam, values,
+ MRP_RESMGR_SINK_MAX);
+ for (i = 0; i < nvalue; i++) {
+ dsc = values + i;
+
+ if (!mrp_resmgr_sink_add(resmgr, dsc->name, dsc->value, source)) {
+ mrp_log_error("gam-resource-manager: failed to add sink '%s' "
+ "with decision id %d", dsc->name, dsc->value);
+ }
+ }
+ }
+}
+
+static void normalise_stamps(int32_t *vector, int nstamp, uint32_t *stamps)
+{
+ int sort[MRP_RESMGR_USECASE_SIZE_MAX];
+ int32_t val, tmp;
+ int i,j,n;
+
+ if (nstamp > 0 && nstamp < MRP_RESMGR_USECASE_SIZE_MAX) {
+ for (n = i = 0; i < nstamp; i++) {
+ j = stamps[i];
+
+ MRP_ASSERT(j >= 0 && j < MRP_RESMGR_USECASE_SIZE_MAX,
+ "invalid stamp index");
+
+ if (!(val = vector[j]))
+ continue;
+
+ if (val < 0)
+ vector[j] = 0;
+ else
+ sort[n++] = j;
+ }
+
+ for (i = 0; i < n-1; i++) {
+ for (j = i + 1; j < n; j++) {
+ if (vector[sort[i]] > vector[sort[j]]) {
+ tmp = sort[i];
+ sort[i] = sort[j];
+ sort[j] = tmp;
+ }
+ }
+ }
+
+ for (i = 0; i < n; i++)
+ vector[sort[i]] = i + 1;
+ }
+}
+
+static int entry_iterator_cb(void *key, void *object, void *user_data)
+{
+ entry_iterator_t *it = (entry_iterator_t *)user_data;
+ const char *name = (const char *)key;
+ int update_idx = (object - NULL) - 1;
+ entry_descr_t *desc;
+
+ if (it->nentry < it->maxentry) {
+ desc = it->descs + it->nentry++;
+ desc->name = name;
+ desc->update_idx = update_idx;
+ }
+
+ return MRP_HTBL_ITER_MORE;
+}
+
+static entry_iterator_t *entry_iterator(mrp_resmgr_usecase_t *usecase)
+{
+ entry_iterator_t *it;
+ size_t size;
+ entry_descr_t tmp;
+ int i,j;
+
+
+ if (!usecase)
+ it = NULL;
+ else {
+ size = sizeof(*it) + (sizeof(entry_descr_t) * usecase->nentry);
+
+ if ((it = mrp_allocz(size))) {
+ it->maxentry = usecase->nentry;
+ mrp_htbl_foreach(usecase->entries, entry_iterator_cb, it);
+ }
+
+ for (i = 0; i < it->nentry - 1; i++) {
+ for (j = i + 1; j < it->nentry; j++) {
+ if (it->descs[i].update_idx > it->descs[j].update_idx) {
+ tmp = it->descs[i];
+ it->descs[i] = it->descs[j];
+ it->descs[j] = tmp;
+ }
+ }
+ }
+ }
+
+ return it;
+}
--- /dev/null
+/*
+ * Copyright (c) 2014, 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.
+ */
+
+#ifndef __MURPHY_GAM_RESOURCE_MANAGER_USECASE_H__
+#define __MURPHY_GAM_RESOURCE_MANAGER_USECASE_H__
+
+#include "plugin-gam-resource-manager.h"
+
+mrp_resmgr_usecase_t *mrp_resmgr_usecase_create(mrp_resmgr_t *resmgr);
+void mrp_resmgr_usecase_destroy(mrp_resmgr_usecase_t *usecase);
+
+ssize_t mrp_resmgr_usecase_add_attribute(mrp_resmgr_usecase_t *usecase,
+ mrp_resmgr_source_t *source,
+ const char *name);
+
+void mrp_resmgr_usecase_update(mrp_resmgr_usecase_t *usecase);
+void *mrp_resmgr_usecase_get_decision_input(mrp_resmgr_usecase_t *usecase);
+
+
+size_t mrp_usecase_print(mrp_resmgr_usecase_t *usecase, char *buf, size_t len);
+
+
+
+#endif /* __MURPHY_GAM_RESOURCE_MANAGER_USECASE_H__ */