~ubuntu-branches/ubuntu/wily/ust/wily-proposed

« back to all changes in this revision

Viewing changes to liblttng-ust/tracepoint.c

  • Committer: Package Import Robot
  • Author(s): Jon Bernard
  • Date: 2012-06-29 16:47:49 UTC
  • mto: (11.2.1 sid) (1.2.1)
  • mto: This revision was merged to the branch mainline in revision 19.
  • Revision ID: package-import@ubuntu.com-20120629164749-mcca8f7w9ovcktj2
Tags: upstream-2.0.4
ImportĀ upstreamĀ versionĀ 2.0.4

Show diffs side-by-side

added added

removed removed

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