Update version to 0.16
[ust.git] / libust / marker-control.c
1 /*
2 * Copyright (C) 2007 Mathieu Desnoyers
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 *
18 */
19
20 /* This file contains a high-level API for activating and deactivating ust_markers,
21 * and making sure ust_markers in a given library can be released when the library
22 * is unloaded.
23 */
24
25 #include <ctype.h>
26 #include <stdlib.h>
27
28 #include "tracer.h"
29 #include "usterr_signal_safe.h"
30
31 #define DEFAULT_CHANNEL "cpu"
32 #define DEFAULT_PROBE "default"
33
34 static int initialized;
35
36 CDS_LIST_HEAD(probes_list);
37
38 /*
39 * Mutex protecting the probe slab cache.
40 * Nests inside the traces mutex.
41 */
42 DEFINE_MUTEX(probes_mutex);
43
44 struct ltt_available_probe default_probe = {
45 .name = "default",
46 .format = NULL,
47 .probe_func = ltt_vtrace,
48 .callbacks[0] = ltt_serialize_data,
49 };
50
51 //ust//static struct kmem_cache *ust_markers_loaded_cachep;
52 static CDS_LIST_HEAD(ust_markers_loaded_list);
53 /*
54 * List sorted by name strcmp order.
55 */
56 static CDS_LIST_HEAD(probes_registered_list);
57
58 static struct ltt_available_probe *get_probe_from_name(const char *pname)
59 {
60 struct ltt_available_probe *iter;
61 int comparison, found = 0;
62
63 if (!pname)
64 pname = DEFAULT_PROBE;
65 cds_list_for_each_entry(iter, &probes_registered_list, node) {
66 comparison = strcmp(pname, iter->name);
67 if (!comparison)
68 found = 1;
69 if (comparison <= 0)
70 break;
71 }
72 if (found)
73 return iter;
74 else
75 return NULL;
76 }
77
78 /* (unused)
79 static char *skip_spaces(char *buf)
80 {
81 while (*buf != '\0' && isspace(*buf))
82 buf++;
83 return buf;
84 }
85
86 static char *skip_nonspaces(char *buf)
87 {
88 while (*buf != '\0' && !isspace(*buf))
89 buf++;
90 return buf;
91 }
92
93 static void get_ust_marker_string(char *buf, char **start,
94 char **end)
95 {
96 *start = skip_spaces(buf);
97 *end = skip_nonspaces(*start);
98 **end = '\0';
99 }
100 */
101
102 int ltt_probe_register(struct ltt_available_probe *pdata)
103 {
104 int ret = 0;
105 int comparison;
106 struct ltt_available_probe *iter;
107
108 pthread_mutex_lock(&probes_mutex);
109 cds_list_for_each_entry_reverse(iter, &probes_registered_list, node) {
110 comparison = strcmp(pdata->name, iter->name);
111 if (!comparison) {
112 ret = -EBUSY;
113 goto end;
114 } else if (comparison > 0) {
115 /* We belong to the location right after iter. */
116 cds_list_add(&pdata->node, &iter->node);
117 goto end;
118 }
119 }
120 /* Should be added at the head of the list */
121 cds_list_add(&pdata->node, &probes_registered_list);
122 end:
123 pthread_mutex_unlock(&probes_mutex);
124 return ret;
125 }
126
127 /*
128 * Called when a probe does not want to be called anymore.
129 */
130 int ltt_probe_unregister(struct ltt_available_probe *pdata)
131 {
132 int ret = 0;
133 struct ltt_active_ust_marker *amark, *tmp;
134
135 pthread_mutex_lock(&probes_mutex);
136 cds_list_for_each_entry_safe(amark, tmp, &ust_markers_loaded_list, node) {
137 if (amark->probe == pdata) {
138 ret = ust_marker_probe_unregister_private_data(
139 pdata->probe_func, amark);
140 if (ret)
141 goto end;
142 cds_list_del(&amark->node);
143 free(amark);
144 }
145 }
146 cds_list_del(&pdata->node);
147 end:
148 pthread_mutex_unlock(&probes_mutex);
149 return ret;
150 }
151
152 /*
153 * Connect ust_marker "mname" to probe "pname".
154 * Only allow _only_ probe instance to be connected to a ust_marker.
155 */
156 int ltt_ust_marker_connect(const char *channel, const char *mname,
157 const char *pname)
158
159 {
160 int ret;
161 struct ltt_active_ust_marker *pdata;
162 struct ltt_available_probe *probe;
163
164 ltt_lock_traces();
165 pthread_mutex_lock(&probes_mutex);
166 probe = get_probe_from_name(pname);
167 if (!probe) {
168 ret = -ENOENT;
169 goto end;
170 }
171 pdata = ust_marker_get_private_data(channel, mname, probe->probe_func, 0);
172 if (pdata && !IS_ERR(pdata)) {
173 ret = -EEXIST;
174 goto end;
175 }
176 pdata = zmalloc(sizeof(struct ltt_active_ust_marker));
177 if (!pdata) {
178 ret = -ENOMEM;
179 goto end;
180 }
181 pdata->probe = probe;
182 /*
183 * ID has priority over channel in case of conflict.
184 */
185 ret = ust_marker_probe_register(channel, mname, NULL,
186 probe->probe_func, pdata);
187 if (ret)
188 free(pdata);
189 else
190 cds_list_add(&pdata->node, &ust_markers_loaded_list);
191 end:
192 pthread_mutex_unlock(&probes_mutex);
193 ltt_unlock_traces();
194 return ret;
195 }
196
197 /*
198 * Disconnect ust_marker "mname", probe "pname".
199 */
200 int ltt_ust_marker_disconnect(const char *channel, const char *mname,
201 const char *pname)
202 {
203 struct ltt_active_ust_marker *pdata;
204 struct ltt_available_probe *probe;
205 int ret = 0;
206
207 pthread_mutex_lock(&probes_mutex);
208 probe = get_probe_from_name(pname);
209 if (!probe) {
210 ret = -ENOENT;
211 goto end;
212 }
213 pdata = ust_marker_get_private_data(channel, mname, probe->probe_func, 0);
214 if (IS_ERR(pdata)) {
215 ret = PTR_ERR(pdata);
216 goto end;
217 } else if (!pdata) {
218 /*
219 * Not registered by us.
220 */
221 ret = -EPERM;
222 goto end;
223 }
224 ret = ust_marker_probe_unregister(channel, mname, probe->probe_func, pdata);
225 if (ret)
226 goto end;
227 else {
228 cds_list_del(&pdata->node);
229 free(pdata);
230 }
231 end:
232 pthread_mutex_unlock(&probes_mutex);
233 return ret;
234 }
235
236 static void disconnect_all_ust_markers(void)
237 {
238 struct ltt_active_ust_marker *pdata, *tmp;
239
240 cds_list_for_each_entry_safe(pdata, tmp, &ust_markers_loaded_list, node) {
241 ust_marker_probe_unregister_private_data(pdata->probe->probe_func,
242 pdata);
243 cds_list_del(&pdata->node);
244 free(pdata);
245 }
246 }
247
248 void __attribute__((constructor)) init_ust_marker_control(void)
249 {
250 if (!initialized) {
251 int ret;
252
253 init_ust_marker();
254 ret = ltt_probe_register(&default_probe);
255 BUG_ON(ret);
256 ret = ltt_ust_marker_connect("metadata", "core_marker_format",
257 DEFAULT_PROBE);
258 BUG_ON(ret);
259 ret = ltt_ust_marker_connect("metadata", "core_marker_id", DEFAULT_PROBE);
260 BUG_ON(ret);
261 initialized = 1;
262 }
263 }
264
265 static void __attribute__((destructor)) ust_marker_control_exit(void)
266 {
267 int ret;
268
269 ret = ltt_ust_marker_disconnect("metadata", "core_marker_format",
270 DEFAULT_PROBE);
271 BUG_ON(ret);
272 ret = ltt_ust_marker_disconnect("metadata", "core_marker_id",
273 DEFAULT_PROBE);
274 BUG_ON(ret);
275 ret = ltt_probe_unregister(&default_probe);
276 BUG_ON(ret);
277 disconnect_all_ust_markers();
278 ust_marker_synchronize_unregister();
279 }
This page took 0.037519 seconds and 4 git commands to generate.