Commit | Line | Data |
---|---|---|
ce5aef0b MD |
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 | ||
8d8a24c8 MD |
11 | #include <string.h> |
12 | #include <errno.h> | |
13 | #include <urcu/list.h> | |
4318ae1b | 14 | #include <lttng/ust-events.h> |
a3bb4b27 | 15 | #include <assert.h> |
c8fcf224 | 16 | #include <helper.h> |
ce5aef0b | 17 | |
8165c8da MD |
18 | #include "ltt-tracer-core.h" |
19 | ||
20 | /* | |
17dfb34b | 21 | * probe list is protected by ust_lock()/ust_unlock(). |
8165c8da | 22 | */ |
8d8a24c8 | 23 | static CDS_LIST_HEAD(probe_list); |
ce5aef0b | 24 | |
df854e41 MD |
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 | ||
ce5aef0b MD |
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 | ||
8d8a24c8 | 43 | cds_list_for_each_entry(probe_desc, &probe_list, head) { |
ce5aef0b | 44 | for (i = 0; i < probe_desc->nr_events; i++) { |
df854e41 MD |
45 | if (!strcmp(probe_desc->event_desc[i]->name, name)) |
46 | return probe_desc->event_desc[i]; | |
ce5aef0b MD |
47 | } |
48 | } | |
49 | return NULL; | |
50 | } | |
51 | ||
52 | int ltt_probe_register(struct lttng_probe_desc *desc) | |
53 | { | |
df854e41 | 54 | struct lttng_probe_desc *iter; |
ce5aef0b MD |
55 | int ret = 0; |
56 | int i; | |
57 | ||
17dfb34b | 58 | ust_lock(); |
df854e41 MD |
59 | if (find_provider(desc->provider)) { |
60 | ret = -EEXIST; | |
61 | goto end; | |
62 | } | |
ce5aef0b MD |
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++) { | |
df854e41 | 68 | if (find_event(desc->event_desc[i]->name)) { |
ce5aef0b MD |
69 | ret = -EEXIST; |
70 | goto end; | |
71 | } | |
72 | } | |
df854e41 MD |
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 */ | |
8d8a24c8 | 87 | cds_list_add(&desc->head, &probe_list); |
df854e41 | 88 | desc_added: |
8165c8da MD |
89 | |
90 | /* | |
91 | * fix the events awaiting probe load. | |
92 | */ | |
93 | for (i = 0; i < desc->nr_events; i++) { | |
df854e41 | 94 | ret = pending_probe_fix_events(desc->event_desc[i]); |
8165c8da MD |
95 | assert(!ret); |
96 | } | |
ce5aef0b | 97 | end: |
17dfb34b | 98 | ust_unlock(); |
ce5aef0b MD |
99 | return ret; |
100 | } | |
ce5aef0b MD |
101 | |
102 | void ltt_probe_unregister(struct lttng_probe_desc *desc) | |
103 | { | |
17dfb34b | 104 | ust_lock(); |
8d8a24c8 | 105 | cds_list_del(&desc->head); |
17dfb34b | 106 | ust_unlock(); |
ce5aef0b | 107 | } |
ce5aef0b | 108 | |
8165c8da MD |
109 | /* |
110 | * called with UST lock held. | |
111 | */ | |
ce5aef0b MD |
112 | const struct lttng_event_desc *ltt_event_get(const char *name) |
113 | { | |
114 | const struct lttng_event_desc *event; | |
ce5aef0b | 115 | |
ce5aef0b | 116 | event = find_event(name); |
ce5aef0b MD |
117 | if (!event) |
118 | return NULL; | |
ce5aef0b MD |
119 | return event; |
120 | } | |
ce5aef0b MD |
121 | |
122 | void ltt_event_put(const struct lttng_event_desc *event) | |
123 | { | |
ce5aef0b | 124 | } |
c8fcf224 MD |
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 | } |