+/*
+ * Callsite hash table, containing the tracepoint call sites.
+ * Protected by tracepoint mutex.
+ */
+#define CALLSITE_HASH_BITS 12
+#define CALLSITE_TABLE_SIZE (1 << CALLSITE_HASH_BITS)
+static struct cds_hlist_head callsite_table[CALLSITE_TABLE_SIZE];
+
+struct callsite_entry {
+ struct cds_hlist_node hlist; /* hash table node */
+ struct cds_list_head node; /* lib list of callsites node */
+ struct lttng_ust_tracepoint *tp;
+ 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] */