Commit | Line | Data |
---|---|---|
4e3c1b9b MD |
1 | /* |
2 | * ltt-events.c | |
3 | * | |
4 | * Copyright 2010 (c) - Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | |
5 | * | |
6 | * Holds LTTng per-session event registry. | |
7 | */ | |
8 | ||
9 | #include <linux/module.h> | |
10 | #include "ltt-events.h" | |
11 | ||
12 | static LIST_HEAD(sessions); | |
13 | static DEFINE_MUTEX(sessions_mutex); | |
14 | static struct kmem_cache *event_cache; | |
15 | ||
16 | struct ltt_session *ltt_session_create(char *name) | |
17 | { | |
18 | struct ltt_session *session; | |
19 | ||
20 | mutex_lock(&sessions_mutex); | |
21 | list_for_each_entry(session, &sessions, list) | |
22 | if (!strcmp(session->name, name)) | |
23 | goto exist; | |
24 | session = kmalloc(sizeof(struct ltt_session) + strlen(name) + 1); | |
25 | if (!session) | |
26 | return NULL; | |
27 | strcpy(session->name, name); | |
28 | INIT_LIST_HEAD(&session->chan); | |
29 | list_add(&session->list, &sessions); | |
30 | mutex_unlock(&sessions_mutex); | |
31 | return session; | |
32 | ||
33 | exist: | |
34 | mutex_unlock(&sessions_mutex); | |
35 | return NULL; | |
36 | } | |
37 | ||
38 | int ltt_session_destroy(struct ltt_session *session) | |
39 | { | |
40 | struct ltt_channel *chan, *tmpchan; | |
41 | struct ltt_event *event, *tmpevent; | |
42 | ||
43 | mutex_lock(&sessions_mutex); | |
44 | list_for_each_entry_safe(event, tmpevent, &session->events, list) | |
45 | _ltt_event_destroy(event); | |
46 | list_for_each_entry_safe(chan, tmpchan, &session->chan, list) | |
47 | _ltt_channel_destroy(chan); | |
48 | list_del(&session->list); | |
49 | mutex_unlock(&sessions_mutex); | |
50 | kfree(session); | |
51 | } | |
52 | ||
53 | struct ltt_channel *ltt_channel_create(struct ltt_session *session, char *name, | |
54 | int overwrite, void *buf_addr, | |
55 | size_t subbuf_size, size_t num_subbuf, | |
56 | unsigned int switch_timer_interval, | |
57 | unsigned int read_timer_interval) | |
58 | { | |
59 | struct ltt_channel *chan; | |
60 | ||
61 | mutex_lock(&sessions_mutex); | |
e5382b6d MD |
62 | if (session->active) |
63 | goto active; /* Refuse to add channel to active session */ | |
4e3c1b9b MD |
64 | list_for_each_entry(chan, &session->chan, list) |
65 | if (!strcmp(chan->name, name)) | |
66 | goto exist; | |
67 | chan = kmalloc(sizeof(struct ltt_channel) + strlen(name) + 1, GFP_KERNEL); | |
68 | if (!chan) | |
69 | return NULL; | |
70 | strcpy(chan->name, name); | |
71 | chan->session = session; | |
72 | ||
73 | /* TODO: create rb channel */ | |
74 | list_add(&chan->list, &session->chan); | |
75 | mutex_unlock(&sessions_mutex); | |
76 | return chan; | |
77 | ||
78 | exist: | |
e5382b6d | 79 | active: |
4e3c1b9b MD |
80 | mutex_unlock(&sessions_mutex); |
81 | return NULL; | |
82 | } | |
83 | ||
84 | /* | |
85 | * Only used internally at session destruction. | |
86 | */ | |
87 | int _ltt_channel_destroy(struct ltt_channel *chan) | |
88 | { | |
89 | list_del(&chan->list); | |
90 | kfree(chan); | |
91 | } | |
92 | ||
e5382b6d MD |
93 | /* |
94 | * Supports event creation while tracing session is active. | |
95 | */ | |
4e3c1b9b MD |
96 | struct ltt_event *ltt_event_create(struct ltt_channel *chan, char *name, |
97 | void *filter) | |
98 | { | |
99 | struct ltt_event *event; | |
100 | ||
101 | mutex_lock(&sessions_mutex); | |
e5382b6d MD |
102 | if (chan->free_event_id == -1UL) |
103 | goto full; | |
4e3c1b9b MD |
104 | /* |
105 | * This is O(n^2) (for each event loop called at event creation). | |
106 | * Might require a hash if we have lots of events. | |
107 | */ | |
108 | list_for_each_entry(event, &chan->session->events, list) | |
109 | if (!strcmp(event->name, name)) | |
110 | goto exist; | |
111 | event = kmem_cache_zalloc(events_cache, GFP_KERNEL); | |
112 | if (!event) | |
113 | goto cache_error; | |
114 | event->name = kmalloc(strlen(name) + 1, GFP_KERNEL); | |
115 | if (!event->name) | |
116 | goto error; | |
117 | strcpy(event->name, name); | |
118 | event->chan = chan; | |
119 | event->filter = filter; | |
e5382b6d | 120 | event->id = chan->free_event_id++; |
4e3c1b9b | 121 | mutex_unlock(&sessions_mutex); |
e5382b6d MD |
122 | /* Populate ltt_event structure before tracepoint registration. */ |
123 | smp_wmb(); | |
124 | /* TODO register to tracepoint */ | |
4e3c1b9b MD |
125 | return event; |
126 | ||
127 | error: | |
128 | kmem_cache_free(event); | |
129 | cache_error: | |
130 | exist: | |
e5382b6d | 131 | full: |
4e3c1b9b MD |
132 | mutex_unlock(&sessions_mutex); |
133 | return NULL; | |
134 | } | |
135 | ||
136 | /* | |
137 | * Only used internally at session destruction. | |
138 | */ | |
139 | int _ltt_event_destroy(struct ltt_event *event) | |
140 | { | |
141 | /* TODO unregister from tracepoint */ | |
142 | kfree(event->name); | |
143 | kmem_cache_free(event); | |
144 | } | |
145 | ||
146 | static int __init ltt_events_init(void) | |
147 | { | |
148 | int ret; | |
149 | ||
150 | events_cache = KMEM_CACHE(ltt_event, 0); | |
151 | if (!events_cache) | |
152 | return -ENOMEM; | |
92e94819 MD |
153 | |
154 | /* TODO: show ABI to userspace */ | |
155 | ||
4e3c1b9b MD |
156 | return 0; |
157 | } | |
158 | ||
159 | static void __exit ltt_events_exit(void) | |
160 | { | |
92e94819 MD |
161 | struct ltt_session *session, *tmpsession; |
162 | ||
163 | /* TODO: hide ABI from userspace, wait for callers to release refs. */ | |
164 | ||
165 | list_for_each_entry_safe(session, tmpsession, &sessions, list) | |
166 | ltt_session_destroy(session); | |
4e3c1b9b MD |
167 | kmem_cache_destroy(events_cache); |
168 | } | |
92e94819 MD |
169 | |
170 | MODULE_LICENSE("GPL and additional rights"); | |
171 | MODULE_AUTHOR("Mathieu Desnoyers <mathieu.desnoyers@efficios.com>"); | |
172 | MODULE_DESCRIPTION("LTTng Events"); |