Atomic context initialisation for bindings
authorJosé Bollo <jose.bollo@iot.bzh>
Wed, 20 Sep 2017 13:34:11 +0000 (15:34 +0200)
committerJosé Bollo <jose.bollo@iot.bzh>
Mon, 9 Oct 2017 12:08:31 +0000 (14:08 +0200)
Change-Id: I3e81b64d57c917da1fba9b3a9387d0f4d7f3e6b7
Signed-off-by: José Bollo <jose.bollo@iot.bzh>
include/afb/afb-req-common.h
src/afb-context.c
src/afb-context.h
src/afb-hook.c
src/afb-hook.h
src/afb-session.c
src/afb-session.h
src/afb-trace.c
src/afb-xreq.c

index 1bb017e..adb0acf 100644 (file)
@@ -77,6 +77,8 @@ struct afb_req_itf
 
        int (*has_permission)(void *closure, const char *permission);
        char *(*get_application_id)(void *closure);
+
+       void *(*context_make)(void *closure, int replace, void *(*create_value)(void *creation_closure), void (*free_value)(void*), void *creation_closure);
 };
 
 /*
@@ -257,12 +259,22 @@ static inline void afb_req_context_set(struct afb_req req, void *context, void (
  */
 static inline void *afb_req_context(struct afb_req req, void *(*create_context)(), void (*free_context)(void*))
 {
-       void *result = afb_req_context_get(req);
-       if (!result) {
-               result = create_context();
-               afb_req_context_set(req, result, free_context);
-       }
-       return result;
+       return req.itf->context_make(req.closure, 0, (void *(*)(void*))(void*)create_context, free_context, 0);
+}
+
+/*
+ * Gets the pointer stored by the binding for the session of 'request'.
+ * If no previous pointer is stored or if 'replace' is not zero, a new value
+ * is generated using the function 'create_context' called with the 'closure'.
+ * If 'create_context' is NULL the generated value is 'closure'.
+ * When a value is created, the function 'free_context' is recorded and will
+ * be called (with the created value as argument) to free the created value when
+ * it is not more used.
+ * This function is atomic: it ensures that 2 threads will not race together.
+ */
+static inline void *afb_req_context_make(struct afb_req req, int replace, void *(*create_context)(void *closure), void (*free_context)(void*), void *closure)
+{
+       return req.itf->context_make(req.closure, replace, create_context, free_context, closure);
 }
 
 /*
index 11abcd4..759ee90 100644 (file)
@@ -118,10 +118,10 @@ const char *afb_context_sent_uuid(struct afb_context *context)
        return afb_session_uuid(context->session);
 }
 
-void *afb_context_data(struct afb_context *context, void *(*make_value)(void), void (*free_value)(void*))
+void *afb_context_make(struct afb_context *context, int replace, void *(*make_value)(void *closure), void (*free_value)(void *item), void *closure)
 {
        assert(context->session != NULL);
-       return afb_session_cookie(context->session, context->api_key, make_value, free_value);
+       return afb_session_cookie(context->session, context->api_key, make_value, free_value, closure, replace);
 }
 
 void *afb_context_get(struct afb_context *context)
index 47e488c..a3e4e56 100644 (file)
@@ -48,7 +48,7 @@ extern const char *afb_context_uuid(struct afb_context *context);
 
 extern void *afb_context_get(struct afb_context *context);
 extern int afb_context_set(struct afb_context *context, void *value, void (*free_value)(void*));
-extern void *afb_context_data(struct afb_context *context, void *(*make_value)(void), void (*free_value)(void*));
+extern void *afb_context_make(struct afb_context *context, int replace, void *(*make_value)(void *closure), void (*free_value)(void *item), void *closure);
 
 extern void afb_context_close(struct afb_context *context);
 extern void afb_context_refresh(struct afb_context *context);
index 188aaba..b3a13a7 100644 (file)
@@ -359,6 +359,11 @@ static void hook_xreq_get_application_id_default_cb(void *closure, const struct
        _hook_xreq_(xreq, "get_application_id() -> %s", result);
 }
 
+static void hook_xreq_context_make_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure, void *result)
+{
+       _hook_xreq_(xreq, "context_make(replace=%s, %p, %p, %p) -> %p", replace?"yes":"no", create_value, free_value, create_closure, result);
+}
+
 static struct afb_hook_xreq_itf hook_xreq_default_itf = {
        .hook_xreq_begin = hook_xreq_begin_default_cb,
        .hook_xreq_end = hook_xreq_end_default_cb,
@@ -384,7 +389,8 @@ static struct afb_hook_xreq_itf hook_xreq_default_itf = {
        .hook_xreq_subcall_req = hook_xreq_subcall_req_default_cb,
        .hook_xreq_subcall_req_result = hook_xreq_subcall_req_result_default_cb,
        .hook_xreq_has_permission = hook_xreq_has_permission_default_cb,
-       .hook_xreq_get_application_id = hook_xreq_get_application_id_default_cb
+       .hook_xreq_get_application_id = hook_xreq_get_application_id_default_cb,
+       .hook_xreq_context_make = hook_xreq_context_make_default_cb
 };
 
 /******************************************************************************
@@ -544,6 +550,12 @@ char *afb_hook_xreq_get_application_id(const struct afb_xreq *xreq, char *result
        return result;
 }
 
+void *afb_hook_xreq_context_make(const struct afb_xreq *xreq, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure, void *result)
+{
+       _HOOK_XREQ_(context_make, xreq, replace, create_value, free_value, create_closure, result);
+       return result;
+}
+
 /******************************************************************************
  * section: hooking xreqs
  *****************************************************************************/
