summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Melenevsky <d.melenevsky@samsung.com>2015-07-21 19:04:03 +0300
committerDenis Melenevsky <d.melenevsky@samsung.com>2015-07-21 19:04:03 +0300
commit89bb9efc1055424c73db0d005356ec6951e3300f (patch)
tree01865c81e53e70b348173892024404f852238ada
parentb5c2c9c9184f369c193636190c91c6b2cf04c410 (diff)
downloadmurphy-89bb9efc1055424c73db0d005356ec6951e3300f.tar.gz
murphy-89bb9efc1055424c73db0d005356ec6951e3300f.tar.bz2
murphy-89bb9efc1055424c73db0d005356ec6951e3300f.zip
Change-Id: I5d54d013a94acb6c6206d35834a8dacb7bcbf2ce Signed-off-by: Denis Melenevsky <d.melenevsky@samsung.com>
-rw-r--r--m4/websockets.m456
-rw-r--r--src/common/websocklib.c89
-rw-r--r--src/plugins/plugin-resource-dbus.c27
-rw-r--r--src/plugins/resource-native/libmurphy-resource/api_test.c3
-rw-r--r--src/plugins/resource-native/libmurphy-resource/message.c57
-rw-r--r--src/plugins/resource-native/libmurphy-resource/message.h4
-rw-r--r--src/plugins/resource-native/libmurphy-resource/resource-api.h31
-rw-r--r--src/plugins/resource-native/libmurphy-resource/resource-private.h4
-rw-r--r--src/plugins/resource-native/libmurphy-resource/resource.c46
-rw-r--r--src/plugins/resource-native/libmurphy-resource/rset.c62
-rw-r--r--src/plugins/resource-native/plugin-resource-native.c43
-rw-r--r--src/plugins/resource-wrt/plugin-resource-wrt.c69
-rw-r--r--src/plugins/resource-wrt/resource-api.js86
-rw-r--r--src/plugins/resource-wrt/resource-test.html14
-rw-r--r--src/plugins/resource-wrt/resource-wrt.h1
-rw-r--r--src/resource/client-api.h11
-rw-r--r--src/resource/config-lua.c25
-rw-r--r--src/resource/data-types.h1
-rw-r--r--src/resource/manager-api.h6
-rw-r--r--src/resource/protocol.h26
-rw-r--r--src/resource/resource-owner.c132
-rw-r--r--src/resource/resource-set.c42
-rw-r--r--src/resource/resource-set.h4
-rw-r--r--src/resource/resource.c37
-rw-r--r--src/resource/resource.h1
25 files changed, 797 insertions, 80 deletions
diff --git a/m4/websockets.m4 b/m4/websockets.m4
index ab1a41d..1daaa42 100644
--- a/m4/websockets.m4
+++ b/m4/websockets.m4
@@ -49,6 +49,49 @@ if test "$enable_websockets" != "no"; then
[websockets_cci=no])
AC_MSG_RESULT([$websockets_cci])
+ # Check for ssl_cipher_list in context creation info
+ if test "$websockets_cci" = "yes"; then
+ AC_MSG_CHECKING([for WEBSOCKETS cipher list support])
+ AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[#include <stdlib.h>
+ #include <libwebsockets.h>]],
+ [[struct libwebsocket_context *ctx;
+ void *ptr;
+ ptr = &ctx->ssl_cipher_list;]])],
+ [websockets_cipherlist=yes],
+ [websockets_cipherlist=no])
+ AC_MSG_RESULT([$websockets_cipherlist])
+ fi
+
+ # Check for pollargs struct support
+ if test "$websockets_cci" = "yes"; then
+ AC_MSG_CHECKING([for WEBSOCKETS pollargs support])
+ AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[#include <stdlib.h>
+ #include <libwebsockets.h>]],
+ [[struct libwebsocket_pollargs = NULL;]])],
+ [websockets_passfd=pollargs],
+ [websockets_passfd=no])
+ AC_MSG_RESULT([$websockets_passfd])
+ else
+ websockets_passfd=no
+ fi
+
+ # Argh... try to detect the poll fd passing API...
+ if test "$websocket_passfd" != "pollargs"; then
+ AC_MSG_CHECKING([for WEBSOCKETS POLL fd passing API])
+ AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[#include <stdlib.h>
+ #include <libwebsockets.h>]],
+ [[printf("%d\n", LWS_MAX_HEADER_NAME_LENGTH);]])],
+ [websockets_passfd=user],
+ [websockets_passfd=in])
+ AC_MSG_RESULT([$websockets_passfd])
+ fi
+
# Check for new libwebsockets_get_internal_extensions.
AC_MSG_CHECKING([for WEBSOCKETS internal extension query API])
AC_LINK_IFELSE(
@@ -179,6 +222,19 @@ if test "$enable_websockets" != "no"; then
if test "$websockets_cci" = "yes"; then
WEBSOCKETS_CFLAGS="$WEBSOCKETS_CFLAGS -DWEBSOCKETS_CONTEXT_INFO"
fi
+ if test "$websockets_cipherlist" = "yes"; then
+ WEBSOCKETS_CFLAGS="$WEBSOCKETS_CFLAGS -DWEBSOCKETS_CIPHER_LIST"
+ fi
+ if test "$websockets_passfd" = "pollargs"; then
+ WEBSOCKETS_CFLAGS="$WEBSOCKETS_CFLAGS -DWEBSOCKETS_PASSFD_POLLARGS"
+ else
+ if test "$websockets_passfd" = "in"; then
+ WEBSOCKETS_CFLAGS="$WEBSOCKETS_CFLAGS -DWEBSOCKETS_PASSFD_IN"
+ else
+ WEBSOCKETS_CFLAGS="$WEBSOCKETS_CFLAGS -DWEBSOCKETS_PASSFD_USER"
+ fi
+ fi
+
if test "$websockets_query_ext" = "yes"; then
WEBSOCKETS_CFLAGS="$WEBSOCKETS_CFLAGS -DWEBSOCKETS_QUERY_EXTENSIONS"
fi
diff --git a/src/common/websocklib.c b/src/common/websocklib.c
index 0595c46..55c8f2f 100644
--- a/src/common/websocklib.c
+++ b/src/common/websocklib.c
@@ -743,7 +743,15 @@ wsl_ctx_t *wsl_create_context(mrp_mainloop_t *ml, wsl_ctx_cfg_t *cfg)
cci.ssl_cert_filepath = cfg->ssl_cert;
cci.ssl_private_key_filepath = cfg->ssl_pkey;
cci.ssl_ca_filepath = cfg->ssl_ca;
+#ifdef WEBSOCKETS_CIPHER_LIST
cci.ssl_cipher_list = cfg->ssl_ciphers;
+#else
+ if (cfg->ssl_ciphers != NULL) {
+ mrp_log_error("setting libwebsockets cipher list not supported");
+ errno = EOPNOTSUPP;
+ return NULL;
+ }
+#endif
cci.options = 0;
cci.ka_time = cfg->timeout;
@@ -1323,6 +1331,59 @@ static int verify_client_cert(void *user, void *in, size_t len)
#endif
+static int getpollfd(void *user, void *in, size_t len, int *fd, int *mask)
+{
+#if defined WEBSOCKETS_PASSFD_POLLARGS
+ struct libwebsocket_pollargs *args;
+
+ MRP_UNUSED(user);
+ MRP_UNUSED(in);
+
+ args = (struct libwebsocket_pollargs *)in;
+
+ *fd = args->fd;
+ if (mask != NULL)
+ *mask = args->events;
+
+#elif defined WEBSOCKETS_PASSFD_IN
+ static int misdetected = 0;
+ int ufd = (ptrdiff_t)user;
+
+ if (!misdetected) {
+ *fd = (ptrdiff_t)in;
+ if (mask != NULL)
+ *mask = (int)len;
+
+ if (0 < ufd && ufd < 4096) {
+ misdetected = 1;
+ mrp_log_error("*** websockets fd passing convention misdetected.");
+ mrp_log_error("*** fixing it up...");
+ goto fixup;
+ }
+ }
+ else {
+ fixup:
+
+ *fd = ufd;
+ if (mask != NULL)
+ *mask = (int)len;
+ }
+
+#else
+ MRP_UNUSED(in);
+
+ *fd = (ptrdiff_t)user;
+ if (mask != NULL)
+ *mask = (int)len;
+
+#endif
+
+ if (*fd != 0)
+ return 0;
+ else
+ return -1;
+}
+
static int http_event(lws_ctx_t *ws_ctx, lws_t *ws, lws_event_t event,
void *user, void *in, size_t len)
@@ -1333,6 +1394,9 @@ static int http_event(lws_ctx_t *ws_ctx, lws_t *ws, lws_event_t event,
const char *ext, *uri;
int fd, mask, status, accepted;
+ mrp_debug("ctx: %p, ws: %p, event: %d, user: %p, in: %p, len: %zd",
+ ws_ctx, ws, event, user, in, len);
+
switch (event) {
case LWS_CALLBACK_ESTABLISHED:
mrp_debug("client-handshake completed on websocket %p/%p", ws, user);
@@ -1405,12 +1469,17 @@ static int http_event(lws_ctx_t *ws_ctx, lws_t *ws, lws_event_t event,
#else /* WEBSOCKETS_CHANGE_MODE_POLL_FD */
case LWS_CALLBACK_ADD_POLL_FD:
-#ifdef WEBSOCKETS_CONTEXT_INFO /* just brilliant... */
+ getpollfd(user, in, len, &fd, &mask);
+#if 0
+ /* just brilliant... */
+#if defined(WEBSOCKETS_CONTEXT_INFO) && defined(WEBSOCKETS_CIPHER_LIST)
fd = (ptrdiff_t)in;
#else
fd = (ptrdiff_t)user;
#endif
mask = (int)len;
+#endif
+
mrp_debug("start polling fd %d for events 0x%x", fd, mask);
if (add_fd(ctx, fd, mask))
return LWS_EVENT_OK;
@@ -1418,11 +1487,15 @@ static int http_event(lws_ctx_t *ws_ctx, lws_t *ws, lws_event_t event,
return LWS_EVENT_ERROR;
case LWS_CALLBACK_DEL_POLL_FD:
-#ifdef WEBSOCKETS_CONTEXT_INFO /* just brilliant... */
+ getpollfd(user, in, len, &fd, NULL);
+#if 0
+ /* just brilliant... */
+#if defined(WEBSOCKETS_CONTEXT_INFO) && defined(WEBSOCKETS_CIPHER_LIST)
fd = (ptrdiff_t)in;
#else
fd = (ptrdiff_t)user;
#endif
+#endif
mrp_debug("stop polling fd %d", fd);
if (del_fd(ctx, fd))
return LWS_EVENT_OK;
@@ -1430,12 +1503,16 @@ static int http_event(lws_ctx_t *ws_ctx, lws_t *ws, lws_event_t event,
return LWS_EVENT_ERROR;
case LWS_CALLBACK_SET_MODE_POLL_FD:
-#ifdef WEBSOCKETS_CONTEXT_INFO /* just brilliant... */
+ getpollfd(user, in, len, &fd, &mask);
+#if 0
+ /* just brilliant... */
+#if defined(WEBSOCKETS_CONTEXT_INFO) && defined(WEBSOCKETS_CIPHER_LIST)
fd = (ptrdiff_t)in;
#else
fd = (ptrdiff_t)user;
#endif
mask = (int)len;
+#endif
mrp_debug("enable poll events 0x%x for fd %d", mask, fd);
if (mod_fd(ctx, fd, mask, FALSE))
return LWS_EVENT_OK;
@@ -1443,12 +1520,16 @@ static int http_event(lws_ctx_t *ws_ctx, lws_t *ws, lws_event_t event,
return LWS_EVENT_ERROR;
case LWS_CALLBACK_CLEAR_MODE_POLL_FD:
-#ifdef WEBSOCKETS_CONTEXT_INFO /* just brilliant... */
+ getpollfd(user, in, len, &fd, &mask);
+#if 0
+ /* just brilliant... */
+#if defined(WEBSOCKETS_CONTEXT_INFO) && defined(WEBSOCKETS_CIPHER_LIST)
fd = (ptrdiff_t)in;
#else
fd = (ptrdiff_t)user;
#endif
mask = (int)len;
+#endif
mrp_debug("disable poll events 0x%x for fd %d", mask, fd);
if (mod_fd(ctx, fd, mask, TRUE))
return LWS_EVENT_OK;
diff --git a/src/plugins/plugin-resource-dbus.c b/src/plugins/plugin-resource-dbus.c
index 2f23141..4eae503 100644
--- a/src/plugins/plugin-resource-dbus.c
+++ b/src/plugins/plugin-resource-dbus.c
@@ -64,6 +64,7 @@
#define RSET_REQUEST "request"
#define RSET_RELEASE "release"
#define RSET_DELETE "delete"
+#define RSET_RELEASING "releasing"
#define RESOURCE_SET_PROPERTY "setProperty"
#define RESOURCE_GET_PROPERTIES "getProperties"
@@ -753,6 +754,11 @@ static void event_cb(uint32_t request_id, mrp_resource_set_t *set, void *data)
mrp_log_info("Event for %s: grant 0x%08x, advice 0x%08x",
rset->path, grant, advice);
+ if (mrp_get_resource_set_state(rset->set) == mrp_resource_pending_release) {
+ update_property(rset->status_prop, "releasing");
+ return;
+ }
+
if (!rset->set || !rset->committed) {
struct deferred_rset_data_s *r_data =
@@ -989,6 +995,8 @@ static void destroy_rset(resource_set_o_t *rset)
mrp_dbus_remove_method(ctx->dbus, rset->path, RSET_IFACE, RSET_DELETE,
rset_cb, ctx);
+ mrp_dbus_remove_method(ctx->dbus, rset->path, RSET_IFACE, RSET_RELEASING,
+ rset_cb, ctx);
mrp_dbus_remove_method(ctx->dbus, rset->path, RSET_IFACE, RSET_RELEASE,
rset_cb, ctx);
mrp_dbus_remove_method(ctx->dbus, rset->path, RSET_IFACE, RSET_REQUEST,
@@ -1903,6 +1911,20 @@ static int rset_cb(mrp_dbus_t *dbus, mrp_dbus_msg_t *msg, void *data)
mrp_dbus_send_msg(dbus, reply);
mrp_dbus_msg_unref(reply);
}
+ else if (strcmp(member, RSET_RELEASING) == 0) {
+
+ mrp_log_info("Releasing cb rset %s", path);
+
+ mrp_resource_set_did_release(rset->set,0);
+
+ reply = mrp_dbus_msg_method_return(dbus, msg);
+
+ if (!reply)
+ goto error;
+
+ mrp_dbus_send_msg(dbus, reply);
+ mrp_dbus_msg_unref(reply);
+ }
else if (strcmp(member, RSET_SET_PROPERTY) == 0) {
char *name = NULL;
char *value = NULL;
@@ -2109,6 +2131,11 @@ static int mgr_cb(mrp_dbus_t *dbus, mrp_dbus_msg_t *msg, void *data)
destroy_rset(rset);
goto error_reply;
}
+ if (!mrp_dbus_export_method(ctx->dbus, rset->path,
+ RSET_IFACE, RSET_RELEASING, rset_cb, ctx)) {
+ destroy_rset(rset);
+ goto error_reply;
+ }
mrp_htbl_insert(ctx->mgr->rsets, (void *) rset->path, rset);
update_property(ctx->mgr->rsets_prop, htbl_keys(ctx->mgr->rsets));
diff --git a/src/plugins/resource-native/libmurphy-resource/api_test.c b/src/plugins/resource-native/libmurphy-resource/api_test.c
index 2e80915..b3f780b 100644
--- a/src/plugins/resource-native/libmurphy-resource/api_test.c
+++ b/src/plugins/resource-native/libmurphy-resource/api_test.c
@@ -263,6 +263,9 @@ static char *state_to_str(mrp_res_resource_state_t st)
case MRP_RES_RESOURCE_PENDING:
state = "pending";
break;
+ case MRP_RES_RESOURCE_ABOUT_TO_LOOSE:
+ state = "about to loose";
+ break;
}
return state;
}
diff --git a/src/plugins/resource-native/libmurphy-resource/message.c b/src/plugins/resource-native/libmurphy-resource/message.c
index 8ae161a..d60fb62 100644
--- a/src/plugins/resource-native/libmurphy-resource/message.c
+++ b/src/plugins/resource-native/libmurphy-resource/message.c
@@ -66,6 +66,7 @@ bool fetch_resource_set_mask(mrp_msg_t *msg, void **pcursor,
switch (mask_type) {
case 0: expected_tag = RESPROTO_RESOURCE_GRANT; break;
case 1: expected_tag = RESPROTO_RESOURCE_ADVICE; break;
+ case 2: expected_tag = RESPROTO_RESOURCE_PENDING; break;
default: /* don't know what to fetch */ return false;
}
@@ -261,6 +262,25 @@ bool fetch_resource_name(mrp_msg_t *msg, void **pcursor,
return true;
}
+bool fetch_resource_sync_release(mrp_msg_t *msg, void **pcursor,
+ bool *psync_release)
+{
+ uint16_t tag;
+ uint16_t type;
+ mrp_msg_value_t value;
+ size_t size;
+
+ if (!mrp_msg_iterate(msg, pcursor, &tag, &type, &value, &size) ||
+ tag != RESPROTO_RESOURCE_SYNC_RELEASE || type != MRP_MSG_FIELD_BOOL)
+ {
+ *psync_release = false;
+ return false;
+ }
+
+ *psync_release = value.bln;
+ return true;
+}
+
static int priv_res_to_mrp_res(uint32_t id, resource_def_t *src, mrp_res_resource_t *dst,
mrp_res_resource_set_t *set)
@@ -272,6 +292,7 @@ static int priv_res_to_mrp_res(uint32_t id, resource_def_t *src, mrp_res_resourc
dst->priv->server_id = id;
+ dst->priv->sync_release = src->sync_release;
dst->priv->num_attributes = src->num_attrs;
dst->priv->attrs = src->attrs;
dst->priv->set = set;
@@ -303,6 +324,10 @@ mrp_res_resource_set_t *resource_query_response(mrp_res_context_t *cx,
while (fetch_resource_name(msg, pcursor, &rdef[dim].name)) {
int n_attrs = 0;
+ if (!fetch_resource_sync_release(msg, pcursor, &rdef[dim].sync_release)) {
+ goto failed;
+ }
+
if (!fetch_attribute_array(msg, pcursor, ATTRIBUTE_MAX+1,
attrs, &n_attrs))
goto failed;
@@ -514,6 +539,38 @@ error:
return -1;
}
+int did_release_resource_set_request(mrp_res_context_t *cx,
+ mrp_res_resource_set_t *rset)
+{
+ mrp_msg_t *msg = NULL;
+
+ if (!cx->priv->connected)
+ return -1;
+
+ msg = mrp_msg_create(
+ RESPROTO_SEQUENCE_NO, MRP_MSG_FIELD_UINT32, cx->priv->next_seqno,
+ RESPROTO_REQUEST_TYPE, MRP_MSG_FIELD_UINT16,
+ RESPROTO_DID_RELEASE_RESOURCE_SET,
+ RESPROTO_RESOURCE_SET_ID, MRP_MSG_FIELD_UINT32, rset->priv->id,
+ RESPROTO_MESSAGE_END);
+
+ if (!msg)
+ return -1;
+
+ rset->priv->seqno = cx->priv->next_seqno;
+ cx->priv->next_seqno++;
+
+ if (!mrp_transport_send(cx->priv->transp, msg))
+ goto error;
+
+ mrp_msg_unref(msg);
+ return 0;
+
+error:
+ mrp_msg_unref(msg);
+ return -1;
+}
+
int create_resource_set_request(mrp_res_context_t *cx,
mrp_res_resource_set_t *rset)
diff --git a/src/plugins/resource-native/libmurphy-resource/message.h b/src/plugins/resource-native/libmurphy-resource/message.h
index 5b37212..5241b3b 100644
--- a/src/plugins/resource-native/libmurphy-resource/message.h
+++ b/src/plugins/resource-native/libmurphy-resource/message.h
@@ -89,4 +89,8 @@ int get_application_classes_request(mrp_res_context_t *cx);
int get_available_resources_request(mrp_res_context_t *cx);
+int did_release_resource_set_request(mrp_res_context_t *cx,
+ mrp_res_resource_set_t *rset);
+
+
#endif
diff --git a/src/plugins/resource-native/libmurphy-resource/resource-api.h b/src/plugins/resource-native/libmurphy-resource/resource-api.h
index f4dae1e..98cc5b2 100644
--- a/src/plugins/resource-native/libmurphy-resource/resource-api.h
+++ b/src/plugins/resource-native/libmurphy-resource/resource-api.h
@@ -60,6 +60,7 @@ typedef enum {
MRP_RES_RESOURCE_PENDING,
MRP_RES_RESOURCE_ACQUIRED,
MRP_RES_RESOURCE_AVAILABLE,
+ MRP_RES_RESOURCE_ABOUT_TO_LOOSE,
} mrp_res_resource_state_t;
typedef enum {
@@ -267,6 +268,35 @@ bool mrp_res_equal_resource_set(const mrp_res_resource_set_t *a,
int mrp_res_acquire_resource_set(const mrp_res_resource_set_t *rs);
/**
+ * Prototype for a callback that will be called
+ * when the client is asked to free the resources.
+ * Upon returning from this callback, the client must
+ * stop using the resource and clean up the infrastructure
+ * related to it, e.g. close opened devices.
+ *
+ * @param cx murphy connection context.
+ * @param set resource set with the resources you must free.
+ * @param userdata data you gave when setting the release callback.
+ */
+typedef void (*mrp_res_resource_release_callback_t) (mrp_res_context_t *cx,
+ const mrp_res_resource_set_t *rs,
+ void *userdata);
+
+/**
+ * Set the resource release callback.
+ * This callback will be called to ask client to free the resources.
+ *
+ * @param rs resource set to update.
+ * @param release_cb resource release callback.
+ * @param userdata data you want to access in resource release callback.
+ *
+ * @return true if the release callback was set successfully, false - otherwise.
+ */
+bool mrp_res_set_release_callback(const mrp_res_resource_set_t *rs,
+ mrp_res_resource_release_callback_t release_cb,
+ void *userdata);
+
+/**
* Release a resource set. Releasing a set of resources
* will not stop delivery of Resource callbacks for that
* set, updates for its status will still be delivered.
@@ -283,7 +313,6 @@ int mrp_res_acquire_resource_set(const mrp_res_resource_set_t *rs);
*/
int mrp_res_release_resource_set(mrp_res_resource_set_t *rs);
-
/**
* Get a resource set unique server-side id. The id information is
* normally available only after mrp_res_acquire_resource_set or
diff --git a/src/plugins/resource-native/libmurphy-resource/resource-private.h b/src/plugins/resource-native/libmurphy-resource/resource-private.h
index 18ec44b..2466921 100644
--- a/src/plugins/resource-native/libmurphy-resource/resource-private.h
+++ b/src/plugins/resource-native/libmurphy-resource/resource-private.h
@@ -62,6 +62,7 @@ typedef struct {
typedef struct {
const char *name;
+ bool sync_release;
int num_attrs;
mrp_res_attribute_t *attrs;
} resource_def_t;
@@ -75,6 +76,7 @@ struct mrp_res_resource_private_s {
mrp_res_resource_t *pub; /* composition */
mrp_res_resource_set_t *set; /* owning set */
+ bool sync_release;
bool mandatory;
bool shared;
int num_attributes;
@@ -93,7 +95,9 @@ struct mrp_res_resource_set_private_s {
bool autorelease;
mrp_res_resource_callback_t cb;
+ mrp_res_resource_release_callback_t release_cb;
void *user_data;
+ void *release_cb_user_data;
uint32_t num_resources;
mrp_res_resource_t **resources;
diff --git a/src/plugins/resource-native/libmurphy-resource/resource.c b/src/plugins/resource-native/libmurphy-resource/resource.c
index 57a18b0..20ba61a 100644
--- a/src/plugins/resource-native/libmurphy-resource/resource.c
+++ b/src/plugins/resource-native/libmurphy-resource/resource.c
@@ -89,7 +89,7 @@ static void resource_event(mrp_msg_t *msg,
void **pcursor)
{
uint32_t rset_id;
- uint32_t grant, advice;
+ uint32_t grant, advice, pending;
mrp_resproto_state_t state;
uint16_t tag;
uint16_t type;
@@ -102,13 +102,15 @@ static void resource_event(mrp_msg_t *msg,
uint32_t mask, all = 0x0, mandatory = 0x0;
uint32_t i;
mrp_res_resource_set_t *rset;
+ bool should_release_resource;
mrp_res_info("Resource event (request no %u):", seqno);
if (!fetch_resource_set_id(msg, pcursor, &rset_id) ||
!fetch_resource_set_state(msg, pcursor, &state) ||
!fetch_resource_set_mask(msg, pcursor, 0, &grant) ||
- !fetch_resource_set_mask(msg, pcursor, 1, &advice)) {
+ !fetch_resource_set_mask(msg, pcursor, 1, &advice) ||
+ !fetch_resource_set_mask(msg, pcursor, 2, &pending)) {
mrp_res_error("failed to fetch data from message");
goto ignore;
}
@@ -197,6 +199,9 @@ static void resource_event(mrp_msg_t *msg,
if (grant & mask) {
res->state = MRP_RES_RESOURCE_ACQUIRED;
}
+ else if (pending & mask) {
+ res->state = MRP_RES_RESOURCE_ABOUT_TO_LOOSE;
+ }
else {
res->state = MRP_RES_RESOURCE_LOST;
}
@@ -205,7 +210,12 @@ static void resource_event(mrp_msg_t *msg,
mrp_res_info("advice = 0x%08x, grant = 0x%08x, mandatory = 0x%08x, all = 0x%08x",
advice, grant, mandatory, all);
- if (grant) {
+ should_release_resource = false;
+ if (pending) {
+ rset->state = MRP_RES_RESOURCE_ABOUT_TO_LOOSE;
+ should_release_resource = true;
+ }
+ else if (grant) {
rset->state = MRP_RES_RESOURCE_ACQUIRED;
}
else if (advice == mandatory) {
@@ -224,10 +234,19 @@ static void resource_event(mrp_msg_t *msg,
print_resource_set(rset);
#endif
if (!rset->priv->seqno) {
- if (rset->priv->cb) {
- increase_ref(cx, rset);
+ increase_ref(cx, rset);
+ if (should_release_resource) {
+ if (rset->priv->release_cb) {
+ rset->priv->release_cb(cx, rset, rset->priv->release_cb_user_data);
+ }
+ }
+ else if (rset->priv->cb) {
rset->priv->cb(cx, rset, rset->priv->user_data);
- decrease_ref(cx, rset);
+ }
+ decrease_ref(cx, rset);
+
+ if (should_release_resource) {
+ did_release_resource_set_request(cx, rset);
}
}
@@ -362,6 +381,21 @@ static void recvfrom_msg(mrp_transport_t *transp, mrp_msg_t *msg,
break;
}
+ case RESPROTO_DID_RELEASE_RESOURCE_SET:
+ {
+ mrp_res_resource_set_t *rset;
+ mrp_res_info("received DID_RELEASE_RESOURCE_SET response");
+
+ rset = acquire_resource_set_response(msg, cx, &cursor);
+
+ if (!rset) {
+ goto error;
+ }
+
+ rset->priv->seqno = 0;
+
+ break;
+ }
case RESPROTO_RESOURCES_EVENT:
mrp_res_info("received RESOURCES_EVENT response");
diff --git a/src/plugins/resource-native/libmurphy-resource/rset.c b/src/plugins/resource-native/libmurphy-resource/rset.c
index 1c788b8..c1021ba 100644
--- a/src/plugins/resource-native/libmurphy-resource/rset.c
+++ b/src/plugins/resource-native/libmurphy-resource/rset.c
@@ -50,6 +50,9 @@ static char *state_to_str(mrp_res_resource_state_t st)
case MRP_RES_RESOURCE_PENDING:
state = "pending";
break;
+ case MRP_RES_RESOURCE_ABOUT_TO_LOOSE:
+ state = "about to loose";
+ break;
}
return state;
}
@@ -443,6 +446,8 @@ static int update_library_resource_set(mrp_res_context_t *cx,
rset->priv->resources = resources;
rset->priv->num_resources = num_resources;
rset->priv->autorelease = original->priv->autorelease;
+ rset->priv->release_cb = original->priv->release_cb;
+ rset->priv->release_cb_user_data = original->priv->release_cb_user_data;
return 0;
@@ -516,6 +521,7 @@ mrp_res_resource_t *mrp_res_create_resource(
goto error;
res->priv->server_id = server_id;
+ res->priv->sync_release = proto->priv->sync_release;
res->priv->mandatory = mandatory;
res->priv->shared = shared;
res->priv->pub = res;
@@ -580,7 +586,6 @@ const mrp_res_resource_set_t * mrp_res_list_resources(
return cx->priv->master_resource_set;
}
-
int mrp_res_release_resource_set(mrp_res_resource_set_t *original)
{
mrp_res_resource_set_t *internal_set = NULL;
@@ -787,11 +792,33 @@ bool mrp_res_set_autorelease(bool status,
return TRUE;
}
+bool mrp_res_set_release_callback(const mrp_res_resource_set_t *rs,
+ mrp_res_resource_release_callback_t release_cb,
+ void *userdata)
+{
+ bool result = false;
+ mrp_res_resource_t *resource;
+ uint32_t i;
-int mrp_res_acquire_resource_set(
- const mrp_res_resource_set_t *original)
+ if (rs && rs->state == MRP_RES_RESOURCE_PENDING) {
+ for (i = 0; i < rs->priv->num_resources; i++) {
+ resource = rs->priv->resources[i];
+ if (resource->priv->sync_release) {
+ result = true;
+ rs->priv->release_cb = release_cb;
+ rs->priv->release_cb_user_data = userdata;
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+static mrp_res_resource_set_t *acquire_resource_set(const mrp_res_resource_set_t *original)
{
- mrp_res_resource_set_t *rset;
+ mrp_res_resource_set_t *rset = NULL;
+
mrp_res_context_t *cx = original->priv->cx;
if (!cx->priv->connected) {
@@ -799,6 +826,15 @@ int mrp_res_acquire_resource_set(
goto error;
}
+ if (!original->priv->release_cb) {
+ for (uint32_t i = 0; i < original->priv->num_resources; i++) {
+ if (original->priv->resources[i]->priv->sync_release) {
+ mrp_res_error("release callback is not set");
+ goto error;
+ }
+ }
+ }
+
rset = mrp_htbl_lookup(cx->priv->internal_rset_mapping,
u_to_p(original->priv->internal_id));
@@ -826,7 +862,7 @@ int mrp_res_acquire_resource_set(
}
else {
/* re-acquire a lost or released set */
- return acquire_resource_set_request(cx, rset);
+ acquire_resource_set_request(cx, rset);
}
}
else {
@@ -860,11 +896,23 @@ int mrp_res_acquire_resource_set(
}
}
- return 0;
+ return rset;
error:
mrp_log_error("error acquiring a resource set");
- return -1;
+ return NULL;
+}
+
+int mrp_res_acquire_resource_set(
+ const mrp_res_resource_set_t *original)
+{
+ int result = -1;
+
+ if (acquire_resource_set(original)) {
+ result = 0;
+ }
+
+ return result;
}
diff --git a/src/plugins/resource-native/plugin-resource-native.c b/src/plugins/resource-native/plugin-resource-native.c
index 13afd55..9eb2f5c 100644
--- a/src/plugins/resource-native/plugin-resource-native.c
+++ b/src/plugins/resource-native/plugin-resource-native.c
@@ -153,7 +153,6 @@ static void print_zones_cb(mrp_console_t *c, void *user_data,
for (i = 0; zone_names[i]; i++)
printf(" %s\n", zone_names[i]);
-
mrp_free(zone_names);
}
}
@@ -409,6 +408,7 @@ static void query_resources_request(client_t *client, mrp_msg_t *req)
mrp_plugin_t *plugin = data->plugin;
const char **names;
mrp_attr_t *attrs;
+ bool sync_release;
mrp_attr_t buf[ATTRIBUTE_MAX];
uint32_t resid;
@@ -421,8 +421,10 @@ static void query_resources_request(client_t *client, mrp_msg_t *req)
for (resid = 0; names[resid]; resid++) {
attrs = mrp_resource_definition_read_all_attributes(
resid, ATTRIBUTE_MAX, buf);
+ sync_release = mrp_resource_definition_get_sync_release(resid);
if (!PUSH(req, RESOURCE_NAME, STRING, names[resid]) ||
+ !PUSH(req, RESOURCE_SYNC_RELEASE, BOOL, sync_release) ||
!write_attributes(req, attrs))
goto failed;
}
@@ -760,6 +762,38 @@ static void acquire_resource_set_request(client_t *client, mrp_msg_t *req,
mrp_resource_set_release(rset, seqno);
}
+static void did_release_resource_set_request(client_t *client, mrp_msg_t *req,
+ uint32_t seqno, void **pcurs)
+{
+ uint16_t tag;
+ uint16_t type;
+ size_t size;
+ mrp_msg_value_t value;
+ uint32_t rset_id;
+ mrp_resource_set_t *rset;
+
+ MRP_ASSERT(client, "invalid argument");
+ MRP_ASSERT(client->rscli, "confused with data structures");
+
+ if (!mrp_msg_iterate(req, pcurs, &tag, &type, &value, &size) ||
+ tag != RESPROTO_RESOURCE_SET_ID || type != MRP_MSG_FIELD_UINT32)
+ {
+ reply_with_status(client, req, EINVAL);
+ return;
+ }
+
+ rset_id = value.u32;
+
+ if (!(rset = mrp_resource_client_find_set(client->rscli, rset_id))) {
+ reply_with_status(client, req, ENOENT);
+ return;
+ }
+
+ reply_with_status(client, req, 0);
+
+ mrp_resource_set_did_release(rset, seqno);
+}
+
static void connection_evt(mrp_transport_t *listen, void *user_data)
{
static uint32_t id;
@@ -891,6 +925,10 @@ static void recvfrom_msg(mrp_transport_t *transp, mrp_msg_t *msg,
acquire_resource_set_request(client, msg, seqno, false, &cursor);
break;
+ case RESPROTO_DID_RELEASE_RESOURCE_SET:
+ did_release_resource_set_request(client, msg, seqno, &cursor);
+ break;
+
default:
mrp_log_warning("%s: unsupported request type %d",
plugin->instance, reqtyp);
@@ -919,6 +957,7 @@ static void resource_event_handler(uint32_t reqid, mrp_resource_set_t *rset,
uint16_t state;
mrp_resource_mask_t grant;
mrp_resource_mask_t advice;
+ mrp_resource_mask_t pending;
mrp_resource_mask_t mask;
mrp_resource_mask_t all;
mrp_msg_t *msg;
@@ -937,6 +976,7 @@ static void resource_event_handler(uint32_t reqid, mrp_resource_set_t *rset,
id = mrp_get_resource_set_id(rset);
grant = mrp_get_resource_set_grant(rset);
advice = mrp_get_resource_set_advice(rset);
+ pending = mrp_get_resource_set_pending_release(rset);
if (mrp_get_resource_set_state(rset) == mrp_resource_acquire)
state = RESPROTO_ACQUIRE;
@@ -949,6 +989,7 @@ static void resource_event_handler(uint32_t reqid, mrp_resource_set_t *rset,
FIELD( RESOURCE_STATE , UINT16, state ),
FIELD( RESOURCE_GRANT , UINT32, grant ),
FIELD( RESOURCE_ADVICE, UINT32, advice ),
+ FIELD( RESOURCE_PENDING, UINT32, pending ),
RESPROTO_MESSAGE_END );
if (!msg)
diff --git a/src/plugins/resource-wrt/plugin-resource-wrt.c b/src/plugins/resource-wrt/plugin-resource-wrt.c
index 36d062f..3fd5f9a 100644
--- a/src/plugins/resource-wrt/plugin-resource-wrt.c
+++ b/src/plugins/resource-wrt/plugin-resource-wrt.c
@@ -220,6 +220,7 @@ static void query_resources(wrt_client_t *c, mrp_json_t *req)
mrp_attr_t *attrs, *a;
mrp_attr_t buf[ATTRIBUTE_MAX];
uint32_t id;
+ bool sync_release;
if (!mrp_json_get_integer(req, "seq", &seq)) {
ignore_invalid_request(c, req, "missing 'seq' field");
@@ -253,6 +254,10 @@ static void query_resources(wrt_client_t *c, mrp_json_t *req)
if (!mrp_json_add_string (r, "name", resources[id]))
goto fail;
+ sync_release = mrp_resource_definition_get_sync_release(id);
+ if (!mrp_json_add_boolean(r, "sync_release", sync_release))
+ goto fail;
+
attrs = mrp_resource_definition_read_all_attributes(id,
ATTRIBUTE_MAX, buf);
@@ -605,7 +610,7 @@ static void emit_resource_set_event(wrt_client_t *c, uint32_t reqid,
mrp_json_t *msg, *rarr, *r;
int rsid;
const char *state;
- int grant, advice, all, mask;
+ int grant, pending_release, pending_acquire, advice, all, mask;
errbuf_t e;
mrp_resource_t *res;
void *it;
@@ -619,14 +624,21 @@ static void emit_resource_set_event(wrt_client_t *c, uint32_t reqid,
return;
}
- if (mrp_get_resource_set_state(rset) == mrp_resource_acquire)
+ pending_release = (int)mrp_get_resource_set_pending_release(rset);
+ pending_acquire = (int)mrp_get_resource_set_pending_acquire(rset);
+
+ if (pending_acquire && !pending_release) {
+ mrp_debug("not emitting event for resource set that is pending acquisition");
+ return;
+ }
+ else if (mrp_get_resource_set_state(rset) == mrp_resource_acquire)
state = RESWRT_STATE_GRANTED;
else
state = RESWRT_STATE_RELEASE;
- rsid = (int)mrp_get_resource_set_id(rset);
- grant = (int)mrp_get_resource_set_grant(rset);
- advice = (int)mrp_get_resource_set_advice(rset);
+ rsid = (int)mrp_get_resource_set_id(rset);
+ grant = (int)mrp_get_resource_set_grant(rset);
+ advice = (int)mrp_get_resource_set_advice(rset);
msg = alloc_reply(type, seq);
@@ -635,10 +647,11 @@ static void emit_resource_set_event(wrt_client_t *c, uint32_t reqid,
rarr = r = NULL;
- if (mrp_json_add_integer(msg, "id" , rsid ) &&
- mrp_json_add_string (msg, "state" , state) &&
- mrp_json_add_integer(msg, "grant" , grant) &&
- mrp_json_add_integer(msg, "advice", advice)) {
+ if (mrp_json_add_integer(msg, "id" , rsid ) &&
+ mrp_json_add_string (msg, "state" , state ) &&
+ mrp_json_add_integer(msg, "grant" , grant ) &&
+ mrp_json_add_integer(msg, "pending" , pending_release) &&
+ mrp_json_add_integer(msg, "advice" , advice)) {
all = grant | advice;
it = NULL;
@@ -969,6 +982,42 @@ static void release_set(wrt_client_t *c, mrp_json_t *req)
}
+static void did_release_set(wrt_client_t *c, mrp_json_t *req)
+{
+ const char *type = RESWRT_DID_RELEASE_SET;
+ int seq;
+ mrp_json_t *reply;
+ mrp_resource_set_t *rset;
+ uint32_t rsid;
+
+ if (!mrp_json_get_integer(req, "seq", &seq)) {
+ ignore_invalid_request(c, req, "missing 'seq' field");
+ return;
+ }
+
+ /* get resource set id */
+ if (!mrp_json_get_integer(req, "id", &rsid)) {
+ error_reply(c, type, seq, EINVAL, "missing id");
+ return;
+ }
+
+ rset = mrp_resource_client_find_set(c->rsc, rsid);
+
+ if (rset != NULL) {
+ reply = alloc_reply(type, seq);
+
+ if (reply != NULL) {
+ if (mrp_json_add_integer(reply, "status", 0))
+ send_message(c, reply);
+ }
+
+ mrp_resource_set_did_release(rset, (uint32_t)seq);
+ }
+ else
+ error_reply(c, type, seq, ENOENT, "resource set %d not found", rsid);
+}
+
+
static wrt_client_t *create_client(wrt_data_t *data, mrp_transport_t *lt)
{
wrt_client_t *c;
@@ -1098,6 +1147,8 @@ static void recv_evt(mrp_transport_t *t, void *data, void *user_data)
acquire_set(c, req);
else if (!strcmp(type, RESWRT_RELEASE_SET))
release_set(c, req);
+ else if (!strcmp(type, RESWRT_DID_RELEASE_SET))
+ did_release_set(c, req);
else
ignore_unknown_request(c, req, type);
}
diff --git a/src/plugins/resource-wrt/resource-api.js b/src/plugins/resource-wrt/resource-api.js
index a739e6b..75e8abc 100644
--- a/src/plugins/resource-wrt/resource-api.js
+++ b/src/plugins/resource-wrt/resource-api.js
@@ -196,6 +196,25 @@ WrtResourceManager.prototype.sckmessage = function (message) {
}
+/** Map resource definitions to names. */
+WrtResourceManager.prototype.map_resources_by_name = function (resources) {
+ if (this.resource_by_name) {
+ return;
+ }
+
+ this.resource_by_name = {};
+
+ for (var i in resources) {
+ var resource = resources[i];
+ var name = resource.name;
+ this.resource_by_name[name] = {
+ sync_release: resource.sync_release,
+ attributes: resource.attributes,
+ };
+ }
+}
+
+
/** Resource set constructor. */
function WrtResourceSet (mgr, reqno) {
this.manager = mgr;
@@ -213,12 +232,20 @@ WrtResourceSet.prototype.notify = function (msg) {
if (!this.resources)
this.resources = msg.resources;
- this.state = msg.state;
- this.grant = msg.grant;
- this.advice = msg.advice;
+ this.state = msg.state;
+ this.grant = msg.grant;
+ this.pending = msg.pending;
+ this.advice = msg.advice;
- if (this.onstatechanged)
- this.onstatechanged(this.grant);
+ if (this.pending) {
+ if (this.onrelease) {
+ this.onrelease(this.grant);
+ }
+ this.didRelease();
+ }
+ else if (this.onstatechanged) {
+ this.onstatechanged(this.pending);
+ }
}
else if (type == 'create') {
var status = msg.status;
@@ -243,6 +270,12 @@ WrtResourceSet.prototype.notify = function (msg) {
}
+/** The resource set was freed by client. */
+WrtResourceSet.prototype.didRelease = function () {
+ this.manager.send_request({ type: 'did_release', id: this.id });
+}
+
+
/** Map resources to names. */
WrtResourceSet.prototype.ensure_resource_map = function () {
var r;
@@ -265,6 +298,24 @@ WrtResourceSet.prototype.ensure_resource_map = function () {
}
+/** Check if the resource set release callback is present if it is needed. */
+WrtResourceSet.prototype.isReleaseCallbackOK = function () {
+ var result = true;
+
+ if (!this.onrelease) {
+ for (var i in this.resources) {
+ var name = this.resources[i].name;
+ if (this.manager.resource_by_name[name].sync_release) {
+ result = false;
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+
/** Pending request constructor. */
function WrtPendingRequest (mgr, reqno) {
this.manager = mgr;
@@ -302,6 +353,11 @@ WrtPendingRequest.prototype.notify = function (msg) {
if (status == 0) {
if (this.onsuccess && (m = evtmap[msg.type])) {
event = m.map ? m.map(msg[m.field]) : msg[m.field];
+
+ if ('resources' == m.field) {
+ this.manager.map_resources_by_name(msg.resources);
+ }
+
this.onsuccess(event);
}
}
@@ -450,7 +506,12 @@ WrtResourceManager.prototype.socketUri = function (http_uri) {
/** Acquire the resource set. */
WrtResourceSet.prototype.acquire = function () {
- this.manager.send_request({ type: 'acquire', id: this.id });
+ if (this.isReleaseCallbackOK()) {
+ this.manager.send_request({ type: 'acquire', id: this.id });
+ }
+ else {
+ throw new WrtResourceError("Release callback is not set when it should be.");
+ }
}
@@ -560,6 +621,19 @@ WrtResourceSet.prototype.isGranted = function (name) {
}
+/** Check if the named resource is pending for release/acqusition. */
+WrtResourceSet.prototype.isPending = function (name) {
+ this.ensure_resource_map();
+
+ r = this.resource_by_name[name];
+
+ if (this.pending & r.mask)
+ return true;
+ else
+ return false;
+}
+
+
/** Check if the named resource can be allocated. */
WrtResourceSet.prototype.isAllocable = function (name) {
this.ensure_resource_map();
diff --git a/src/plugins/resource-wrt/resource-test.html b/src/plugins/resource-wrt/resource-test.html
index f87323b..3859a07 100644
--- a/src/plugins/resource-wrt/resource-test.html
+++ b/src/plugins/resource-wrt/resource-test.html
@@ -150,6 +150,20 @@ function managerConnected () {
rset.onsuccess = resourceSetCreated;
rset.onerror = resourceSetFailed;
rset.onstatechanged = resourceSetEvent;
+ rset.onrelease = function (grant) {
+ var names = this.getResourceNames();
+ for (var i in names) {
+ if (this.isPending(names[i])) {
+ console.log("Resource '" + names[i] + "' must be released.");
+ }
+ }
+
+ window.alert("Resource must be released!!");
+
+ if (this.isPending('audio_playback')) {
+ stopAudio();
+ }
+ };
}
catch (e) {
console.log("Query failed: " +
diff --git a/src/plugins/resource-wrt/resource-wrt.h b/src/plugins/resource-wrt/resource-wrt.h
index f0df672..dede7b7 100644
--- a/src/plugins/resource-wrt/resource-wrt.h
+++ b/src/plugins/resource-wrt/resource-wrt.h
@@ -38,6 +38,7 @@
#define RESWRT_DESTROY_SET "destroy"
#define RESWRT_ACQUIRE_SET "acquire"
#define RESWRT_RELEASE_SET "release"
+#define RESWRT_DID_RELEASE_SET "did_release"
#define RESWRT_EVENT "event"
#define RESWRT_STATE_GRANTED "acquire"
diff --git a/src/resource/client-api.h b/src/resource/client-api.h
index 5f56dfa..00b6554 100644
--- a/src/resource/client-api.h
+++ b/src/resource/client-api.h
@@ -51,6 +51,7 @@ mrp_attr_t *
mrp_resource_definition_read_all_attributes(uint32_t resource_id,
uint32_t buflen,
mrp_attr_t *buf);
+bool mrp_resource_definition_get_sync_release(uint32_t resource_id);
const char **mrp_application_class_get_all_names(uint32_t buflen,
const char **buf);
@@ -68,6 +69,7 @@ mrp_resource_set_t *mrp_resource_set_create(mrp_resource_client_t *client,
void *user_data);
void mrp_resource_set_destroy(mrp_resource_set_t *resource_set);
+
uint32_t mrp_get_resource_set_id(mrp_resource_set_t *resource_set);
mrp_resource_state_t
@@ -79,6 +81,12 @@ mrp_get_resource_set_grant(mrp_resource_set_t *resource_set);
mrp_resource_mask_t
mrp_get_resource_set_advice(mrp_resource_set_t *resource_set);
+mrp_resource_mask_t
+mrp_get_resource_set_pending_release(mrp_resource_set_t *resource_set);
+
+mrp_resource_mask_t
+mrp_get_resource_set_pending_acquire(mrp_resource_set_t *resource_set);
+
mrp_resource_client_t *
mrp_get_resource_set_client(mrp_resource_set_t *resource_set);
@@ -111,6 +119,9 @@ void mrp_resource_set_acquire(mrp_resource_set_t *resource_set,
void mrp_resource_set_release(mrp_resource_set_t *resource_set,
uint32_t request_id);
+void mrp_resource_set_did_release(mrp_resource_set_t *resource_set,
+ uint32_t request_id);
+
mrp_resource_t *
mrp_resource_set_iterate_resources(mrp_resource_set_t *resource_set,void **it);
diff --git a/src/resource/config-lua.c b/src/resource/config-lua.c
index 5a0a5d7..25b8534 100644
--- a/src/resource/config-lua.c
+++ b/src/resource/config-lua.c
@@ -79,6 +79,7 @@ enum field_e {
PRIORITY,
SHAREABLE,
MANDATORY,
+ SYNC_RELEASE,
MODAL,
SHARE,
GRANT,
@@ -1031,6 +1032,7 @@ static int resclass_create_from_lua(lua_State *L)
const char *name = NULL;
mrp_attr_def_t *attrs = NULL;
bool shareable = false;
+ bool sync_release = false;
mrp_resource_mgr_ftbl_t *ftbl = NULL;
void *mgrdata = NULL;
attr_def_t *adef;
@@ -1051,6 +1053,13 @@ static int resclass_create_from_lua(lua_State *L)
shareable = lua_toboolean(L, -1);
break;
+ case SYNC_RELEASE:
+ luaL_argcheck(L, lua_isboolean(L,-1), 2, "attempt to assign "
+ "non-boolean value to 'sync_release' field");
+ sync_release = lua_toboolean(L, -1);
+ break;
+
+
case ATTRIBUTES:
attrs = check_attrdefs(L, -1, &nattr);
break;
@@ -1064,7 +1073,7 @@ static int resclass_create_from_lua(lua_State *L)
if (!name)
luaL_error(L, "missing or wrong name field");
- id = mrp_resource_definition_create(name, shareable, attrs,ftbl,mgrdata);
+ id = mrp_resource_definition_create_with_sync_release(name, shareable, sync_release, attrs,ftbl,mgrdata);
MRP_ASSERT(id < MRP_RESOURCE_MAX, "resource id is out of range");
@@ -1107,10 +1116,11 @@ static int resclass_getfield(lua_State *L)
lua_pushnil(L);
else {
switch (fld) {
- case NAME: lua_pushstring(L, rd->name); break;
- case ID: lua_pushinteger(L, rd->id + 1); break;
- case SHAREABLE: lua_pushboolean(L, rd->shareable); break;
- default: lua_pushnil(L); break;
+ case NAME: lua_pushstring(L, rd->name); break;
+ case ID: lua_pushinteger(L, rd->id + 1); break;
+ case SHAREABLE: lua_pushboolean(L, rd->shareable); break;
+ case SYNC_RELEASE: lua_pushboolean(L, rd->sync_release); break;
+ default: lua_pushnil(L); break;
}
}
@@ -1717,6 +1727,11 @@ static field_t field_name_to_type(const char *name, size_t len)
return ATTRIBUTES;
break;
+ case 12:
+ if (!strcmp(name, "sync_release"))
+ return SYNC_RELEASE;
+ break;
+
default:
break;
}
diff --git a/src/resource/data-types.h b/src/resource/data-types.h
index 7a347a0..ede35b5 100644
--- a/src/resource/data-types.h
+++ b/src/resource/data-types.h
@@ -85,6 +85,7 @@ enum mrp_resource_state_e {
mrp_resource_no_request = 0,
mrp_resource_release,
mrp_resource_acquire,
+ mrp_resource_pending_release,
};
diff --git a/src/resource/manager-api.h b/src/resource/manager-api.h
index c91f054..010f8d3 100644
--- a/src/resource/manager-api.h
+++ b/src/resource/manager-api.h
@@ -51,6 +51,12 @@ uint32_t mrp_resource_definition_create(const char *name,
mrp_attr_def_t *attrdefs,
mrp_resource_mgr_ftbl_t *manager,
void *manager_data);
+uint32_t mrp_resource_definition_create_with_sync_release(const char *name,
+ bool shareable,
+ bool sync_release,
+ mrp_attr_def_t *attrdefs,
+ mrp_resource_mgr_ftbl_t *manager,
+ void *manager_data);
void mrp_lua_resclass_create_from_c(uint32_t id);
diff --git a/src/resource/protocol.h b/src/resource/protocol.h
index fa03484..44075e8 100644
--- a/src/resource/protocol.h
+++ b/src/resource/protocol.h
@@ -62,24 +62,28 @@
#define RESPROTO_RESOURCE_STATE RESPROTO_TAG(7)
#define RESPROTO_RESOURCE_GRANT RESPROTO_TAG(8)
#define RESPROTO_RESOURCE_ADVICE RESPROTO_TAG(9)
-#define RESPROTO_RESOURCE_ID RESPROTO_TAG(10)
-#define RESPROTO_RESOURCE_NAME RESPROTO_TAG(11)
-#define RESPROTO_RESOURCE_FLAGS RESPROTO_TAG(12)
-#define RESPROTO_RESOURCE_PRIORITY RESPROTO_TAG(13)
-#define RESPROTO_CLASS_NAME RESPROTO_TAG(14)
-#define RESPROTO_ZONE_NAME RESPROTO_TAG(15)
-#define RESPROTO_ATTRIBUTE_INDEX RESPROTO_TAG(16)
-#define RESPROTO_ATTRIBUTE_NAME RESPROTO_TAG(17)
-#define RESPROTO_ATTRIBUTE_VALUE RESPROTO_TAG(18)
+#define RESPROTO_RESOURCE_PENDING RESPROTO_TAG(10)
+
+#define RESPROTO_RESOURCE_ID RESPROTO_TAG(11)
+#define RESPROTO_RESOURCE_NAME RESPROTO_TAG(12)
+#define RESPROTO_RESOURCE_FLAGS RESPROTO_TAG(13)
+#define RESPROTO_RESOURCE_PRIORITY RESPROTO_TAG(14)
+#define RESPROTO_CLASS_NAME RESPROTO_TAG(15)
+#define RESPROTO_ZONE_NAME RESPROTO_TAG(16)
+#define RESPROTO_ATTRIBUTE_INDEX RESPROTO_TAG(17)
+#define RESPROTO_ATTRIBUTE_NAME RESPROTO_TAG(18)
+#define RESPROTO_ATTRIBUTE_VALUE RESPROTO_TAG(19)
+#define RESPROTO_RESOURCE_SYNC_RELEASE RESPROTO_TAG(20)
typedef enum {
- RESPROTO_QUERY_RESOURCES,
+ RESPROTO_QUERY_RESOURCES, // 0
RESPROTO_QUERY_CLASSES,
RESPROTO_QUERY_ZONES,
RESPROTO_CREATE_RESOURCE_SET,
RESPROTO_DESTROY_RESOURCE_SET,
- RESPROTO_ACQUIRE_RESOURCE_SET,
+ RESPROTO_ACQUIRE_RESOURCE_SET, // 5
RESPROTO_RELEASE_RESOURCE_SET,
+ RESPROTO_DID_RELEASE_RESOURCE_SET,
RESPROTO_RESOURCES_EVENT,
} mrp_resproto_request_t;
diff --git a/src/resource/resource-owner.c b/src/resource/resource-owner.c
index aa5d5c0..a441fcd 100644
--- a/src/resource/resource-owner.c
+++ b/src/resource/resource-owner.c
@@ -69,6 +69,7 @@ static mrp_resource_owner_t resource_owners[MRP_ZONE_MAX * MRP_RESOURCE_MAX];
static mqi_handle_t owner_tables[MRP_RESOURCE_MAX];
static mrp_resource_owner_t *get_owner(uint32_t, uint32_t);
+static void restore_owner(mrp_resource_owner_t *owner, mrp_resource_owner_t *oldowner);
static void reset_owners(uint32_t, mrp_resource_owner_t *);
static bool grant_ownership(mrp_resource_owner_t *, mrp_zone_t *,
mrp_application_class_t *, mrp_resource_set_t *,
@@ -184,7 +185,11 @@ void mrp_resource_owner_update_zone(uint32_t zoneid,
mrp_resource_mask_t mask;
mrp_resource_mask_t mandatory;
mrp_resource_mask_t grant;
+ mrp_resource_mask_t old_grant;
mrp_resource_mask_t advice;
+ mrp_resource_mask_t pending_acquire = 0;
+ mrp_resource_mask_t pending_release = 0;
+ mrp_resource_state_t new_state;
void *clc, *rsc, *rc;
uint32_t rid;
uint32_t rcnt;
@@ -195,6 +200,8 @@ void mrp_resource_owner_update_zone(uint32_t zoneid,
uint32_t replyid;
uint32_t nevent, maxev;
event_t *events, *ev, *lastev;
+ bool resource_granted_by_manager;
+ bool owned_by_other;
MRP_ASSERT(zoneid < MRP_ZONE_MAX, "invalid argument");
@@ -223,33 +230,73 @@ void mrp_resource_owner_update_zone(uint32_t zoneid,
force_release = false;
mandatory = rset->resource.mask.mandatory;
grant = 0;
+ old_grant = rset->resource.mask.grant;
advice = 0;
+ pending_acquire = 0;
+ pending_release = 0;
rc = NULL;
+ if ((mrp_resource_pending_release == rset->state) && !rset->resource.mask.pending.release) {
+ // Release the resource that was pending to be released.
+
+ if (!rset->resource.mask.grant && rset->auto_release.current) {
+ rset->state = mrp_resource_release;
+ rset->auto_release.current = rset->auto_release.client;
+ }
+ else {
+ rset->state = mrp_resource_acquire;
+ }
+ }
+
switch (rset->state) {
case mrp_resource_acquire:
while ((res = mrp_resource_set_iterate_resources(rset, &rc))) {
+ resource_granted_by_manager = false;
+
rdef = res->def;
rid = rdef->id;
owner = get_owner(zoneid, rid);
+ mask = (mrp_resource_mask_t)1 << rid;
+
backup[rid] = *owner;
- if (grant_ownership(owner, zone, class, rset, res))
+ /*
+ * Here we first check if the resource is owned by some other client.
+ * If not - we will grant it as ordinary,
+ * otherwise - we will mark it as pending.
+ */
+ old = oldowners + rid;
+ owned_by_other = old->rset && old->rset != rset &&
+ ((old->rset->state == mrp_resource_acquire) ||
+ (old->rset->state == mrp_resource_pending_release && old->rset->resource.mask.pending.release));
+
+ resource_granted_by_manager = grant_ownership(owner, zone, class, rset, res);
+ if (resource_granted_by_manager)
grant |= ((mrp_resource_mask_t)1 << rid);
- else {
- if (owner->rset != rset)
- force_release |= owner->modal;
+ else if (owner->rset != rset) {
+ force_release |= owner->modal;
+ }
+
+
+ if (rdef->sync_release && (old_grant & mask) && !(grant & mask)) {
+ pending_release |= mask;
+ }
+
+ if (rdef->sync_release && (grant & mask) && owned_by_other) {
+ pending_acquire |= mask;
}
}
owners = get_owner(zoneid, 0);
+
+
if ((grant & mandatory) == mandatory &&
- mrp_resource_lua_veto(zone, rset, owners, grant, reqset))
- {
+ mrp_resource_lua_veto(zone, rset, owners, grant, reqset)) {
advice = grant;
}
else {
+
/* rollback, ie. restore the backed up state */
rc = NULL;
while ((res=mrp_resource_set_iterate_resources(rset,&rc))){
@@ -260,8 +307,9 @@ void mrp_resource_owner_update_zone(uint32_t zoneid,
*owner = backup[rid];
if ((grant & mask)) {
- if ((ftbl = rdef->manager.ftbl) && ftbl->free)
+ if ((ftbl = rdef->manager.ftbl) && ftbl->free) {
ftbl->free(zone, res, rdef->manager.userdata);
+ }
}
if (advice_ownership(owner, zone, class, rset, res))
@@ -275,7 +323,8 @@ void mrp_resource_owner_update_zone(uint32_t zoneid,
mrp_resource_lua_set_owners(zone, owners);
}
- break;
+ break; // mrp_resource_acquire
+
case mrp_resource_release:
while ((res = mrp_resource_set_iterate_resources(rset, &rc))) {
@@ -290,6 +339,13 @@ void mrp_resource_owner_update_zone(uint32_t zoneid,
advice = 0;
break;
+ case mrp_resource_pending_release:
+ // Preserve the resource state while it is being freed by the client
+ grant = rset->resource.mask.grant;
+ pending_release = rset->resource.mask.pending.release;
+ pending_acquire = rset->resource.mask.pending.acquire;
+ break;
+
default:
break;
}
@@ -299,47 +355,61 @@ void mrp_resource_owner_update_zone(uint32_t zoneid,
notify = 0;
replyid = (reqset == rset && reqid == rset->request.id) ? reqid:0;
+ new_state = rset->state;
if (force_release) {
move = (rset->state != mrp_resource_release);
notify = move ? MRP_RESOURCE_EVENT_RELEASE : 0;
changed = move || rset->resource.mask.grant;
- rset->state = mrp_resource_release;
rset->resource.mask.grant = 0;
+ new_state = mrp_resource_release;
+ }
+ else if (!pending_release && grant && pending_acquire && (mrp_resource_acquire == rset->state)) {
+ /* Resource is pending for acquisition.
+ * It will be actually granted when the current owner frees it.
+ * No event is emitted at this point. */
+ rset->resource.mask.grant = 0;
+ replyid = 0;
}
else {
if (grant == rset->resource.mask.grant) {
- if (rset->state == mrp_resource_acquire &&
- !grant && rset->dont_wait.current)
- {
- rset->state = mrp_resource_release;
- rset->dont_wait.current = rset->dont_wait.client;
+ if (rset->state == mrp_resource_acquire && !grant) {
+ if (pending_acquire != rset->resource.mask.pending.acquire && !pending_acquire) {
+ changed = true;
+ }
+ else if (rset->dont_wait.current) {
+ new_state = mrp_resource_pending_release;
+ rset->dont_wait.current = rset->dont_wait.client;
- notify = MRP_RESOURCE_EVENT_RELEASE;
- move = true;
+ notify = MRP_RESOURCE_EVENT_RELEASE;
+ }
}
}
else {
rset->resource.mask.grant = grant;
changed = true;
- if (rset->state != mrp_resource_release &&
- !grant && rset->auto_release.current)
- {
- rset->state = mrp_resource_release;
- rset->auto_release.current = rset->auto_release.client;
-
+ if (rset->state == mrp_resource_acquire && pending_release) {
notify = MRP_RESOURCE_EVENT_RELEASE;
- move = true;
+ new_state = mrp_resource_pending_release;
}
}
+
+ if (!grant && new_state == mrp_resource_acquire && rset->auto_release.current) {
+ new_state = mrp_resource_release;
+ rset->auto_release.current = rset->auto_release.client;
+ }
}
+ rset->state = new_state;
+
+ rset->resource.mask.pending.acquire = pending_acquire;
+ rset->resource.mask.pending.release = pending_release;
if (notify) {
mrp_resource_set_notify(rset, notify);
}
- if (advice != rset->resource.mask.advice) {
+ if (advice != rset->resource.mask.advice && !pending_release && !pending_acquire) {
rset->resource.mask.advice = advice;
changed = true;
}
@@ -354,6 +424,15 @@ void mrp_resource_owner_update_zone(uint32_t zoneid,
} /* while rset */
} /* while class */
+ for (rid = 0; rid < rcnt; rid++) {
+ owner = get_owner(zoneid, rid);
+
+ if (owner->rset && owner->rset->resource.mask.pending.acquire) {
+ old = oldowners + rid;
+ restore_owner(owner, old);
+ }
+ }
+
manager_end_transaction(zone);
for (lastev = (ev = events) + nevent; ev < lastev; ev++) {
@@ -476,6 +555,11 @@ static mrp_resource_owner_t *get_owner(uint32_t zone, uint32_t resid)
return resource_owners + (zone * MRP_RESOURCE_MAX + resid);
}
+static void restore_owner(mrp_resource_owner_t *owner, mrp_resource_owner_t *oldowner)
+{
+ memcpy(owner, oldowner, sizeof(mrp_resource_owner_t));
+}
+
static void reset_owners(uint32_t zone, mrp_resource_owner_t *oldowners)
{
mrp_resource_owner_t *owners = get_owner(zone, 0);
diff --git a/src/resource/resource-set.c b/src/resource/resource-set.c
index 12e56d7..d933e27 100644
--- a/src/resource/resource-set.c
+++ b/src/resource/resource-set.c
@@ -197,6 +197,20 @@ mrp_resource_mask_t mrp_get_resource_set_advice(mrp_resource_set_t *rset)
return rset->resource.mask.advice;
}
+mrp_resource_mask_t mrp_get_resource_set_pending_release(mrp_resource_set_t *rset)
+{
+ MRP_ASSERT(rset, "invalid argument");
+
+ return rset->resource.mask.pending.release;
+}
+
+mrp_resource_mask_t mrp_get_resource_set_pending_acquire(mrp_resource_set_t *rset)
+{
+ MRP_ASSERT(rset, "invalid argument");
+
+ return rset->resource.mask.pending.acquire;
+}
+
mrp_resource_client_t *mrp_get_resource_set_client(mrp_resource_set_t *rset)
{
MRP_ASSERT(rset, "invalid argument");
@@ -367,6 +381,8 @@ void mrp_resource_set_release(mrp_resource_set_t *rset, uint32_t reqid)
}
else {
rset->state = mrp_resource_release;
+ rset->resource.mask.pending.release = 0;
+ rset->resource.mask.pending.acquire = 0;
rset->request.id = reqid;
rset->request.stamp = get_request_stamp();
@@ -381,6 +397,32 @@ void mrp_resource_set_release(mrp_resource_set_t *rset, uint32_t reqid)
}
}
+void mrp_resource_set_did_release(mrp_resource_set_t *rset, uint32_t reqid)
+{
+ mqi_handle_t trh;
+
+ MRP_ASSERT(rset, "invalid argument");
+
+ mrp_debug("releasing resource set #%d", rset->id);
+
+ if (!rset->class.ptr)
+ rset->state = mrp_resource_release;
+ else {
+ rset->state = mrp_resource_pending_release;
+ rset->resource.mask.pending.release = 0;
+ rset->request.id = reqid;
+ rset->request.stamp = get_request_stamp();
+
+ mrp_application_class_move_resource_set(rset);
+
+ mrp_resource_set_notify(rset, MRP_RESOURCE_EVENT_RELEASE);
+
+ trh = mqi_begin_transaction();
+ mrp_resource_owner_update_zone(rset->zone, rset, reqid);
+ mqi_commit_transaction(trh);
+ }
+}
+
void mrp_resource_set_updated(mrp_resource_set_t *rset)
{
mrp_resource_t *res;
diff --git a/src/resource/resource-set.h b/src/resource/resource-set.h
index 088aad1..0280953 100644
--- a/src/resource/resource-set.h
+++ b/src/resource/resource-set.h
@@ -61,6 +61,10 @@ struct mrp_resource_set_s {
mrp_resource_mask_t mandatory;
mrp_resource_mask_t grant;
mrp_resource_mask_t advice;
+ struct {
+ mrp_resource_mask_t acquire;
+ mrp_resource_mask_t release;
+ } pending;
} mask;
mrp_list_hook_t list;
bool share;
diff --git a/src/resource/resource.c b/src/resource/resource.c
index 25eb865..0629c7d 100644
--- a/src/resource/resource.c
+++ b/src/resource/resource.c
@@ -77,7 +77,7 @@ static mrp_resource_def_t *resource_def_table[RESOURCE_MAX];
static MRP_LIST_HOOK(manager_list);
static mqi_handle_t resource_user_table[RESOURCE_MAX];
-static uint32_t add_resource_definition(const char *, bool, uint32_t,
+static uint32_t add_resource_definition(const char *, bool, bool, uint32_t,
mrp_resource_mgr_ftbl_t *, void *);
#if 0
@@ -103,6 +103,17 @@ uint32_t mrp_resource_definition_create(const char *name, bool shareable,
mrp_resource_mgr_ftbl_t *manager,
void *mgrdata)
{
+ return mrp_resource_definition_create_with_sync_release(name, shareable,
+ false, attrdefs,
+ manager, mgrdata);
+}
+
+uint32_t mrp_resource_definition_create_with_sync_release(const char *name, bool shareable,
+ bool sync_release,
+ mrp_attr_def_t *attrdefs,
+ mrp_resource_mgr_ftbl_t *manager,
+ void *mgrdata)
+{
uint32_t nattr;
uint32_t id;
mrp_resource_def_t *def;
@@ -117,7 +128,7 @@ uint32_t mrp_resource_definition_create(const char *name, bool shareable,
for (nattr = 0; attrdefs && attrdefs[nattr].name; nattr++)
;
- id = add_resource_definition(name, shareable, nattr, manager, mgrdata);
+ id = add_resource_definition(name, shareable, sync_release, nattr, manager, mgrdata);
if (id != MRP_RESOURCE_ID_INVALID) {
def = mrp_resource_definition_find_by_id(id);
@@ -239,6 +250,18 @@ mrp_attr_t *mrp_resource_definition_read_all_attributes(uint32_t resid,
return retval;
}
+bool mrp_resource_definition_get_sync_release(uint32_t resid)
+{
+ bool result = false;
+
+ mrp_resource_def_t *rdef = mrp_resource_definition_find_by_id(resid);
+ if (rdef) {
+ result = rdef->sync_release;
+ }
+
+ return result;
+}
+
mrp_resource_t *mrp_resource_create(const char *name,
@@ -539,6 +562,7 @@ int mrp_resource_attribute_print(mrp_resource_t *res, char *buf, int len)
static uint32_t add_resource_definition(const char *name,
bool shareable,
+ bool sync_release,
uint32_t nattr,
mrp_resource_mgr_ftbl_t *mgrftbl,
void *mgrdata)
@@ -564,10 +588,11 @@ static uint32_t add_resource_definition(const char *name,
id = resource_def_count++;
- def->id = id;
- def->name = dup_name;
- def->shareable = shareable;
- def->nattr = nattr;
+ def->id = id;
+ def->name = dup_name;
+ def->shareable = shareable;
+ def->sync_release = sync_release;
+ def->nattr = nattr;
if (mgrftbl) {
def->manager.ftbl = mrp_alloc(sizeof(mrp_resource_mgr_ftbl_t));
diff --git a/src/resource/resource.h b/src/resource/resource.h
index 3c01fd9..442d02e 100644
--- a/src/resource/resource.h
+++ b/src/resource/resource.h
@@ -39,6 +39,7 @@ struct mrp_resource_def_s {
uint32_t id;
const char *name;
bool shareable;
+ bool sync_release;
struct {
mrp_list_hook_t list;
mrp_resource_mgr_ftbl_t *ftbl;