aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosé Bollo <jose.bollo@iot.bzh>2017-09-20 15:34:11 +0200
committerJosé Bollo <jose.bollo@iot.bzh>2017-10-09 14:08:31 +0200
commit7b42076a77b81e205ecc704c3bb7538716567487 (patch)
treef1158e4ea14177f01ebf55355aa995257c7b79c8
parent9ece61d2cbda88878b9f1e6a6e62d3d42cbdef00 (diff)
Atomic context initialisation for bindings
Change-Id: I3e81b64d57c917da1fba9b3a9387d0f4d7f3e6b7 Signed-off-by: José Bollo <jose.bollo@iot.bzh>
-rw-r--r--include/afb/afb-req-common.h24
-rw-r--r--src/afb-context.c4
-rw-r--r--src/afb-context.h2
-rw-r--r--src/afb-hook.c14
-rw-r--r--src/afb-hook.h6
-rw-r--r--src/afb-session.c20
-rw-r--r--src/afb-session.h2
-rw-r--r--src/afb-trace.c19
-rw-r--r--src/afb-xreq.c19
9 files changed, 89 insertions, 21 deletions
diff --git a/include/afb/afb-req-common.h b/include/afb/afb-req-common.h
index 1bb017ef..adb0acf4 100644
--- a/include/afb/afb-req-common.h
+++ b/include/afb/afb-req-common.h
@@ -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);
}
/*
diff --git a/src/afb-context.c b/src/afb-context.c
index 11abcd48..759ee90e 100644
--- a/src/afb-context.c
+++ b/src/afb-context.c
@@ -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)
diff --git a/src/afb-context.h b/src/afb-context.h
index 47e488c4..a3e4e568 100644
--- a/src/afb-context.h
+++ b/src/afb-context.h
@@ -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);
diff --git a/src/afb-hook.c b/src/afb-hook.c
index 188aabae..b3a13a7e 100644
--- a/src/afb-hook.c
+++ b/src/afb-hook.c
@@ -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
*****************************************************************************/
diff --git a/src/afb-hook.h b/src/afb-hook.h
index b3707a6d..be4ba54a 100644
--- a/src/afb-hook.h
+++ b/src/afb-hook.h
@@ -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)
diff --git a/src/afb-session.c b/src/afb-session.c
index db7a99a3..61bce09a 100644
--- a/src/afb-session.c
+++ b/src/afb-session.c
@@ -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)
diff --git a/src/afb-session.h b/src/afb-session.h
index ccedb4ab..b5dc3944 100644
--- a/src/afb-session.h
+++ b/src/afb-session.h
@@ -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*));
diff --git a/src/afb-trace.c b/src/afb-trace.c
index e4134103..5e82274a 100644
--- a/src/afb-trace.c
+++ b/src/afb-trace.c
@@ -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
};
/*******************************************************************************/
diff --git a/src/afb-xreq.c b/src/afb-xreq.c
index 13deeb06..696bf9d4 100644
--- a/src/afb-xreq.c
+++ b/src/afb-xreq.c
@@ -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
};
/******************************************************************************/