#include <stdio.h>
#include <urcu/arch.h>
-#include <urcu-bp.h>
+#include <lttng/urcu/urcu-ust.h>
#include <urcu/hlist.h>
#include <urcu/uatomic.h>
#include <urcu/compiler.h>
bool tp_entry_callsite_ref; /* Has a tp_entry took a ref on this callsite */
};
+static int tracepoint_v1_api_used;
+static void (*lttng_ust_liburcu_bp_synchronize_rcu)(void);
+static void (*lttng_ust_liburcu_bp_rcu_read_lock)(void);
+static void (*lttng_ust_liburcu_bp_rcu_read_unlock)(void);
+void (*lttng_ust_liburcu_bp_before_fork)(void);
+void (*lttng_ust_liburcu_bp_after_fork_parent)(void);
+void (*lttng_ust_liburcu_bp_after_fork_child)(void);
+
+static bool lttng_ust_tracepoint_v1_used(void)
+{
+ return uatomic_read(&tracepoint_v1_api_used);
+}
+
+static void lttng_ust_tracepoint_set_v1_used(void)
+{
+ if (!lttng_ust_tracepoint_v1_used()) {
+ /*
+ * Perform dlsym here rather than lazily on first use to
+ * eliminate nesting of dynamic loader lock (used within
+ * dlsym) inside the ust lock.
+ */
+ if (!lttng_ust_liburcu_bp_synchronize_rcu) {
+ lttng_ust_liburcu_bp_synchronize_rcu = URCU_FORCE_CAST(void (*)(void),
+ dlsym(RTLD_DEFAULT, "synchronize_rcu_bp"));
+ /*
+ * Allow legacy applications compiled without
+ * _LGPL_SOURCE to use v1 API. Those are not
+ * required to be linked against liburcu-bp,
+ * so in those situations the liburcu-bp symbols
+ * are not present in the global symbol table,
+ * and we do not need to call urcu-bp
+ * synchronize.
+ *
+ * However, nothing prevents a _LGPL_SOURCE
+ * instrumented library loaded afterwards to
+ * require liburcu-bp, so we need to check again
+ * in that situation.
+ */
+ if (!lttng_ust_liburcu_bp_synchronize_rcu)
+ return;
+ }
+ if (!lttng_ust_liburcu_bp_before_fork) {
+ lttng_ust_liburcu_bp_before_fork = URCU_FORCE_CAST(void (*)(void),
+ dlsym(RTLD_DEFAULT, "rcu_bp_before_fork"));
+ if (!lttng_ust_liburcu_bp_before_fork)
+ abort();
+ }
+ if (!lttng_ust_liburcu_bp_after_fork_parent) {
+ lttng_ust_liburcu_bp_after_fork_parent = URCU_FORCE_CAST(void (*)(void),
+ dlsym(RTLD_DEFAULT, "rcu_bp_after_fork_parent"));
+ if (!lttng_ust_liburcu_bp_after_fork_parent)
+ abort();
+ }
+ if (!lttng_ust_liburcu_bp_after_fork_child) {
+ lttng_ust_liburcu_bp_after_fork_child = URCU_FORCE_CAST(void (*)(void),
+ dlsym(RTLD_DEFAULT, "rcu_bp_after_fork_child"));
+ if (!lttng_ust_liburcu_bp_after_fork_child)
+ abort();
+ }
+ if (!lttng_ust_liburcu_bp_rcu_read_lock) {
+ lttng_ust_liburcu_bp_rcu_read_lock = URCU_FORCE_CAST(void (*)(void),
+ dlsym(RTLD_DEFAULT, "rcu_read_lock_bp"));
+ if (!lttng_ust_liburcu_bp_rcu_read_lock)
+ abort();
+ }
+ if (!lttng_ust_liburcu_bp_rcu_read_unlock) {
+ lttng_ust_liburcu_bp_rcu_read_unlock = URCU_FORCE_CAST(void (*)(void),
+ dlsym(RTLD_DEFAULT, "rcu_read_unlock_bp"));
+ if (!lttng_ust_liburcu_bp_rcu_read_unlock)
+ abort();
+ }
+
+ /* Fixup URCU bp TLS. */
+ lttng_ust_liburcu_bp_rcu_read_lock();
+ lttng_ust_liburcu_bp_rcu_read_unlock();
+
+ uatomic_set(&tracepoint_v1_api_used, 1);
+ }
+}
+
/* coverity[+alloc] */
static void *allocate_probes(int count)
{
if (old) {
struct tp_probes *tp_probes = caa_container_of(old,
struct tp_probes, probes[0]);
- synchronize_rcu();
+ lttng_ust_synchronize_trace();
free(tp_probes);
}
}
* include/linux/tracepoints.h. A matching cmm_smp_read_barrier_depends()
* is used.
*/
- rcu_assign_pointer(elem->probes, (*entry)->probes);
+ lttng_ust_rcu_assign_pointer(elem->probes, (*entry)->probes);
CMM_STORE_SHARED(elem->state, active);
}
static void disable_tracepoint(struct lttng_ust_tracepoint *elem)
{
CMM_STORE_SHARED(elem->state, 0);
- rcu_assign_pointer(elem->probes, NULL);
+ lttng_ust_rcu_assign_pointer(elem->probes, NULL);
}
/*
release_queue_need_update = 0;
/* Wait for grace period between all sync_callsites and free. */
- synchronize_rcu();
+ lttng_ust_synchronize_trace();
cds_list_for_each_entry_safe(pos, next, &release_probes, u.list) {
cds_list_del(&pos->u.list);
tracepoint_update_probes();
/* Wait for grace period between update_probes and free. */
- synchronize_rcu();
+ lttng_ust_synchronize_trace();
cds_list_for_each_entry_safe(pos, next, &release_probes, u.list) {
cds_list_del(&pos->u.list);
free(pos);
}
}
-int tracepoint_register_lib(struct lttng_ust_tracepoint * const *tracepoints_start,
- int tracepoints_count)
+/*
+ * tracepoint_{un,}register_lib is meant to be looked up by instrumented
+ * applications through dlsym(). If found, those can register their
+ * tracepoints, else those tracepoints will not be available for
+ * tracing. The number at the end of those symbols acts as a major
+ * version for tracepoints.
+ *
+ * Older instrumented applications should still work with newer
+ * liblttng-ust, but it is fine that instrumented applications compiled
+ * against recent liblttng-ust headers require a recent liblttng-ust
+ * runtime for those tracepoints to be taken into account.
+ */
+int tracepoint_register_lib2(struct lttng_ust_tracepoint * const *tracepoints_start,
+ int tracepoints_count)
{
struct tracepoint_lib *pl, *iter;
return 0;
}
-int tracepoint_unregister_lib(struct lttng_ust_tracepoint * const *tracepoints_start)
+/* Exposed for backward compatibility with old instrumented applications. */
+int tracepoint_register_lib(struct lttng_ust_tracepoint * const *tracepoints_start,
+ int tracepoints_count)
+{
+ lttng_ust_tracepoint_set_v1_used();
+ return tracepoint_register_lib2(tracepoints_start, tracepoints_count);
+}
+
+int tracepoint_unregister_lib2(struct lttng_ust_tracepoint * const *tracepoints_start)
{
struct tracepoint_lib *lib;
return 0;
}
+/* Exposed for backward compatibility with old instrumented applications. */
+int tracepoint_unregister_lib(struct lttng_ust_tracepoint * const *tracepoints_start)
+{
+ lttng_ust_tracepoint_set_v1_used();
+ return tracepoint_unregister_lib2(tracepoints_start);
+}
+
/*
* Report in debug message whether the compiler correctly supports weak
* hidden symbols. This test checks that the address associated with two
/*
* Create the wrapper symbols.
*/
-#undef tp_rcu_read_lock_bp
-#undef tp_rcu_read_unlock_bp
-#undef tp_rcu_dereference_bp
+#undef tp_rcu_read_lock
+#undef tp_rcu_read_unlock
+#undef tp_rcu_dereference
-void tp_rcu_read_lock_bp(void)
+void tp_rcu_read_lock(void)
{
- rcu_read_lock_bp();
+ lttng_ust_urcu_read_lock();
}
-void tp_rcu_read_unlock_bp(void)
+void tp_rcu_read_unlock(void)
{
- rcu_read_unlock_bp();
+ lttng_ust_urcu_read_unlock();
}
-void *tp_rcu_dereference_sym_bp(void *p)
+void *tp_rcu_dereference_sym(void *p)
{
- return rcu_dereference_bp(p);
+ return lttng_ust_rcu_dereference(p);
}
/*
{
return uatomic_read(&tracepoint_destructors_state);
}
+
+void lttng_ust_synchronize_trace(void)
+{
+ lttng_ust_urcu_synchronize_rcu();
+ /*
+ * For legacy tracepoint instrumentation, also wait for urcu-bp
+ * grace period.
+ */
+ if (lttng_ust_liburcu_bp_synchronize_rcu)
+ lttng_ust_liburcu_bp_synchronize_rcu();
+}
+
+/*
+ * Create the wrapper symbols for legacy v1 API.
+ */
+void tp_rcu_read_lock_bp(void)
+{
+ lttng_ust_urcu_read_lock();
+}
+
+void tp_rcu_read_unlock_bp(void)
+{
+ lttng_ust_urcu_read_unlock();
+}
+
+void *tp_rcu_dereference_sym_bp(void *p)
+{
+ return lttng_ust_rcu_dereference(p);
+}