Use TLS variable for key state
[libside.git] / src / side.c
index bcce6084ec5fb09e4044142f9c07d667c0c5ba2e..df6123684f3d207c7a4cefe6008b68d4756c8aee 100644 (file)
@@ -38,6 +38,20 @@ struct side_tracer_handle {
        void *priv;
 };
 
+struct side_callback {
+       union {
+               void (*call)(const struct side_event_description *desc,
+                       const struct side_arg_vec *side_arg_vec,
+                       void *priv);
+               void (*call_variadic)(const struct side_event_description *desc,
+                       const struct side_arg_vec *side_arg_vec,
+                       const struct side_arg_dynamic_struct *var_struct,
+                       void *priv);
+       } u;
+       void *priv;
+       void *key;
+};
+
 static struct side_rcu_gp_state rcu_gp;
 
 /*
@@ -57,13 +71,19 @@ static pthread_mutex_t side_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
 static DEFINE_SIDE_LIST_HEAD(side_events_list);
 static DEFINE_SIDE_LIST_HEAD(side_tracer_list);
 
+/*
+ * Callback filter key for state dump.
+ */
+static __thread void *filter_key;
+
 /*
  * The empty callback has a NULL function callback pointer, which stops
  * iteration on the array of callbacks immediately.
  */
-const struct side_callback side_empty_callback = { };
+const char side_empty_callback[sizeof(struct side_callback)];
 
-void side_call(const struct side_event_state *event_state, const struct side_arg_vec *side_arg_vec)
+static
+void _side_call(const struct side_event_state *event_state, const struct side_arg_vec *side_arg_vec, void *key)
 {
        struct side_rcu_read_state rcu_read_state;
        const struct side_event_state_0 *es0;
@@ -83,14 +103,30 @@ void side_call(const struct side_event_state *event_state, const struct side_arg
                // TODO: call kernel write.
        }
        side_rcu_read_begin(&rcu_gp, &rcu_read_state);
-       for (side_cb = side_rcu_dereference(es0->callbacks); side_cb->u.call != NULL; side_cb++)
+       for (side_cb = side_rcu_dereference(es0->callbacks); side_cb->u.call != NULL; side_cb++) {
+               /* A NULL key is always a match. */
+               if (key && side_cb->key && side_cb->key != key)
+                       continue;
                side_cb->u.call(es0->desc, side_arg_vec, side_cb->priv);
+       }
        side_rcu_read_end(&rcu_gp, &rcu_read_state);
 }
 
-void side_call_variadic(const struct side_event_state *event_state,
+void side_call(const struct side_event_state *event_state, const struct side_arg_vec *side_arg_vec)
+{
+       _side_call(event_state, side_arg_vec, NULL);
+}
+
+void side_call_key(const struct side_event_state *event_state, const struct side_arg_vec *side_arg_vec)
+{
+       _side_call(event_state, side_arg_vec, filter_key);
+}
+
+static
+void _side_call_variadic(const struct side_event_state *event_state,
        const struct side_arg_vec *side_arg_vec,
-       const struct side_arg_dynamic_struct *var_struct)
+       const struct side_arg_dynamic_struct *var_struct,
+       void *key)
 {
        struct side_rcu_read_state rcu_read_state;
        const struct side_event_state_0 *es0;
@@ -110,15 +146,33 @@ void side_call_variadic(const struct side_event_state *event_state,
                // TODO: call kernel write.
        }
        side_rcu_read_begin(&rcu_gp, &rcu_read_state);
-       for (side_cb = side_rcu_dereference(es0->callbacks); side_cb->u.call_variadic != NULL; side_cb++)
+       for (side_cb = side_rcu_dereference(es0->callbacks); side_cb->u.call_variadic != NULL; side_cb++) {
+               /* A NULL key is always a match. */
+               if (key && side_cb->key && side_cb->key != key)
+                       continue;
                side_cb->u.call_variadic(es0->desc, side_arg_vec, var_struct, side_cb->priv);
+       }
        side_rcu_read_end(&rcu_gp, &rcu_read_state);
 }
 
