Use iterator on tracepoint probes instead of tracepoints per se
[lttng-ust.git] / liblttng-ust / ltt-probes.c
1 /*
2 * ltt-probes.c
3 *
4 * Copyright 2010 (c) - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
5 *
6 * Holds LTTng probes registry.
7 *
8 * Dual LGPL v2.1/GPL v2 license.
9 */
10
11 #include <string.h>
12 #include <errno.h>
13 #include <urcu/list.h>
14 #include <lttng/ust-events.h>
15 #include <assert.h>
16 #include <helper.h>
17
18 #include "ltt-tracer-core.h"
19
20 /*
21 * probe list is protected by ust_lock()/ust_unlock().
22 */
23 static CDS_LIST_HEAD(probe_list);
24
25 static
26 const struct lttng_probe_desc *find_provider(const char *provider)
27 {
28 struct lttng_probe_desc *iter;
29
30 cds_list_for_each_entry(iter, &probe_list, head) {
31 if (!strcmp(iter->provider, provider))
32 return iter;
33 }
34 return NULL;
35 }
36
37 static
38 const struct lttng_event_desc *find_event(const char *name)
39 {
40 struct lttng_probe_desc *probe_desc;
41 int i;
42
43 cds_list_for_each_entry(probe_desc, &probe_list, head) {
44 for (i = 0; i < probe_desc->nr_events; i++) {
45 if (!strcmp(probe_desc->event_desc[i]->name, name))
46 return probe_desc->event_desc[i];
47 }
48 }
49 return NULL;
50 }
51
52 int ltt_probe_register(struct lttng_probe_desc *desc)
53 {
54 struct lttng_probe_desc *iter;
55 int ret = 0;
56 int i;
57
58 ust_lock();
59 if (find_provider(desc->provider)) {
60 ret = -EEXIST;
61 goto end;
62 }
63 /*
64 * TODO: This is O(N^2). Turn into a hash table when probe registration
65 * overhead becomes an issue.
66 */
67 for (i = 0; i < desc->nr_events; i++) {
68 if (find_event(desc->event_desc[i]->name)) {
69 ret = -EEXIST;
70 goto end;
71 }
72 }
73
74 /*
75 * We sort the providers by struct lttng_probe_desc pointer
76 * address.
77 */
78 cds_list_for_each_entry_reverse(iter, &probe_list, head) {
79 BUG_ON(iter == desc); /* Should never be in the list twice */
80 if (iter < desc) {
81 /* We belong to the location right after iter. */
82 cds_list_add(&desc->head, &iter->head);
83 goto desc_added;
84 }
85 }
86 /* We should be added at the head of the list */
87 cds_list_add(&desc->head, &probe_list);
88 desc_added:
89
90 /*
91 * fix the events awaiting probe load.
92 */
93 for (i = 0; i < desc->nr_events; i++) {
94 ret = pending_probe_fix_events(desc->event_desc[i]);
95 assert(!ret);
96 }
97 end:
98 ust_unlock();
99 return ret;
100 }
101
102 void ltt_probe_unregister(struct lttng_probe_desc *desc)
103 {
104 ust_lock();
105 cds_list_del(&desc->head);
106 ust_unlock();
107 }
108
109 /*
110 * called with UST lock held.
111 */
112 const struct lttng_event_desc *ltt_event_get(const char *name)
113 {
114 const struct lttng_event_desc *event;
115
116 event = find_event(name);
117 if (!event)
118 return NULL;
119 return event;
120 }
121
122 void ltt_event_put(const struct lttng_event_desc *event)
123 {
124 }
125
126 void ltt_probes_prune_event_list(struct lttng_ust_tracepoint_list *list)
127 {
128 struct tp_list_entry *list_entry, *tmp;
129
130 cds_list_for_each_entry_safe(list_entry, tmp, &list->head, head) {
131 cds_list_del(&list_entry->head);
132 free(list_entry);
133 }
134 }
135
136 /*
137 * called with UST lock held.
138 */
139 int ltt_probes_get_event_list(struct lttng_ust_tracepoint_list *list)
140 {
141 struct lttng_probe_desc *probe_desc;
142 int i;
143
144 CDS_INIT_LIST_HEAD(&list->head);
145 cds_list_for_each_entry(probe_desc, &probe_list, head) {
146 for (i = 0; i < probe_desc->nr_events; i++) {
147 struct tp_list_entry *list_entry;
148
149 list_entry = zmalloc(sizeof(*list_entry));
150 if (!list_entry)
151 goto err_nomem;
152 cds_list_add(&list_entry->head, &list->head);
153 strncpy(list_entry->tp.name,
154 probe_desc->event_desc[i]->name,
155 LTTNG_UST_SYM_NAME_LEN);
156 list_entry->tp.name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
157 if (!probe_desc->event_desc[i]->loglevel) {
158 list_entry->tp.loglevel[0] = '\0';
159 list_entry->tp.loglevel_value = 0;
160 } else {
161 strncpy(list_entry->tp.loglevel,
162 (*probe_desc->event_desc[i]->loglevel)->identifier,
163 LTTNG_UST_SYM_NAME_LEN);
164 list_entry->tp.loglevel[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
165 list_entry->tp.loglevel_value =
166 (*probe_desc->event_desc[i]->loglevel)->value;
167 }
168 }
169 }
170 if (cds_list_empty(&list->head))
171 list->iter = NULL;
172 else
173 list->iter =
174 cds_list_first_entry(&list->head, struct tp_list_entry, head);
175 return 0;
176
177 err_nomem:
178 ltt_probes_prune_event_list(list);
179 return -ENOMEM;
180 }
181
182 /*
183 * Return current iteration position, advance internal iterator to next.
184 * Return NULL if end of list.
185 */
186 struct lttng_ust_tracepoint_iter *
187 lttng_ust_tracepoint_list_get_iter_next(struct lttng_ust_tracepoint_list *list)
188 {
189 struct tp_list_entry *entry;
190
191 if (!list->iter)
192 return NULL;
193 entry = list->iter;
194 if (entry->head.next == &list->head)
195 list->iter = NULL;
196 else
197 list->iter = cds_list_entry(entry->head.next,
198 struct tp_list_entry, head);
199 return &entry->tp;
200 }
This page took 0.037206 seconds and 4 git commands to generate.