index b3707a6..be4ba54 100644 (file)
@@ -76,6 +76,7 @@ struct afb_hookid
 #define afb_hook_flag_req_subcall_req_result   0x00400000
 #define afb_hook_flag_req_has_permission       0x00800000
 #define afb_hook_flag_req_get_application_id   0x01000000
+#define afb_hook_flag_req_context_make         0x02000000
 
 /* common flags */
 #define afb_hook_flags_req_life                (afb_hook_flag_req_begin|afb_hook_flag_req_end)
@@ -90,7 +91,8 @@ struct afb_hookid
 
 /* extra flags */
 #define afb_hook_flags_req_ref         (afb_hook_flag_req_addref|afb_hook_flag_req_unref)
-#define afb_hook_flags_req_context     (afb_hook_flag_req_context_get|afb_hook_flag_req_context_set)
+#define afb_hook_flags_req_context     (afb_hook_flag_req_context_get|afb_hook_flag_req_context_set\
+                                       |afb_hook_flag_req_context_make)
 #define afb_hook_flags_req_stores      (afb_hook_flag_req_store|afb_hook_flag_req_unstore)
 
 /* predefined groups */
@@ -127,6 +129,7 @@ struct afb_hook_xreq_itf {
        void (*hook_xreq_subcall_req_result)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result);
        void (*hook_xreq_has_permission)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *permission, int result);
        void (*hook_xreq_get_application_id)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, char *result);
+       void (*hook_xreq_context_make)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure, void *result);
 };
 
 extern void afb_hook_init_xreq(struct afb_xreq *xreq);
@@ -161,6 +164,7 @@ extern void afb_hook_xreq_subcall_req(const struct afb_xreq *xreq, const char *a
 extern void afb_hook_xreq_subcall_req_result(const struct afb_xreq *xreq, int status, struct json_object *result);
 extern int afb_hook_xreq_has_permission(const struct afb_xreq *xreq, const char *permission, int result);
 extern char *afb_hook_xreq_get_application_id(const struct afb_xreq *xreq, char *result);
+extern void *afb_hook_xreq_context_make(const struct afb_xreq *xreq, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure, void *result);
 
 /*********************************************************
 * section hooking export (daemon interface)
index db7a99a..61bce09 100644 (file)
@@ -433,7 +433,7 @@ static struct cookie *cookie_add(struct afb_session *session, int idx, const voi
        return cookie;
 }
 
-void *afb_session_cookie(struct afb_session *session, const void *key, void *(*makecb)(void), void (*freecb)(void*))
+void *afb_session_cookie(struct afb_session *session, const void *key, void *(*makecb)(void *closure), void (*freecb)(void *item), void *closure, int replace)
 {
        int idx;
        void *value;
@@ -441,11 +441,19 @@ void *afb_session_cookie(struct afb_session *session, const void *key, void *(*m
 
        lock(session);
        cookie = cookie_search(session, key, &idx);
-       if (cookie)
-               value = cookie->value;
-       else {
-               value = makecb ? makecb() : NULL;
-               if (makecb || freecb) {
+       if (cookie) {
+               if (!replace)
+                       value = cookie->value;
+               else {
+                       value = makecb ? makecb(closure) : closure;
+                       if (cookie->value != value && cookie->freecb)
+                               cookie->freecb(cookie->value);
+                       cookie->value = value;
+                       cookie->freecb = freecb;
+               }
+       } else {
+               value = makecb ? makecb(closure) : closure;
+               if (replace || makecb || freecb) {
                        cookie = cookie_add(session, idx, key, value, freecb);
                        if (!cookie) {
                                if (makecb && freecb)
index ccedb4a..b5dc394 100644 (file)
@@ -36,6 +36,6 @@ extern void afb_session_new_token(struct afb_session *session);
 extern const char *afb_session_token(struct afb_session *session);
 
 extern void *afb_session_get_cookie(struct afb_session *session, const void *key);
-extern void *afb_session_cookie(struct afb_session *session, const void *key, void *(*makecb)(void), void (*freecb)(void*));
+extern void *afb_session_cookie(struct afb_session *session, const void *key, void *(*makecb)(void *closure), void (*freecb)(void *item), void *closure, int replace);
 extern int afb_session_set_cookie(struct afb_session *session, const void *key, void *value, void (*freecb)(void*));
 
index e413410..5e82274 100644 (file)
@@ -221,6 +221,7 @@ static struct flag xreq_flags[] = { /* must be sorted by names */
                { "common",             afb_hook_flags_req_common },
                { "context",            afb_hook_flags_req_context },
                { "context_get",        afb_hook_flag_req_context_get },
+               { "context_make",       afb_hook_flag_req_context_make },
                { "context_set",        afb_hook_flag_req_context_set },
                { "end",                afb_hook_flag_req_end },
                { "event",              afb_hook_flags_req_event },
@@ -472,6 +473,21 @@ static void hook_xreq_get_application_id(void *closure, const struct afb_hookid
                                        "result", result);
 }
 
