uint32_t loglevel; /* enum side_loglevel */
uint32_t nr_fields;
uint32_t nr_attr;
- uint32_t nr_cb;
+ uint32_t _unused;
uint64_t flags;
const char *provider_name;
const char *event_name;
const struct side_event_field *fields;
const struct side_attr *attr;
- struct side_callback *callbacks;
+ const struct side_callback *callbacks;
};
struct side_arg_dynamic_vec {
.loglevel = _loglevel, \
.nr_fields = SIDE_ARRAY_SIZE(SIDE_PARAM(_fields)), \
.nr_attr = SIDE_ARRAY_SIZE(SIDE_PARAM(_attr)), \
- .nr_cb = 0, \
+ ._unused = 0, \
.flags = (_flags), \
.provider_name = _provider, \
.event_name = _event, \
.fields = _fields, \
.attr = _attr, \
- .callbacks = NULL, \
+ .callbacks = &side_empty_callback, \
}; \
static const struct side_event_description *side_event_ptr__##_identifier \
__attribute__((section("side_event_description_ptr"), used)) = &(_identifier);
const struct side_arg_vec_description *sav_desc,
const struct side_arg_dynamic_event_struct *var_struct);
+extern const struct side_callback side_empty_callback;
+
#endif /* _SIDE_TRACE_H */
*/
#include <sched.h>
+#include <string.h>
#include <stdint.h>
#include <pthread.h>
#include <stdbool.h>
#include <poll.h>
+#include <stdlib.h>
#include "rcu.h"
+#include "smp.h"
/* active_readers is an input/output parameter. */
static
*/
__atomic_thread_fence(__ATOMIC_SEQ_CST);
}
+
+void side_rcu_gp_init(struct side_rcu_gp_state *rcu_gp)
+{
+ memset(rcu_gp, 0, sizeof(*rcu_gp));
+ rcu_gp->nr_cpus = get_possible_cpus_array_len();
+ if (!rcu_gp->nr_cpus)
+ abort();
+ pthread_mutex_init(&rcu_gp->gp_lock, NULL);
+ rcu_gp->percpu_state = calloc(rcu_gp->nr_cpus, sizeof(struct side_rcu_cpu_gp_state));
+ if (!rcu_gp->percpu_state)
+ abort();
+}
#include <side/trace.h>
#include "tracer.h"
#include "rcu.h"
-#include "smp.h"
+/* Top 8 bits reserved for kernel tracer use. */
+#define SIDE_EVENT_ENABLED_KERNEL_MASK 0xFF000000
#define SIDE_EVENT_ENABLED_KERNEL_USER_EVENT_MASK 0x80000000
-struct side_rcu_gp_state rcu_gp = {
- .percpu_state = NULL,
- .nr_cpus = 0,
- .period = 0,
- .gp_lock = PTHREAD_MUTEX_INITIALIZER,
-};
+/* Allow 2^24 tracers to be registered on an event. */
+#define SIDE_EVENT_ENABLED_USER_MASK 0x00FFFFFF
+
+struct side_rcu_gp_state rcu_gp;
/*
* Lazy initialization for early use within library constructors.
void side_init(void)
__attribute__((constructor));
+const struct side_callback side_empty_callback;
+
void side_call(const struct side_event_description *desc, const struct side_arg_vec_description *sav_desc)
{
+ const struct side_callback *side_cb;
+ unsigned int rcu_period;
+
if (side_unlikely(!initialized))
side_init();
if (side_unlikely(desc->flags & SIDE_EVENT_FLAG_VARIADIC)) {
if (side_unlikely(*desc->enabled & SIDE_EVENT_ENABLED_KERNEL_USER_EVENT_MASK)) {
// TODO: call kernel write.
}
+ if (side_unlikely(!(*desc->enabled & SIDE_EVENT_ENABLED_USER_MASK)))
+ return;
+
//TODO: replace tracer_call by rcu iteration on list of registered callbacks
tracer_call(desc, sav_desc, NULL);
+
+ rcu_period = side_rcu_read_begin(&rcu_gp);
+ for (side_cb = side_rcu_dereference(desc->callbacks); side_cb->u.call != NULL; side_cb++)
+ side_cb->u.call(desc, sav_desc, side_cb->priv);
+ side_rcu_read_end(&rcu_gp, rcu_period);
}
void side_call_variadic(const struct side_event_description *desc,
const struct side_arg_vec_description *sav_desc,
const struct side_arg_dynamic_event_struct *var_struct)
{
+ const struct side_callback *side_cb;
+ unsigned int rcu_period;
+
if (side_unlikely(!initialized))
side_init();
if (side_unlikely(*desc->enabled & SIDE_EVENT_ENABLED_KERNEL_USER_EVENT_MASK)) {
// TODO: call kernel write.
}
+ if (side_unlikely(!(*desc->enabled & SIDE_EVENT_ENABLED_USER_MASK)))
+ return;
+
//TODO: replace tracer_call by rcu iteration on list of registered callbacks
tracer_call_variadic(desc, sav_desc, var_struct, NULL);
+
+ rcu_period = side_rcu_read_begin(&rcu_gp);
+ for (side_cb = side_rcu_dereference(desc->callbacks); side_cb->u.call_variadic != NULL; side_cb++)
+ side_cb->u.call_variadic(desc, sav_desc, var_struct, side_cb->priv);
+ side_rcu_read_end(&rcu_gp, rcu_period);
}
void side_init(void)
{
if (initialized)
return;
- rcu_gp.nr_cpus = get_possible_cpus_array_len();
- if (!rcu_gp.nr_cpus)
- abort();
+ side_rcu_gp_init(&rcu_gp);
initialized = true;
}