tracepoint: move "probe" test outside of loop
[lttng-ust.git] / liblttng-ust / tracepoint.c
CommitLineData
f99be407 1/*
b27f8e75 2 * Copyright (C) 2008-2011 Mathieu Desnoyers
1f8b0dff 3 * Copyright (C) 2009 Pierre-Marc Fournier
f99be407 4 *
34e4b7db
PMF
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
f37142a4
MD
7 * License as published by the Free Software Foundation;
8 * version 2.1 of the License.
f99be407 9 *
34e4b7db 10 * This library is distributed in the hope that it will be useful,
f99be407 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
34e4b7db
PMF
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
f99be407 14 *
34e4b7db
PMF
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1f8b0dff
PMF
18 *
19 * Ported to userspace by Pierre-Marc Fournier.
f99be407 20 */
1f8b0dff 21
b0c4126f 22#define _LGPL_SOURCE
474d745f 23#include <errno.h>
b728d87e
MD
24#include <stdint.h>
25#include <stddef.h>
33661f97 26#include <stdio.h>
44c72f10 27
b728d87e 28#include <urcu/arch.h>
b7ea1a1c 29#include <urcu-bp.h>
10c56168 30#include <urcu/hlist.h>
edaa1431 31#include <urcu/uatomic.h>
b728d87e 32#include <urcu/compiler.h>
44c72f10
MD
33
34#include <lttng/tracepoint.h>
ff412fb5 35#include <lttng/ust-abi.h> /* for LTTNG_UST_SYM_NAME_LEN */
44c72f10
MD
36
37#include <usterr-signal-safe.h>
35897f8b 38#include <helper.h>
474d745f 39
23c8854a 40#include "tracepoint-internal.h"
7dd08bec 41#include "lttng-tracer-core.h"
596c4223 42#include "jhash.h"
8f3f8c99 43#include "error.h"
b0c4126f 44
f99be407
PMF
45/* Set to 1 to enable tracepoint debug output */
46static const int tracepoint_debug;
b27f8e75
MD
47static int initialized;
48static void (*new_tracepoint_cb)(struct tracepoint *);
f99be407 49
8792fbae
MD
50/*
51 * tracepoint_mutex nests inside UST mutex.
52 *
53 * Note about interaction with fork/clone: UST does not hold the
54 * tracepoint mutex across fork/clone because it is either:
55 * - nested within UST mutex, in which case holding the UST mutex across
56 * fork/clone suffice,
57 * - taken by a library constructor, which should never race with a
58 * fork/clone if the application is expected to continue running with
59 * the same memory layout (no following exec()).
60 */
61static pthread_mutex_t tracepoint_mutex = PTHREAD_MUTEX_INITIALIZER;
62
efa2c591
MD
63/*
64 * libraries that contain tracepoints (struct tracepoint_lib).
8792fbae 65 * Protected by tracepoint mutex.
efa2c591 66 */
0222e121 67static CDS_LIST_HEAD(libs);
474d745f 68
f99be407 69/*
8792fbae 70 * The tracepoint mutex protects the library tracepoints, the hash table, and
17dfb34b 71 * the library list.
8792fbae 72 * All calls to the tracepoint API must be protected by the tracepoint mutex,
17dfb34b 73 * excepts calls to tracepoint_register_lib and
8792fbae 74 * tracepoint_unregister_lib, which take the tracepoint mutex themselves.
f99be407 75 */
f99be407
PMF
76
77/*
78 * Tracepoint hash table, containing the active tracepoints.
8792fbae 79 * Protected by tracepoint mutex.
f99be407 80 */
814f7df1 81#define TRACEPOINT_HASH_BITS 12
f99be407 82#define TRACEPOINT_TABLE_SIZE (1 << TRACEPOINT_HASH_BITS)
10c56168 83static struct cds_hlist_head tracepoint_table[TRACEPOINT_TABLE_SIZE];
f99be407 84
b27f8e75
MD
85static CDS_LIST_HEAD(old_probes);
86static int need_update;
87
f99be407
PMF
88/*
89 * Note about RCU :
90 * It is used to to delay the free of multiple probes array until a quiescent
91 * state is reached.
8792fbae 92 * Tracepoint entries modifications are protected by the tracepoint mutex.
f99be407
PMF
93 */
94struct tracepoint_entry {
10c56168 95 struct cds_hlist_node hlist;
b979b346 96 struct tracepoint_probe *probes;
f99be407 97 int refcount; /* Number of times armed. 0 if disarmed. */
67e5f391 98 const char *signature;
f99be407
PMF
99 char name[0];
100};
101
102struct tp_probes {
103 union {
0222e121 104 struct cds_list_head list;
ade7037b
MD
105 /* Field below only used for call_rcu scheme */
106 /* struct rcu_head head; */
f99be407 107 } u;
b979b346 108 struct tracepoint_probe probes[0];
f99be407
PMF
109};
110
efa2c591 111static void *allocate_probes(int count)
f99be407 112{
b979b346 113 struct tp_probes *p = zmalloc(count * sizeof(struct tracepoint_probe)
909bc43f 114 + sizeof(struct tp_probes));
f99be407
PMF
115 return p == NULL ? NULL : p->probes;
116}
117
efa2c591 118static void release_probes(void *old)
f99be407
PMF
119{
120 if (old) {
b728d87e 121 struct tp_probes *tp_probes = caa_container_of(old,
f99be407 122 struct tp_probes, probes[0]);
474d745f 123 synchronize_rcu();
909bc43f 124 free(tp_probes);
f99be407
PMF
125 }
126}
127
128static void debug_print_probes(struct tracepoint_entry *entry)
129{
130 int i;
131
9dec086e 132 if (!tracepoint_debug || !entry->probes)
f99be407
PMF
133 return;
134
9dec086e
NC
135 for (i = 0; entry->probes[i].func; i++)
136 DBG("Probe %d : %p", i, entry->probes[i].func);
f99be407
PMF
137}
138
139static void *
9dec086e 140tracepoint_entry_add_probe(struct tracepoint_entry *entry,
fbdeb5ec 141 void (*probe)(void), void *data)
f99be407
PMF
142{
143 int nr_probes = 0;
b979b346 144 struct tracepoint_probe *old, *new;
f99be407 145
d7509147
MD
146 if (!probe) {
147 WARN_ON(1);
148 return ERR_PTR(-EINVAL);
149 }
f99be407 150 debug_print_probes(entry);
9dec086e 151 old = entry->probes;
f99be407
PMF
152 if (old) {
153 /* (N -> N+1), (N != 0, 1) probes */
9dec086e
NC
154 for (nr_probes = 0; old[nr_probes].func; nr_probes++)
155 if (old[nr_probes].func == probe &&
156 old[nr_probes].data == data)
f99be407
PMF
157 return ERR_PTR(-EEXIST);
158 }
159 /* + 2 : one for new probe, one for NULL func */
160 new = allocate_probes(nr_probes + 2);
161 if (new == NULL)
162 return ERR_PTR(-ENOMEM);
163 if (old)
b979b346 164 memcpy(new, old, nr_probes * sizeof(struct tracepoint_probe));
9dec086e
NC
165 new[nr_probes].func = probe;
166 new[nr_probes].data = data;
167 new[nr_probes + 1].func = NULL;
f99be407 168 entry->refcount = nr_probes + 1;
9dec086e 169 entry->probes = new;
f99be407
PMF
170 debug_print_probes(entry);
171 return old;
172}
173
174static void *
fbdeb5ec
MD
175tracepoint_entry_remove_probe(struct tracepoint_entry *entry,
176 void (*probe)(void), void *data)
f99be407
PMF
177{
178 int nr_probes = 0, nr_del = 0, i;
b979b346 179 struct tracepoint_probe *old, *new;
f99be407 180
9dec086e 181 old = entry->probes;
f99be407
PMF
182
183 if (!old)
184 return ERR_PTR(-ENOENT);
185
186 debug_print_probes(entry);
187 /* (N -> M), (N > 1, M >= 0) probes */
956c6fab
MD
188 if (probe) {
189 for (nr_probes = 0; old[nr_probes].func; nr_probes++) {
190 if (old[nr_probes].func == probe &&
191 old[nr_probes].data == data)
192 nr_del++;
193 }
194 } else {
195 nr_del = nr_probes;
f99be407
PMF
196 }
197
198 if (nr_probes - nr_del == 0) {
199 /* N -> 0, (N > 1) */
9dec086e 200 entry->probes = NULL;
f99be407
PMF
201 entry->refcount = 0;
202 debug_print_probes(entry);
203 return old;
204 } else {
205 int j = 0;
206 /* N -> M, (N > 1, M > 0) */
207 /* + 1 for NULL */
208 new = allocate_probes(nr_probes - nr_del + 1);
209 if (new == NULL)
210 return ERR_PTR(-ENOMEM);
9dec086e 211 for (i = 0; old[i].func; i++)
956c6fab 212 if (old[i].func != probe || old[i].data != data)
f99be407 213 new[j++] = old[i];
9dec086e 214 new[nr_probes - nr_del].func = NULL;
f99be407 215 entry->refcount = nr_probes - nr_del;
9dec086e 216 entry->probes = new;
f99be407
PMF
217 }
218 debug_print_probes(entry);
219 return old;
220}
221
222/*
223 * Get tracepoint if the tracepoint is present in the tracepoint hash table.
8792fbae 224 * Must be called with tracepoint mutex held.
f99be407
PMF
225 * Returns NULL if not present.
226 */
227static struct tracepoint_entry *get_tracepoint(const char *name)
228{
10c56168
DG
229 struct cds_hlist_head *head;
230 struct cds_hlist_node *node;
f99be407 231 struct tracepoint_entry *e;
ff412fb5
MD
232 size_t name_len = strlen(name);
233 uint32_t hash;
f99be407 234
ff412fb5
MD
235 if (name_len > LTTNG_UST_SYM_NAME_LEN - 1) {
236 WARN("Truncating tracepoint name %s which exceeds size limits of %u chars", name, LTTNG_UST_SYM_NAME_LEN - 1);
237 name_len = LTTNG_UST_SYM_NAME_LEN - 1;
238 }
239 hash = jhash(name, name_len, 0);
f99be407 240 head = &tracepoint_table[hash & (TRACEPOINT_TABLE_SIZE - 1)];
10c56168 241 cds_hlist_for_each_entry(e, node, head, hlist) {
ff412fb5 242 if (!strncmp(name, e->name, LTTNG_UST_SYM_NAME_LEN - 1))
f99be407
PMF
243 return e;
244 }
245 return NULL;
246}
247
248/*
249 * Add the tracepoint to the tracepoint hash table. Must be called with
8792fbae 250 * tracepoint mutex held.
f99be407 251 */
67e5f391
MD
252static struct tracepoint_entry *add_tracepoint(const char *name,
253 const char *signature)
f99be407 254{
10c56168
DG
255 struct cds_hlist_head *head;
256 struct cds_hlist_node *node;
f99be407 257 struct tracepoint_entry *e;
ff412fb5
MD
258 size_t name_len = strlen(name);
259 uint32_t hash;
f99be407 260
ff412fb5
MD
261 if (name_len > LTTNG_UST_SYM_NAME_LEN - 1) {
262 WARN("Truncating tracepoint name %s which exceeds size limits of %u chars", name, LTTNG_UST_SYM_NAME_LEN - 1);
263 name_len = LTTNG_UST_SYM_NAME_LEN - 1;
264 }
265 hash = jhash(name, name_len, 0);
f99be407 266 head = &tracepoint_table[hash & (TRACEPOINT_TABLE_SIZE - 1)];
10c56168 267 cds_hlist_for_each_entry(e, node, head, hlist) {
ff412fb5 268 if (!strncmp(name, e->name, LTTNG_UST_SYM_NAME_LEN - 1)) {
c1f20530 269 DBG("tracepoint %s busy", name);
f99be407
PMF
270 return ERR_PTR(-EEXIST); /* Already there */
271 }
272 }
273 /*
1dba3e6c 274 * Using zmalloc here to allocate a variable length element. Could
f99be407
PMF
275 * cause some memory fragmentation if overused.
276 */
ff412fb5 277 e = zmalloc(sizeof(struct tracepoint_entry) + name_len + 1);
f99be407
PMF
278 if (!e)
279 return ERR_PTR(-ENOMEM);
ff412fb5
MD
280 memcpy(&e->name[0], name, name_len + 1);
281 e->name[name_len] = '\0';
9dec086e 282 e->probes = NULL;
f99be407 283 e->refcount = 0;
67e5f391 284 e->signature = signature;
10c56168 285 cds_hlist_add_head(&e->hlist, head);
f99be407
PMF
286 return e;
287}
288
289/*
290 * Remove the tracepoint from the tracepoint hash table. Must be called with
8792fbae 291 * tracepoint mutex held.
f99be407 292 */
efa2c591 293static void remove_tracepoint(struct tracepoint_entry *e)
f99be407 294{
10c56168 295 cds_hlist_del(&e->hlist);
909bc43f 296 free(e);
f99be407
PMF
297}
298
299/*
300 * Sets the probe callback corresponding to one tracepoint.
301 */
302static void set_tracepoint(struct tracepoint_entry **entry,
303 struct tracepoint *elem, int active)
304{
ff412fb5 305 WARN_ON(strncmp((*entry)->name, elem->name, LTTNG_UST_SYM_NAME_LEN - 1) != 0);
67e5f391
MD
306 /*
307 * Check that signatures match before connecting a probe to a
308 * tracepoint. Warn the user if they don't.
309 */
310 if (strcmp(elem->signature, (*entry)->signature) != 0) {
311 static int warned = 0;
312
313 /* Only print once, don't flood console. */
314 if (!warned) {
315 WARN("Tracepoint signature mismatch, not enabling one or more tracepoints. Ensure that the tracepoint probes prototypes match the application.");
316 WARN("Tracepoint \"%s\" signatures: call: \"%s\" vs probe: \"%s\".",
317 elem->name, elem->signature, (*entry)->signature);
318 warned = 1;
319 }
320 /* Don't accept connecting non-matching signatures. */
321 return;
322 }
f99be407
PMF
323
324 /*
0222e121 325 * rcu_assign_pointer has a cmm_smp_wmb() which makes sure that the new
f99be407
PMF
326 * probe callbacks array is consistent before setting a pointer to it.
327 * This array is referenced by __DO_TRACE from
0222e121 328 * include/linux/tracepoints.h. A matching cmm_smp_read_barrier_depends()
f99be407
PMF
329 * is used.
330 */
9dec086e 331 rcu_assign_pointer(elem->probes, (*entry)->probes);
f36c12ab 332 elem->state = active;
f99be407
PMF
333}
334
335/*
336 * Disable a tracepoint and its probe callback.
337 * Note: only waiting an RCU period after setting elem->call to the empty
338 * function insures that the original callback is not used anymore. This insured
339 * by preempt_disable around the call site.
340 */
341static void disable_tracepoint(struct tracepoint *elem)
342{
f36c12ab 343 elem->state = 0;
9dec086e 344 rcu_assign_pointer(elem->probes, NULL);
f99be407
PMF
345}
346
347/**
348 * tracepoint_update_probe_range - Update a probe range
349 * @begin: beginning of the range
350 * @end: end of the range
351 *
352 * Updates the probe callback corresponding to a range of tracepoints.
353 */
b27f8e75 354static
f218ff28
MD
355void tracepoint_update_probe_range(struct tracepoint * const *begin,
356 struct tracepoint * const *end)
f99be407 357{
f218ff28 358 struct tracepoint * const *iter;
f99be407
PMF
359 struct tracepoint_entry *mark_entry;
360
f99be407 361 for (iter = begin; iter < end; iter++) {
f08ebbe2
MD
362 if (!*iter)
363 continue; /* skip dummy */
f218ff28
MD
364 if (!(*iter)->name) {
365 disable_tracepoint(*iter);
9dec086e
NC
366 continue;
367 }
f218ff28 368 mark_entry = get_tracepoint((*iter)->name);
f99be407 369 if (mark_entry) {
f218ff28 370 set_tracepoint(&mark_entry, *iter,
f99be407
PMF
371 !!mark_entry->refcount);
372 } else {
f218ff28 373 disable_tracepoint(*iter);
f99be407
PMF
374 }
375 }
f99be407
PMF
376}
377
772030fe
PMF
378static void lib_update_tracepoints(void)
379{
380 struct tracepoint_lib *lib;
381
b27f8e75 382 cds_list_for_each_entry(lib, &libs, list) {
772030fe
PMF
383 tracepoint_update_probe_range(lib->tracepoints_start,
384 lib->tracepoints_start + lib->tracepoints_count);
b27f8e75 385 }
772030fe
PMF
386}
387
f99be407
PMF
388/*
389 * Update probes, removing the faulty probes.
390 */
391static void tracepoint_update_probes(void)
392{
b27f8e75 393 /* tracepoints registered from libraries and executable. */
474d745f 394 lib_update_tracepoints();
f99be407
PMF
395}
396
b979b346 397static struct tracepoint_probe *
fbdeb5ec 398tracepoint_add_probe(const char *name, void (*probe)(void), void *data,
67e5f391 399 const char *signature)
f99be407
PMF
400{
401 struct tracepoint_entry *entry;
b979b346 402 struct tracepoint_probe *old;
f99be407
PMF
403
404 entry = get_tracepoint(name);
405 if (!entry) {
67e5f391 406 entry = add_tracepoint(name, signature);
f99be407 407 if (IS_ERR(entry))
b979b346 408 return (struct tracepoint_probe *)entry;
f99be407 409 }
9dec086e 410 old = tracepoint_entry_add_probe(entry, probe, data);
f99be407
PMF
411 if (IS_ERR(old) && !entry->refcount)
412 remove_tracepoint(entry);
413 return old;
414}
415
416/**
81614639 417 * __tracepoint_probe_register - Connect a probe to a tracepoint
f99be407
PMF
418 * @name: tracepoint name
419 * @probe: probe handler
420 *
421 * Returns 0 if ok, error value on error.
422 * The probe address must at least be aligned on the architecture pointer size.
8792fbae 423 * Called with the tracepoint mutex held.
f99be407 424 */
fbdeb5ec
MD
425int __tracepoint_probe_register(const char *name, void (*probe)(void),
426 void *data, const char *signature)
f99be407
PMF
427{
428 void *old;
8792fbae 429 int ret = 0;
f99be407 430
05780d81
MD
431 DBG("Registering probe to tracepoint %s", name);
432
8792fbae 433 pthread_mutex_lock(&tracepoint_mutex);
67e5f391 434 old = tracepoint_add_probe(name, probe, data, signature);
8792fbae
MD
435 if (IS_ERR(old)) {
436 ret = PTR_ERR(old);
437 goto end;
438 }
f99be407
PMF
439
440 tracepoint_update_probes(); /* may update entry */
441 release_probes(old);
8792fbae
MD
442end:
443 pthread_mutex_unlock(&tracepoint_mutex);
444 return ret;
f99be407 445}
f99be407 446
fbdeb5ec
MD
447static void *tracepoint_remove_probe(const char *name, void (*probe)(void),
448 void *data)
f99be407
PMF
449{
450 struct tracepoint_entry *entry;
451 void *old;
452
453 entry = get_tracepoint(name);
454 if (!entry)
455 return ERR_PTR(-ENOENT);
9dec086e 456 old = tracepoint_entry_remove_probe(entry, probe, data);
f99be407
PMF
457 if (IS_ERR(old))
458 return old;
459 if (!entry->refcount)
460 remove_tracepoint(entry);
461 return old;
462}
463
464/**
465 * tracepoint_probe_unregister - Disconnect a probe from a tracepoint
466 * @name: tracepoint name
467 * @probe: probe function pointer
9dec086e 468 * @probe: probe data pointer
f99be407 469 */
fbdeb5ec
MD
470int __tracepoint_probe_unregister(const char *name, void (*probe)(void),
471 void *data)
f99be407
PMF
472{
473 void *old;
8792fbae 474 int ret = 0;
f99be407 475
05780d81
MD
476 DBG("Un-registering probe from tracepoint %s", name);
477
8792fbae 478 pthread_mutex_lock(&tracepoint_mutex);
9dec086e 479 old = tracepoint_remove_probe(name, probe, data);
8792fbae
MD
480 if (IS_ERR(old)) {
481 ret = PTR_ERR(old);
482 goto end;
483 }
f99be407
PMF
484 tracepoint_update_probes(); /* may update entry */
485 release_probes(old);
8792fbae
MD
486end:
487 pthread_mutex_unlock(&tracepoint_mutex);
488 return ret;
f99be407 489}
f99be407 490
f99be407
PMF
491static void tracepoint_add_old_probes(void *old)
492{
493 need_update = 1;
494 if (old) {
b728d87e 495 struct tp_probes *tp_probes = caa_container_of(old,
f99be407 496 struct tp_probes, probes[0]);
0222e121 497 cds_list_add(&tp_probes->u.list, &old_probes);
f99be407
PMF
498 }
499}
500
501/**
502 * tracepoint_probe_register_noupdate - register a probe but not connect
503 * @name: tracepoint name
504 * @probe: probe handler
505 *
506 * caller must call tracepoint_probe_update_all()
507 */
fbdeb5ec 508int tracepoint_probe_register_noupdate(const char *name, void (*probe)(void),
67e5f391 509 void *data, const char *signature)
f99be407
PMF
510{
511 void *old;
8792fbae 512 int ret = 0;
f99be407 513
8792fbae 514 pthread_mutex_lock(&tracepoint_mutex);
67e5f391 515 old = tracepoint_add_probe(name, probe, data, signature);
f99be407 516 if (IS_ERR(old)) {
8792fbae
MD
517 ret = PTR_ERR(old);
518 goto end;
f99be407
PMF
519 }
520 tracepoint_add_old_probes(old);
8792fbae
MD
521end:
522 pthread_mutex_unlock(&tracepoint_mutex);
523 return ret;
f99be407 524}
f99be407
PMF
525
526/**
527 * tracepoint_probe_unregister_noupdate - remove a probe but not disconnect
528 * @name: tracepoint name
529 * @probe: probe function pointer
530 *
531 * caller must call tracepoint_probe_update_all()
8792fbae 532 * Called with the tracepoint mutex held.
f99be407 533 */
fbdeb5ec 534int tracepoint_probe_unregister_noupdate(const char *name, void (*probe)(void),
9dec086e 535 void *data)
f99be407
PMF
536{
537 void *old;
8792fbae 538 int ret = 0;
f99be407 539
05780d81
MD
540 DBG("Un-registering probe from tracepoint %s", name);
541
8792fbae 542 pthread_mutex_lock(&tracepoint_mutex);
9dec086e 543 old = tracepoint_remove_probe(name, probe, data);
f99be407 544 if (IS_ERR(old)) {
8792fbae
MD
545 ret = PTR_ERR(old);
546 goto end;
f99be407
PMF
547 }
548 tracepoint_add_old_probes(old);
8792fbae
MD
549end:
550 pthread_mutex_unlock(&tracepoint_mutex);
551 return ret;
f99be407 552}
f99be407
PMF
553
554/**
555 * tracepoint_probe_update_all - update tracepoints
556 */
557void tracepoint_probe_update_all(void)
558{
0222e121 559 CDS_LIST_HEAD(release_probes);
f99be407
PMF
560 struct tp_probes *pos, *next;
561
8792fbae 562 pthread_mutex_lock(&tracepoint_mutex);
f99be407 563 if (!need_update) {
8792fbae 564 goto end;
f99be407 565 }
0222e121
MD
566 if (!cds_list_empty(&old_probes))
567 cds_list_replace_init(&old_probes, &release_probes);
f99be407 568 need_update = 0;
f99be407
PMF
569
570 tracepoint_update_probes();
0222e121
MD
571 cds_list_for_each_entry_safe(pos, next, &release_probes, u.list) {
572 cds_list_del(&pos->u.list);
474d745f 573 synchronize_rcu();
909bc43f 574 free(pos);
f99be407 575 }
8792fbae
MD
576end:
577 pthread_mutex_unlock(&tracepoint_mutex);
f99be407 578}
f99be407 579
474d745f
PMF
580void tracepoint_set_new_tracepoint_cb(void (*cb)(struct tracepoint *))
581{
582 new_tracepoint_cb = cb;
583}
f99be407 584
f218ff28 585static void new_tracepoints(struct tracepoint * const *start, struct tracepoint * const *end)
f99be407 586{
f218ff28
MD
587 if (new_tracepoint_cb) {
588 struct tracepoint * const *t;
f08ebbe2 589
b27f8e75 590 for (t = start; t < end; t++) {
f08ebbe2
MD
591 if (*t)
592 new_tracepoint_cb(*t);
474d745f
PMF
593 }
594 }
f99be407 595}
f99be407 596
1622ba22
MD
597static
598void lib_disable_tracepoints(struct tracepoint * const *begin,
599 struct tracepoint * const *end)
600{
601 struct tracepoint * const *iter;
602
603 for (iter = begin; iter < end; iter++) {
604 if (!*iter)
605 continue; /* skip dummy */
606 disable_tracepoint(*iter);
607 }
608
609}
610
b27f8e75
MD
611int tracepoint_register_lib(struct tracepoint * const *tracepoints_start,
612 int tracepoints_count)
474d745f 613{
b467f7a7 614 struct tracepoint_lib *pl, *iter;
474d745f 615
edaa1431
MD
616 init_tracepoint();
617
1dba3e6c 618 pl = (struct tracepoint_lib *) zmalloc(sizeof(struct tracepoint_lib));
474d745f
PMF
619
620 pl->tracepoints_start = tracepoints_start;
621 pl->tracepoints_count = tracepoints_count;
622
8792fbae 623 pthread_mutex_lock(&tracepoint_mutex);
b467f7a7
MD
624 /*
625 * We sort the libs by struct lib pointer address.
626 */
627 cds_list_for_each_entry_reverse(iter, &libs, list) {
628 BUG_ON(iter == pl); /* Should never be in the list twice */
629 if (iter < pl) {
630 /* We belong to the location right after iter. */
631 cds_list_add(&pl->list, &iter->list);
632 goto lib_added;
633 }
634 }
635 /* We should be added at the head of the list */
0222e121 636 cds_list_add(&pl->list, &libs);
b467f7a7 637lib_added:
474d745f
PMF
638 new_tracepoints(tracepoints_start, tracepoints_start + tracepoints_count);
639
b27f8e75 640 /* TODO: update just the loaded lib */
474d745f 641 lib_update_tracepoints();
8792fbae 642 pthread_mutex_unlock(&tracepoint_mutex);
474d745f 643
1fcf7ad7
MD
644 DBG("just registered a tracepoints section from %p and having %d tracepoints",
645 tracepoints_start, tracepoints_count);
05780d81
MD
646 if (ust_debug()) {
647 int i;
648
649 for (i = 0; i < tracepoints_count; i++) {
650 DBG("registered tracepoint: %s", tracepoints_start[i]->name);
651 }
652 }
9dec086e 653
474d745f
PMF
654 return 0;
655}
656
f218ff28 657int tracepoint_unregister_lib(struct tracepoint * const *tracepoints_start)
474d745f 658{
24b6668c 659 struct tracepoint_lib *lib;
1622ba22 660 int tracepoints_count;
24b6668c 661
8792fbae 662 pthread_mutex_lock(&tracepoint_mutex);
0222e121 663 cds_list_for_each_entry(lib, &libs, list) {
f218ff28 664 if (lib->tracepoints_start == tracepoints_start) {
24b6668c 665 struct tracepoint_lib *lib2free = lib;
1622ba22 666
0222e121 667 cds_list_del(&lib->list);
1622ba22 668 tracepoints_count = lib->tracepoints_count;
24b6668c 669 free(lib2free);
1622ba22 670 goto found;
24b6668c
PMF
671 }
672 }
1622ba22
MD
673 goto end;
674found:
675 /*
676 * Force tracepoint disarm for all tracepoints of this lib.
677 * This takes care of destructor of library that would leave a
678 * LD_PRELOAD wrapper override function enabled for tracing, but
679 * the session teardown would not be able to reach the
680 * tracepoint anymore to disable it.
681 */
682 lib_disable_tracepoints(tracepoints_start,
683 tracepoints_start + tracepoints_count);
684 DBG("just unregistered a tracepoints section from %p",
685 tracepoints_start);
686end:
8792fbae 687 pthread_mutex_unlock(&tracepoint_mutex);
474d745f
PMF
688 return 0;
689}
b27f8e75 690
edaa1431 691void init_tracepoint(void)
b27f8e75 692{
edaa1431
MD
693 if (uatomic_xchg(&initialized, 1) == 1)
694 return;
5e96a467 695 init_usterr();
b27f8e75
MD
696}
697
edaa1431 698void exit_tracepoint(void)
b27f8e75 699{
17dfb34b 700 initialized = 0;
b27f8e75 701}
40b2b5a4
MD
702
703/*
704 * Create the wrapper symbols.
705 */
706#undef tp_rcu_read_lock_bp
707#undef tp_rcu_read_unlock_bp
708#undef tp_rcu_dereference_bp
709
710void tp_rcu_read_lock_bp(void)
711{
712 rcu_read_lock_bp();
713}
714
715void tp_rcu_read_unlock_bp(void)
716{
717 rcu_read_unlock_bp();
718}
719
720void *tp_rcu_dereference_sym_bp(void *p)
721{
722 return rcu_dereference_bp(p);
723}
This page took 0.079304 seconds and 4 git commands to generate.