+void side_call_variadic(const struct side_event_state *event_state,
+       const struct side_arg_vec *side_arg_vec,
+       const struct side_arg_dynamic_struct *var_struct)
+{
+       _side_call_variadic(event_state, side_arg_vec, var_struct, NULL);
+}
+
+void side_call_variadic_key(const struct side_event_state *event_state,
+       const struct side_arg_vec *side_arg_vec,
+       const struct side_arg_dynamic_struct *var_struct)
+{
+       _side_call_variadic(event_state, side_arg_vec, var_struct, filter_key);
+}
+
 static
 const struct side_callback *side_tracer_callback_lookup(
                const struct side_event_description *desc,
-               void *call, void *priv)
+               void *call, void *priv, void *key)
 {
        struct side_event_state *event_state = side_ptr_get(desc->state);
        const struct side_event_state_0 *es0;
@@ -128,7 +182,7 @@ const struct side_callback *side_tracer_callback_lookup(
                abort();
        es0 = side_container_of(event_state, const struct side_event_state_0, parent);
        for (cb = es0->callbacks; cb->u.call != NULL; cb++) {
-               if ((void *) cb->u.call == call && cb->priv == priv)
+               if ((void *) cb->u.call == call && cb->priv == priv && cb->key == key)
                        return cb;
        }
        return NULL;
@@ -136,7 +190,7 @@ const struct side_callback *side_tracer_callback_lookup(
 
 static
 int _side_tracer_callback_register(struct side_event_description *desc,
-               void *call, void *priv)
+               void *call, void *priv, void *key)
 {
        struct side_event_state *event_state;
        struct side_callback *old_cb, *new_cb;
@@ -161,7 +215,7 @@ int _side_tracer_callback_register(struct side_event_description *desc,
                goto unlock;
        }
        /* Reject duplicate (call, priv) tuples. */
-       if (side_tracer_callback_lookup(desc, call, priv)) {
+       if (side_tracer_callback_lookup(desc, call, priv, key)) {
                ret = SIDE_ERROR_EXIST;
                goto unlock;
        }
@@ -180,6 +234,7 @@ int _side_tracer_callback_register(struct side_event_description *desc,
                new_cb[old_nr_cb].u.call =
                        (side_tracer_callback_func) call;
        new_cb[old_nr_cb].priv = priv;
+       new_cb[old_nr_cb].key = key;
        /* High order bits are already zeroed. */
        side_rcu_assign_pointer(es0->callbacks, new_cb);
        side_rcu_wait_grace_period(&rcu_gp);
@@ -196,24 +251,24 @@ unlock:
 
 int side_tracer_callback_register(struct side_event_description *desc,
                side_tracer_callback_func call,
-               void *priv)
+               void *priv, void *key)
 {
        if (desc->flags & SIDE_EVENT_FLAG_VARIADIC)
                return SIDE_ERROR_INVAL;
-       return _side_tracer_callback_register(desc, (void *) call, priv);
+       return _side_tracer_callback_register(desc, (void *) call, priv, key);
 }
 
 int side_tracer_callback_variadic_register(struct side_event_description *desc,
                side_tracer_callback_variadic_func call_variadic,
-               void *priv)
+               void *priv, void *key)
 {
        if (!(desc->flags & SIDE_EVENT_FLAG_VARIADIC))
                return SIDE_ERROR_INVAL;
-       return _side_tracer_callback_register(desc, (void *) call_variadic, priv);
+       return _side_tracer_callback_register(desc, (void *) call_variadic, priv, key);
 }
 
 static int _side_tracer_callback_unregister(struct side_event_description *desc,
-               void *call, void *priv)
+               void *call, void *priv, void *key)
 {
        struct side_event_state *event_state;
        struct side_callback *old_cb, *new_cb;
@@ -234,7 +289,7 @@ static int _side_tracer_callback_unregister(struct side_event_description *desc,
        if (side_unlikely(event_state->version != 0))
                abort();
        es0 = side_container_of(event_state, struct side_event_state_0, parent);
-       cb_pos = side_tracer_callback_lookup(desc, call, priv);
+       cb_pos = side_tracer_callback_lookup(desc, call, priv, key);
        if (!cb_pos) {
                ret = SIDE_ERROR_NOENT;
                goto unlock;
@@ -270,20 +325,20 @@ unlock:
 
 int side_tracer_callback_unregister(struct side_event_description *desc,
                side_tracer_callback_func call,
-               void *priv)
+               void *priv, void *key)
 {
        if (desc->flags & SIDE_EVENT_FLAG_VARIADIC)
                return SIDE_ERROR_INVAL;
-       return _side_tracer_callback_unregister(desc, (void *) call, priv);
+       return _side_tracer_callback_unregister(desc, (void *) call, priv, key);
 }
 
 int side_tracer_callback_variadic_unregister(struct side_event_description *desc,
                side_tracer_callback_variadic_func call_variadic,
-               void *priv)
+               void *priv, void *key)
 {
        if (!(desc->flags & SIDE_EVENT_FLAG_VARIADIC))
                return SIDE_ERROR_INVAL;
-       return _side_tracer_callback_unregister(desc, (void *) call_variadic, priv);
+       return _side_tracer_callback_unregister(desc, (void *) call_variadic, priv, key);
 }
 
 struct side_events_register_handle *side_events_register(struct side_event_description **events, uint32_t nr_events)
This page took 0.025533 seconds and 4 git commands to generate.