diff options
author | Denis Melenevsky <d.melenevsky@samsung.com> | 2015-07-21 19:04:03 +0300 |
---|---|---|
committer | Denis Melenevsky <d.melenevsky@samsung.com> | 2015-07-21 19:04:03 +0300 |
commit | 89bb9efc1055424c73db0d005356ec6951e3300f (patch) | |
tree | 01865c81e53e70b348173892024404f852238ada | |
parent | b5c2c9c9184f369c193636190c91c6b2cf04c410 (diff) | |
download | murphy-89bb9efc1055424c73db0d005356ec6951e3300f.tar.gz murphy-89bb9efc1055424c73db0d005356ec6951e3300f.tar.bz2 murphy-89bb9efc1055424c73db0d005356ec6951e3300f.zip |
Synchronous resource release mechanismsubmit/tizen/20150722.090021accepted/tizen/wearable/20150722.094530accepted/tizen/tv/20150722.095031accepted/tizen/mobile/20150722.094357
Change-Id: I5d54d013a94acb6c6206d35834a8dacb7bcbf2ce
Signed-off-by: Denis Melenevsky <d.melenevsky@samsung.com>
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; |