+static void hook_xreq_context_make(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure, void *result)
+{
+       char pc[50], pf[50], pv[50], pr[50];
+       snprintf(pc, sizeof pc, "%p", create_value);
+       snprintf(pf, sizeof pf, "%p", free_value);
+       snprintf(pv, sizeof pv, "%p", create_closure);
+       snprintf(pr, sizeof pr, "%p", result);
+       hook_xreq(closure, hookid, xreq, "context_make", "{sb ss ss ss ss}",
+                                       "replace", replace,
+                                       "create", pc,
+                                       "free", pf,
+                                       "closure", pv,
+                                       "result", pr);
+}
+
 static struct afb_hook_xreq_itf hook_xreq_itf = {
        .hook_xreq_begin = hook_xreq_begin,
        .hook_xreq_end = hook_xreq_end,
@@ -497,7 +513,8 @@ static struct afb_hook_xreq_itf hook_xreq_itf = {
        .hook_xreq_subcall_req = hook_xreq_subcall_req,
        .hook_xreq_subcall_req_result = hook_xreq_subcall_req_result,
        .hook_xreq_has_permission = hook_xreq_has_permission,
-       .hook_xreq_get_application_id = hook_xreq_get_application_id
+       .hook_xreq_get_application_id = hook_xreq_get_application_id,
+       .hook_xreq_context_make = hook_xreq_context_make
 };
 
 /*******************************************************************************/
index 13deeb0..696bf9d 100644 (file)
@@ -527,6 +527,12 @@ static char *xreq_get_application_id_cb(void*closure)
        return xreq->cred && xreq->cred->id ? strdup(xreq->cred->id) : NULL;
 }
 
+static void *xreq_context_make_cb(void *closure, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure)
+{
+       struct afb_xreq *xreq = closure;
+       return afb_context_make(&xreq->context, replace, create_value, free_value, create_closure);
+}
+
 /******************************************************************************/
 
 static struct json_object *xreq_hooked_json_cb(void *closure)
@@ -696,6 +702,13 @@ static char *xreq_hooked_get_application_id_cb(void*closure)
        return afb_hook_xreq_get_application_id(xreq, r);
 }
 
+static void *xreq_hooked_context_make_cb(void *closure, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure)
+{
+       struct afb_xreq *xreq = closure;
+       void *result = xreq_context_make_cb(closure, replace, create_value, free_value, create_closure);
+       return afb_hook_xreq_context_make(xreq, replace, create_value, free_value, create_closure, result);
+}
+
 /******************************************************************************/
 
 const struct afb_req_itf xreq_itf = {
@@ -719,7 +732,8 @@ const struct afb_req_itf xreq_itf = {
        .store = xreq_store_cb,
        .subcall_req = xreq_subcall_req_cb,
        .has_permission = xreq_has_permission_cb,
-       .get_application_id = xreq_get_application_id_cb
+       .get_application_id = xreq_get_application_id_cb,
+       .context_make = xreq_context_make_cb
 };
 
 const struct afb_req_itf xreq_hooked_itf = {
@@ -743,7 +757,8 @@ const struct afb_req_itf xreq_hooked_itf = {
        .store = xreq_hooked_store_cb,
        .subcall_req = xreq_hooked_subcall_req_cb,
        .has_permission = xreq_hooked_has_permission_cb,
-       .get_application_id = xreq_hooked_get_application_id_cb
+       .get_application_id = xreq_hooked_get_application_id_cb,
+       .context_make = xreq_hooked_context_make_cb
 };
 
 /******************************************************************************/