Fix: statedump hang due to incorrect wait/wakeup use
[lttng-modules.git] / lttng-probes.c
1 /*
2 * lttng-probes.c
3 *
4 * Holds LTTng probes registry.
5 *
6 * Copyright (C) 2010-2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; only
11 * version 2.1 of the License.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #include <linux/module.h>
24 #include <linux/list.h>
25 #include <linux/mutex.h>
26 #include <linux/seq_file.h>
27
28 #include "lttng-events.h"
29
30 static LIST_HEAD(probe_list);
31 static DEFINE_MUTEX(probe_mutex);
32
33 static
34 const struct lttng_event_desc *find_event(const char *name)
35 {
36 struct lttng_probe_desc *probe_desc;
37 int i;
38
39 list_for_each_entry(probe_desc, &probe_list, head) {
40 for (i = 0; i < probe_desc->nr_events; i++) {
41 if (!strcmp(probe_desc->event_desc[i]->name, name))
42 return probe_desc->event_desc[i];
43 }
44 }
45 return NULL;
46 }
47
48 int lttng_probe_register(struct lttng_probe_desc *desc)
49 {
50 int ret = 0;
51 int i;
52
53 mutex_lock(&probe_mutex);
54 /*
55 * TODO: This is O(N^2). Turn into a hash table when probe registration
56 * overhead becomes an issue.
57 */
58 for (i = 0; i < desc->nr_events; i++) {
59 if (find_event(desc->event_desc[i]->name)) {
60 ret = -EEXIST;
61 goto end;
62 }
63 }
64 list_add(&desc->head, &probe_list);
65 end:
66 mutex_unlock(&probe_mutex);
67 return ret;
68 }
69 EXPORT_SYMBOL_GPL(lttng_probe_register);
70
71 void lttng_probe_unregister(struct lttng_probe_desc *desc)
72 {
73 mutex_lock(&probe_mutex);
74 list_del(&desc->head);
75 mutex_unlock(&probe_mutex);
76 }
77 EXPORT_SYMBOL_GPL(lttng_probe_unregister);
78
79 const struct lttng_event_desc *lttng_event_get(const char *name)
80 {
81 const struct lttng_event_desc *event;
82 int ret;
83
84 mutex_lock(&probe_mutex);
85 event = find_event(name);
86 mutex_unlock(&probe_mutex);
87 if (!event)
88 return NULL;
89 ret = try_module_get(event->owner);
90 WARN_ON_ONCE(!ret);
91 return event;
92 }
93 EXPORT_SYMBOL_GPL(lttng_event_get);
94
95 void lttng_event_put(const struct lttng_event_desc *event)
96 {
97 module_put(event->owner);
98 }
99 EXPORT_SYMBOL_GPL(lttng_event_put);
100
101 static
102 void *tp_list_start(struct seq_file *m, loff_t *pos)
103 {
104 struct lttng_probe_desc *probe_desc;
105 int iter = 0, i;
106
107 mutex_lock(&probe_mutex);
108 list_for_each_entry(probe_desc, &probe_list, head) {
109 for (i = 0; i < probe_desc->nr_events; i++) {
110 if (iter++ >= *pos)
111 return (void *) probe_desc->event_desc[i];
112 }
113 }
114 /* End of list */
115 return NULL;
116 }
117
118 static
119 void *tp_list_next(struct seq_file *m, void *p, loff_t *ppos)
120 {
121 struct lttng_probe_desc *probe_desc;
122 int iter = 0, i;
123
124 (*ppos)++;
125 list_for_each_entry(probe_desc, &probe_list, head) {
126 for (i = 0; i < probe_desc->nr_events; i++) {
127 if (iter++ >= *ppos)
128 return (void *) probe_desc->event_desc[i];
129 }
130 }
131 /* End of list */
132 return NULL;
133 }
134
135 static
136 void tp_list_stop(struct seq_file *m, void *p)
137 {
138 mutex_unlock(&probe_mutex);
139 }
140
141 static
142 int tp_list_show(struct seq_file *m, void *p)
143 {
144 const struct lttng_event_desc *probe_desc = p;
145
146 /*
147 * Don't export lttng internal event: lttng_metadata.
148 */
149 if (!strcmp(probe_desc->name, "lttng_metadata"))
150 return 0;
151 seq_printf(m, "event { name = %s; };\n",
152 probe_desc->name);
153 return 0;
154 }
155
156 static
157 const struct seq_operations lttng_tracepoint_list_seq_ops = {
158 .start = tp_list_start,
159 .next = tp_list_next,
160 .stop = tp_list_stop,
161 .show = tp_list_show,
162 };
163
164 static
165 int lttng_tracepoint_list_open(struct inode *inode, struct file *file)
166 {
167 return seq_open(file, &lttng_tracepoint_list_seq_ops);
168 }
169
170 const struct file_operations lttng_tracepoint_list_fops = {
171 .owner = THIS_MODULE,
172 .open = lttng_tracepoint_list_open,
173 .read = seq_read,
174 .llseek = seq_lseek,
175 .release = seq_release,
176 };
This page took 0.041503 seconds and 4 git commands to generate.