Remove core.h
[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>
4318ae1b 24#include <lttng/tracepoint.h>
b728d87e
MD
25#include <stdint.h>
26#include <stddef.h>
27#include <urcu/arch.h>
b7ea1a1c 28#include <urcu-bp.h>
10c56168 29#include <urcu/hlist.h>
edaa1431 30#include <urcu/uatomic.h>
b728d87e 31#include <urcu/compiler.h>
35897f8b 32#include <helper.h>
474d745f 33
4318ae1b 34#include <lttng/usterr-signal-safe.h>
23c8854a 35#include "tracepoint-internal.h"
b751f722 36#include "ltt-tracer-core.h"
596c4223 37#include "jhash.h"
8f3f8c99 38#include "error.h"
b0c4126f 39
f99be407
PMF
40/* Set to 1 to enable tracepoint debug output */
41static const int tracepoint_debug;
b27f8e75
MD
42static int initialized;
43static void (*new_tracepoint_cb)(struct tracepoint *);
f99be407 44
474d745f 45/* libraries that contain tracepoints (struct tracepoint_lib) */
0222e121 46static CDS_LIST_HEAD(libs);
474d745f 47
f99be407 48/*
17dfb34b
MD
49 * The UST lock protects the library tracepoints, the hash table, and
50 * the library list.
51 * All calls to the tracepoint API must be protected by the UST lock,
52 * excepts calls to tracepoint_register_lib and
53 * tracepoint_unregister_lib, which take the UST lock themselves.
f99be407 54 */
f99be407
PMF
55
56/*
57 * Tracepoint hash table, containing the active tracepoints.
58 * Protected by tracepoints_mutex.
59 */
60#define TRACEPOINT_HASH_BITS 6
61#define TRACEPOINT_TABLE_SIZE (1 << TRACEPOINT_HASH_BITS)
10c56168 62static struct cds_hlist_head tracepoint_table[TRACEPOINT_TABLE_SIZE];
f99be407 63
b27f8e75
MD
64static CDS_LIST_HEAD(old_probes);
65static int need_update;
66
f99be407
PMF
67/*
68 * Note about RCU :
69 * It is used to to delay the free of multiple probes array until a quiescent
70 * state is reached.
71 * Tracepoint entries modifications are protected by the tracepoints_mutex.
72 */
73struct tracepoint_entry {
10c56168 74 struct cds_hlist_node hlist;
b979b346 75 struct tracepoint_probe *probes;
f99be407
PMF
76 int refcount; /* Number of times armed. 0 if disarmed. */
77 char name[0];
78};
79
80struct tp_probes {
81 union {
0222e121 82 struct cds_list_head list;
f99be407 83 } u;
b979b346 84 struct tracepoint_probe probes[0];
f99be407
PMF
85};
86
87static inline void *allocate_probes(int count)
88{
b979b346 89 struct tp_probes *p = zmalloc(count * sizeof(struct tracepoint_probe)
909bc43f 90 + sizeof(struct tp_probes));
f99be407
PMF
91 return p == NULL ? NULL : p->probes;
92}
93
f99be407
PMF
94static inline void release_probes(void *old)
95{
96 if (old) {
b728d87e 97 struct tp_probes *tp_probes = caa_container_of(old,
f99be407 98 struct tp_probes, probes[0]);
474d745f 99 synchronize_rcu();
909bc43f 100 free(tp_probes);
f99be407
PMF
101 }
102}
103
104static void debug_print_probes(struct tracepoint_entry *entry)
105{
106 int i;
107
9dec086e 108 if (!tracepoint_debug || !entry->probes)
f99be407
PMF
109 return;
110
9dec086e
NC
111 for (i = 0; entry->probes[i].func; i++)
112 DBG("Probe %d : %p", i, entry->probes[i].func);
f99be407
PMF
113}
114
115static void *
9dec086e
NC
116tracepoint_entry_add_probe(struct tracepoint_entry *entry,
117 void *probe, void *data)
f99be407
PMF
118{
119 int nr_probes = 0;
b979b346 120 struct tracepoint_probe *old, *new;
f99be407
PMF
121
122 WARN_ON(!probe);
123
124 debug_print_probes(entry);
9dec086e 125 old = entry->probes;
f99be407
PMF
126 if (old) {
127 /* (N -> N+1), (N != 0, 1) probes */
9dec086e
NC
128 for (nr_probes = 0; old[nr_probes].func; nr_probes++)
129 if (old[nr_probes].func == probe &&
130 old[nr_probes].data == data)
f99be407
PMF
131 return ERR_PTR(-EEXIST);
132 }
133 /* + 2 : one for new probe, one for NULL func */
134 new = allocate_probes(nr_probes + 2);
135 if (new == NULL)
136 return ERR_PTR(-ENOMEM);
137 if (old)
b979b346 138 memcpy(new, old, nr_probes * sizeof(struct tracepoint_probe));
9dec086e
NC
139 new[nr_probes].func = probe;
140 new[nr_probes].data = data;
141 new[nr_probes + 1].func = NULL;
f99be407 142 entry->refcount = nr_probes + 1;
9dec086e 143 entry->probes = new;
f99be407
PMF
144 debug_print_probes(entry);
145 return old;
146}
147
148static void *
9dec086e
NC
149tracepoint_entry_remove_probe(struct tracepoint_entry *entry, void *probe,
150 void *data)
f99be407
PMF
151{
152 int nr_probes = 0, nr_del = 0, i;
b979b346 153 struct tracepoint_probe *old, *new;
f99be407 154
9dec086e 155 old = entry->probes;
f99be407
PMF
156
157 if (!old)
158 return ERR_PTR(-ENOENT);
159
160 debug_print_probes(entry);
161 /* (N -> M), (N > 1, M >= 0) probes */
9dec086e 162 for (nr_probes = 0; old[nr_probes].func; nr_probes++) {
c66428ac
DG
163 if (!probe ||
164 (old[nr_probes].func == probe &&
9dec086e 165 old[nr_probes].data == data))
f99be407
PMF
166 nr_del++;
167 }
168
169 if (nr_probes - nr_del == 0) {
170 /* N -> 0, (N > 1) */
9dec086e 171 entry->probes = NULL;
f99be407
PMF
172 entry->refcount = 0;
173 debug_print_probes(entry);
174 return old;
175 } else {
176 int j = 0;
177 /* N -> M, (N > 1, M > 0) */
178 /* + 1 for NULL */
179 new = allocate_probes(nr_probes - nr_del + 1);
180 if (new == NULL)
181 return ERR_PTR(-ENOMEM);
9dec086e
NC
182 for (i = 0; old[i].func; i++)
183 if (probe &&
184 (old[i].func != probe || old[i].data != data))
f99be407 185 new[j++] = old[i];
9dec086e 186 new[nr_probes - nr_del].func = NULL;
f99be407 187 entry->refcount = nr_probes - nr_del;
9dec086e 188 entry->probes = new;
f99be407
PMF
189 }
190 debug_print_probes(entry);
191 return old;
192}
193
194/*
195 * Get tracepoint if the tracepoint is present in the tracepoint hash table.
196 * Must be called with tracepoints_mutex held.
197 * Returns NULL if not present.
198 */
199static struct tracepoint_entry *get_tracepoint(const char *name)
200{
10c56168
DG
201 struct cds_hlist_head *head;
202 struct cds_hlist_node *node;
f99be407 203 struct tracepoint_entry *e;
23c8854a 204 uint32_t hash = jhash(name, strlen(name), 0);
f99be407
PMF
205
206 head = &tracepoint_table[hash & (TRACEPOINT_TABLE_SIZE - 1)];
10c56168 207 cds_hlist_for_each_entry(e, node, head, hlist) {
f99be407
PMF
208 if (!strcmp(name, e->name))
209 return e;
210 }
211 return NULL;
212}
213
214/*
215 * Add the tracepoint to the tracepoint hash table. Must be called with
216 * tracepoints_mutex held.
217 */
218static struct tracepoint_entry *add_tracepoint(const char *name)
219{
10c56168
DG
220 struct cds_hlist_head *head;
221 struct cds_hlist_node *node;
f99be407
PMF
222 struct tracepoint_entry *e;
223 size_t name_len = strlen(name) + 1;
23c8854a 224 uint32_t hash = jhash(name, name_len-1, 0);
f99be407
PMF
225
226 head = &tracepoint_table[hash & (TRACEPOINT_TABLE_SIZE - 1)];
10c56168 227 cds_hlist_for_each_entry(e, node, head, hlist) {
f99be407 228 if (!strcmp(name, e->name)) {
c1f20530 229 DBG("tracepoint %s busy", name);
f99be407
PMF
230 return ERR_PTR(-EEXIST); /* Already there */
231 }
232 }
233 /*
1dba3e6c 234 * Using zmalloc here to allocate a variable length element. Could
f99be407
PMF
235 * cause some memory fragmentation if overused.
236 */
1dba3e6c 237 e = zmalloc(sizeof(struct tracepoint_entry) + name_len);
f99be407
PMF
238 if (!e)
239 return ERR_PTR(-ENOMEM);
240 memcpy(&e->name[0], name, name_len);
9dec086e 241 e->probes = NULL;
f99be407 242 e->refcount = 0;
10c56168 243 cds_hlist_add_head(&e->hlist, head);
f99be407
PMF
244 return e;
245}
246
247/*
248 * Remove the tracepoint from the tracepoint hash table. Must be called with
17dfb34b 249 * ust_lock held.
f99be407
PMF
250 */
251static inline void remove_tracepoint(struct tracepoint_entry *e)
252{
10c56168 253 cds_hlist_del(&e->hlist);
909bc43f 254 free(e);
f99be407
PMF
255}
256
257/*
258 * Sets the probe callback corresponding to one tracepoint.
259 */
260static void set_tracepoint(struct tracepoint_entry **entry,
261 struct tracepoint *elem, int active)
262{
263 WARN_ON(strcmp((*entry)->name, elem->name) != 0);
264
265 /*
0222e121 266 * rcu_assign_pointer has a cmm_smp_wmb() which makes sure that the new
f99be407
PMF
267 * probe callbacks array is consistent before setting a pointer to it.
268 * This array is referenced by __DO_TRACE from
0222e121 269 * include/linux/tracepoints.h. A matching cmm_smp_read_barrier_depends()
f99be407
PMF
270 * is used.
271 */
9dec086e 272 rcu_assign_pointer(elem->probes, (*entry)->probes);
f36c12ab 273 elem->state = active;
f99be407
PMF
274}
275
276/*
277 * Disable a tracepoint and its probe callback.
278 * Note: only waiting an RCU period after setting elem->call to the empty
279 * function insures that the original callback is not used anymore. This insured
280 * by preempt_disable around the call site.
281 */
282static void disable_tracepoint(struct tracepoint *elem)
283{
f36c12ab 284 elem->state = 0;
9dec086e 285 rcu_assign_pointer(elem->probes, NULL);
f99be407
PMF
286}
287
288/**
289 * tracepoint_update_probe_range - Update a probe range
290 * @begin: beginning of the range
291 * @end: end of the range
292 *
293 * Updates the probe callback corresponding to a range of tracepoints.
294 */
b27f8e75 295static
f218ff28
MD
296void tracepoint_update_probe_range(struct tracepoint * const *begin,
297 struct tracepoint * const *end)
f99be407 298{
f218ff28 299 struct tracepoint * const *iter;
f99be407
PMF
300 struct tracepoint_entry *mark_entry;
301
f99be407 302 for (iter = begin; iter < end; iter++) {
f08ebbe2
MD
303 if (!*iter)
304 continue; /* skip dummy */
f218ff28
MD
305 if (!(*iter)->name) {
306 disable_tracepoint(*iter);
9dec086e
NC
307 continue;
308 }
f218ff28 309 mark_entry = get_tracepoint((*iter)->name);
f99be407 310 if (mark_entry) {
f218ff28 311 set_tracepoint(&mark_entry, *iter,
f99be407
PMF
312 !!mark_entry->refcount);
313 } else {
f218ff28 314 disable_tracepoint(*iter);
f99be407
PMF
315 }
316 }
f99be407
PMF
317}
318
772030fe
PMF
319static void lib_update_tracepoints(void)
320{
321 struct tracepoint_lib *lib;
322
b27f8e75 323 cds_list_for_each_entry(lib, &libs, list) {
772030fe
PMF
324 tracepoint_update_probe_range(lib->tracepoints_start,
325 lib->tracepoints_start + lib->tracepoints_count);
b27f8e75 326 }
772030fe
PMF
327}
328
f99be407
PMF
329/*
330 * Update probes, removing the faulty probes.
331 */
332static void tracepoint_update_probes(void)
333{
b27f8e75 334 /* tracepoints registered from libraries and executable. */
474d745f 335 lib_update_tracepoints();
f99be407
PMF
336}
337
b979b346 338static struct tracepoint_probe *
9dec086e 339tracepoint_add_probe(const char *name, void *probe, void *data)
f99be407
PMF
340{
341 struct tracepoint_entry *entry;
b979b346 342 struct tracepoint_probe *old;
f99be407
PMF
343
344 entry = get_tracepoint(name);
345 if (!entry) {
346 entry = add_tracepoint(name);
347 if (IS_ERR(entry))
b979b346 348 return (struct tracepoint_probe *)entry;
f99be407 349 }
9dec086e 350 old = tracepoint_entry_add_probe(entry, probe, data);
f99be407
PMF
351 if (IS_ERR(old) && !entry->refcount)
352 remove_tracepoint(entry);
353 return old;
354}
355
356/**
81614639 357 * __tracepoint_probe_register - Connect a probe to a tracepoint
f99be407
PMF
358 * @name: tracepoint name
359 * @probe: probe handler
360 *
361 * Returns 0 if ok, error value on error.
362 * The probe address must at least be aligned on the architecture pointer size.
17dfb34b 363 * Called with the UST lock held.
f99be407 364 */
81614639 365int __tracepoint_probe_register(const char *name, void *probe, void *data)
f99be407
PMF
366{
367 void *old;
368
9dec086e 369 old = tracepoint_add_probe(name, probe, data);
f99be407
PMF
370 if (IS_ERR(old))
371 return PTR_ERR(old);
372
373 tracepoint_update_probes(); /* may update entry */
374 release_probes(old);
375 return 0;
376}
f99be407 377
9dec086e 378static void *tracepoint_remove_probe(const char *name, void *probe, void *data)
f99be407
PMF
379{
380 struct tracepoint_entry *entry;
381 void *old;
382
383 entry = get_tracepoint(name);
384 if (!entry)
385 return ERR_PTR(-ENOENT);
9dec086e 386 old = tracepoint_entry_remove_probe(entry, probe, data);
f99be407
PMF
387 if (IS_ERR(old))
388 return old;
389 if (!entry->refcount)
390 remove_tracepoint(entry);
391 return old;
392}
393
394/**
395 * tracepoint_probe_unregister - Disconnect a probe from a tracepoint
396 * @name: tracepoint name
397 * @probe: probe function pointer
9dec086e 398 * @probe: probe data pointer
f99be407 399 *
17dfb34b 400 * Called with the UST lock held.
f99be407 401 */
81614639 402int __tracepoint_probe_unregister(const char *name, void *probe, void *data)
f99be407
PMF
403{
404 void *old;
405
9dec086e 406 old = tracepoint_remove_probe(name, probe, data);
f99be407
PMF
407 if (IS_ERR(old))
408 return PTR_ERR(old);
409
410 tracepoint_update_probes(); /* may update entry */
411 release_probes(old);
412 return 0;
413}
f99be407 414
f99be407
PMF
415static void tracepoint_add_old_probes(void *old)
416{
417 need_update = 1;
418 if (old) {
b728d87e 419 struct tp_probes *tp_probes = caa_container_of(old,
f99be407 420 struct tp_probes, probes[0]);
0222e121 421 cds_list_add(&tp_probes->u.list, &old_probes);
f99be407
PMF
422 }
423}
424
425/**
426 * tracepoint_probe_register_noupdate - register a probe but not connect
427 * @name: tracepoint name
428 * @probe: probe handler
429 *
430 * caller must call tracepoint_probe_update_all()
17dfb34b 431 * Called with the UST lock held.
f99be407 432 */
9dec086e
NC
433int tracepoint_probe_register_noupdate(const char *name, void *probe,
434 void *data)
f99be407
PMF
435{
436 void *old;
437
9dec086e 438 old = tracepoint_add_probe(name, probe, data);
f99be407 439 if (IS_ERR(old)) {
f99be407
PMF
440 return PTR_ERR(old);
441 }
442 tracepoint_add_old_probes(old);
f99be407
PMF
443 return 0;
444}
f99be407
PMF
445
446/**
447 * tracepoint_probe_unregister_noupdate - remove a probe but not disconnect
448 * @name: tracepoint name
449 * @probe: probe function pointer
450 *
451 * caller must call tracepoint_probe_update_all()
17dfb34b 452 * Called with the UST lock held.
f99be407 453 */
9dec086e
NC
454int tracepoint_probe_unregister_noupdate(const char *name, void *probe,
455 void *data)
f99be407
PMF
456{
457 void *old;
458
9dec086e 459 old = tracepoint_remove_probe(name, probe, data);
f99be407 460 if (IS_ERR(old)) {
f99be407
PMF
461 return PTR_ERR(old);
462 }
463 tracepoint_add_old_probes(old);
f99be407
PMF
464 return 0;
465}
f99be407
PMF
466
467/**
468 * tracepoint_probe_update_all - update tracepoints
17dfb34b 469 * Called with the UST lock held.
f99be407
PMF
470 */
471void tracepoint_probe_update_all(void)
472{
0222e121 473 CDS_LIST_HEAD(release_probes);
f99be407
PMF
474 struct tp_probes *pos, *next;
475
f99be407 476 if (!need_update) {
f99be407
PMF
477 return;
478 }
0222e121
MD
479 if (!cds_list_empty(&old_probes))
480 cds_list_replace_init(&old_probes, &release_probes);
f99be407 481 need_update = 0;
f99be407
PMF
482
483 tracepoint_update_probes();
0222e121
MD
484 cds_list_for_each_entry_safe(pos, next, &release_probes, u.list) {
485 cds_list_del(&pos->u.list);
474d745f 486 synchronize_rcu();
909bc43f 487 free(pos);
f99be407
PMF
488 }
489}
f99be407 490
772030fe
PMF
491/*
492 * Returns 0 if current not found.
493 * Returns 1 if current found.
b27f8e75
MD
494 *
495 * Called with tracepoint mutex held
772030fe
PMF
496 */
497int lib_get_iter_tracepoints(struct tracepoint_iter *iter)
498{
499 struct tracepoint_lib *iter_lib;
500 int found = 0;
501
0222e121 502 cds_list_for_each_entry(iter_lib, &libs, list) {
772030fe
PMF
503 if (iter_lib < iter->lib)
504 continue;
505 else if (iter_lib > iter->lib)
506 iter->tracepoint = NULL;
507 found = tracepoint_get_iter_range(&iter->tracepoint,
508 iter_lib->tracepoints_start,
509 iter_lib->tracepoints_start + iter_lib->tracepoints_count);
510 if (found) {
511 iter->lib = iter_lib;
512 break;
513 }
514 }
772030fe
PMF
515 return found;
516}
517
f99be407
PMF
518/**
519 * tracepoint_get_iter_range - Get a next tracepoint iterator given a range.
520 * @tracepoint: current tracepoints (in), next tracepoint (out)
521 * @begin: beginning of the range
522 * @end: end of the range
523 *
524 * Returns whether a next tracepoint has been found (1) or not (0).
525 * Will return the first tracepoint in the range if the input tracepoint is
526 * NULL.
b27f8e75 527 * Called with tracepoint mutex held.
f99be407 528 */
f218ff28
MD
529int tracepoint_get_iter_range(struct tracepoint * const **tracepoint,
530 struct tracepoint * const *begin, struct tracepoint * const *end)
f99be407 531{
f08ebbe2 532 if (!*tracepoint && begin != end)
f99be407 533 *tracepoint = begin;
f08ebbe2
MD
534 while (*tracepoint >= begin && *tracepoint < end) {
535 if (!**tracepoint)
536 (*tracepoint)++; /* skip dummy */
537 else
538 return 1;
f99be407 539 }
f99be407
PMF
540 return 0;
541}
f99be407 542
b27f8e75
MD
543/*
544 * Called with tracepoint mutex held.
545 */
f99be407
PMF
546static void tracepoint_get_iter(struct tracepoint_iter *iter)
547{
548 int found = 0;
549
474d745f
PMF
550 /* tracepoints in libs. */
551 found = lib_get_iter_tracepoints(iter);
f99be407
PMF
552 if (!found)
553 tracepoint_iter_reset(iter);
554}
555
17dfb34b
MD
556/*
557 * Called with UST lock held.
558 */
f99be407
PMF
559void tracepoint_iter_start(struct tracepoint_iter *iter)
560{
561 tracepoint_get_iter(iter);
562}
f99be407 563
b27f8e75 564/*
17dfb34b 565 * Called with UST lock held.
b27f8e75 566 */
f99be407
PMF
567void tracepoint_iter_next(struct tracepoint_iter *iter)
568{
569 iter->tracepoint++;
570 /*
571 * iter->tracepoint may be invalid because we blindly incremented it.
572 * Make sure it is valid by marshalling on the tracepoints, getting the
573 * tracepoints from following modules if necessary.
574 */
575 tracepoint_get_iter(iter);
576}
f99be407 577
17dfb34b
MD
578/*
579 * Called with UST lock held.
580 */
f99be407
PMF
581void tracepoint_iter_stop(struct tracepoint_iter *iter)
582{
583}
f99be407
PMF
584
585void tracepoint_iter_reset(struct tracepoint_iter *iter)
586{
f99be407
PMF
587 iter->tracepoint = NULL;
588}
474d745f
PMF
589
590void tracepoint_set_new_tracepoint_cb(void (*cb)(struct tracepoint *))
591{
592 new_tracepoint_cb = cb;
593}
f99be407 594
f218ff28 595static void new_tracepoints(struct tracepoint * const *start, struct tracepoint * const *end)
f99be407 596{
f218ff28
MD
597 if (new_tracepoint_cb) {
598 struct tracepoint * const *t;
f08ebbe2 599
b27f8e75 600 for (t = start; t < end; t++) {
f08ebbe2
MD
601 if (*t)
602 new_tracepoint_cb(*t);
474d745f
PMF
603 }
604 }
f99be407 605}
f99be407 606
b27f8e75
MD
607int tracepoint_register_lib(struct tracepoint * const *tracepoints_start,
608 int tracepoints_count)
474d745f 609{
b467f7a7 610 struct tracepoint_lib *pl, *iter;
474d745f 611
edaa1431
MD
612 init_tracepoint();
613
1dba3e6c 614 pl = (struct tracepoint_lib *) zmalloc(sizeof(struct tracepoint_lib));
474d745f
PMF
615
616 pl->tracepoints_start = tracepoints_start;
617 pl->tracepoints_count = tracepoints_count;
618
17dfb34b 619 ust_lock();
b467f7a7
MD
620 /*
621 * We sort the libs by struct lib pointer address.
622 */
623 cds_list_for_each_entry_reverse(iter, &libs, list) {
624 BUG_ON(iter == pl); /* Should never be in the list twice */
625 if (iter < pl) {
626 /* We belong to the location right after iter. */
627 cds_list_add(&pl->list, &iter->list);
628 goto lib_added;
629 }
630 }
631 /* We should be added at the head of the list */
0222e121 632 cds_list_add(&pl->list, &libs);
b467f7a7 633lib_added:
474d745f
PMF
634 new_tracepoints(tracepoints_start, tracepoints_start + tracepoints_count);
635
b27f8e75 636 /* TODO: update just the loaded lib */
474d745f 637 lib_update_tracepoints();
17dfb34b 638 ust_unlock();
474d745f 639
1fcf7ad7
MD
640 DBG("just registered a tracepoints section from %p and having %d tracepoints",
641 tracepoints_start, tracepoints_count);
9dec086e 642
474d745f
PMF
643 return 0;
644}
645
f218ff28 646int tracepoint_unregister_lib(struct tracepoint * const *tracepoints_start)
474d745f 647{
24b6668c
PMF
648 struct tracepoint_lib *lib;
649
17dfb34b 650 ust_lock();
0222e121 651 cds_list_for_each_entry(lib, &libs, list) {
f218ff28 652 if (lib->tracepoints_start == tracepoints_start) {
24b6668c 653 struct tracepoint_lib *lib2free = lib;
0222e121 654 cds_list_del(&lib->list);
24b6668c
PMF
655 free(lib2free);
656 break;
657 }
658 }
17dfb34b 659 ust_unlock();
474d745f
PMF
660
661 return 0;
662}
b27f8e75 663
edaa1431 664void init_tracepoint(void)
b27f8e75 665{
edaa1431
MD
666 if (uatomic_xchg(&initialized, 1) == 1)
667 return;
5e96a467 668 init_usterr();
b27f8e75
MD
669}
670
edaa1431 671void exit_tracepoint(void)
b27f8e75 672{
17dfb34b 673 initialized = 0;
b27f8e75 674}
This page took 0.061717 seconds and 4 git commands to generate.