disable signals in update function
[lttv.git] / usertrace / lttng_usertrace.c
1
2 /* LTTng user-space tracing code
3 *
4 * Copyright 2006 Mathieu Desnoyers
5 *
6 */
7
8
9 #include <sys/types.h>
10 #include <sys/wait.h>
11 #include <unistd.h>
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <signal.h>
15 #include <syscall.h>
16 #include <features.h>
17 #include <pthread.h>
18 #include <malloc.h>
19 #include <string.h>
20
21 #include "lttng_usertrace.h"
22
23 #define MAX_TRACES 16
24
25
26 /*
27 * Notes :
28 *
29 * ltt_update :
30 *
31 * it should send the information on the traces that has their status MODIFIED.
32 * It's a necessary assumption to have a correct lttng_free_trace_info, which
33 * would not be reentrant otherwise.
34 */
35
36
37 /* TLS for the trace info
38 * http://www.dis.com/gnu/gcc/C--98-Thread-Local-Edits.html
39 *
40 * Add after paragraph 4
41 *
42 * The storage for an object of thread storage duration shall be statically
43 * initialized before the first statement of the thread startup function. An
44 * object of thread storage duration shall not require dynamic
45 * initialization.
46 * GCC extention permits init of a range.
47 */
48
49 static __thread struct lttng_trace_info lttng_trace_info[MAX_TRACES] =
50 { [ 0 ... MAX_TRACES-1 ].active = 0,
51 [ 0 ... MAX_TRACES-1 ].filter = 0,
52 [ 0 ... MAX_TRACES-1 ].nesting = ATOMIC_INIT(0),
53 [ 0 ... MAX_TRACES-1 ].channel =
54 { NULL,
55 0,
56 ATOMIC_INIT(0),
57 ATOMIC_INIT(0),
58 ATOMIC_INIT(0),
59 ATOMIC_INIT(0),
60 ATOMIC_INIT(0)
61 }
62 };
63
64
65 /* Must be called we sure nobody else is using the info.
66 * It implies that the trace should have been previously stopped
67 * and that every writer has finished.
68 *
69 * Writers should always check if the trace must be destroyed when they
70 * finish writing and the nesting level is 0.
71 */
72 void lttng_free_trace_info(struct lttng_trace_info *info)
73 {
74 int ret;
75
76 if(info->active) {
77 printf(
78 "LTTng ERROR : lttng_free_trace_info should be called on inactive trace\n");
79 exit(1);
80 }
81 if(!info->destroy) {
82 printf(
83 "LTTng ERROR : lttng_free_trace_info should be called on destroyed trace\n");
84 exit(1);
85 }
86 if(atomic_read(&info->nesting) > 0) {
87 printf(
88 "LTTng ERROR : lttng_free_trace_info should not be nested on tracing\n");
89 exit(1);
90 }
91
92 /* Remove the maps */
93 ret = munmap(info->channel.cpu.start, info->channel.cpu.length);
94 if(ret) {
95 perror("LTTNG : error in munmap");
96 }
97 ret = munmap(info->channel.facilities.start, info->channel.facilities.length);
98 if(ret) {
99 perror("LTTNG : error in munmap");
100 }
101
102 /* Zero the structure */
103 memset(info, 0, sizeof(struct lttng_trace_info));
104 }
105
106
107 static struct lttng_trace_info* find_info(unsigned long cpu_addr,
108 unsigned long fac_addr, unsigned int *first_empty)
109 {
110 struct lttng_trace_info *found = NULL;
111 unsigned int i;
112
113 *first_empty = MAX_TRACES;
114
115 /* Try to find the trace */
116 for(i=0;i<MAX_TRACES;i++) {
117 if(i<*first_empty && !lttng_trace_info[i].channel.cpu.start)
118 *first_empty = i;
119 if(cpu_addr ==
120 (unsigned long)lttng_trace_info[i].channel.cpu.start &&
121 fac_addr ==
122 (unsigned long)lttng_trace_info[i].channel.facilities.start) {
123 /* Found */
124 found = &lttng_trace_info[i];
125 break;
126 }
127 }
128 return found;
129 }
130
131
132 static void lttng_get_new_info(void)
133 {
134 unsigned long cpu_addr, fac_addr;
135 unsigned int i, first_empty;
136 int active, filter, destroy;
137 int ret;
138 struct lttng_trace_info *info;
139 sigset_t set, oldset;
140
141 /* Disable signals */
142 ret = sigfillset(&set);
143 if(ret) {
144 printf("Error in sigfillset\n");
145 exit(1);
146 }
147
148 ret = pthread_sigmask(SIG_BLOCK, &set, &oldset);
149 if(ret) {
150 printf("Error in sigprocmask\n");
151 exit(1);
152 }
153
154 /* Get all the new traces */
155 while(1) {
156 cpu_addr = fac_addr = 0;
157 active = filter = destroy = 0;
158 ret = ltt_update(&cpu_addr, &fac_addr, &active, &filter, &destroy);
159 if(ret) {
160 printf("LTTng : error in ltt_update\n");
161 exit(1);
162 }
163
164 if(!cpu_addr || !fac_addr) break;
165
166 info = find_info(cpu_addr, fac_addr, &first_empty);
167 if(info) {
168 info->filter = filter;
169 info->active = active;
170 info->destroy = destroy;
171 if(destroy && !atomic_read(&info->nesting))
172 lttng_free_trace_info(info);
173 } else {
174 /* Not found. Must take an empty slot */
175 if(first_empty == MAX_TRACES) {
176 printf(
177 "LTTng WARNING : too many traces requested for pid %d by the kernel.\n"
178 " Compilation defined maximum is %u\n",
179 getpid(), MAX_TRACES);
180
181 } else {
182 info = &lttng_trace_info[first_empty];
183 info->channel.cpu.start = (void*)cpu_addr;
184 info->channel.cpu.length = PAGE_SIZE;
185 info->channel.facilities.start = (void*)fac_addr;
186 info->channel.facilities.length = PAGE_SIZE;
187 info->filter = filter;
188 info->active = active;
189 info->destroy = destroy;
190 if(destroy && !atomic_read(&info->nesting))
191 lttng_free_trace_info(info);
192 }
193 }
194 }
195
196 /* Enable signals */
197 ret = pthread_sigmask(SIG_SETMASK, &oldset, NULL);
198 if(ret) {
199 printf("Error in sigprocmask\n");
200 exit(1);
201 }
202 }
203
204
205 /* signal handler */
206 void __lttng_sig_trace_handler(int signo)
207 {
208 printf("LTTng signal handler : thread id : %lu, pid %lu\n", pthread_self(), getpid());
209 lttng_get_new_info();
210 }
211
212
213 static void thread_init(void)
214 {
215 int err;
216 lttng_get_new_info();
217
218 /* Make some ltt_switch syscalls */
219 err = ltt_switch((unsigned long)NULL);
220 if(err) {
221 printf("Error in ltt_switch system call\n");
222 exit(1);
223 }
224 }
225
226 void __attribute__((constructor)) __lttng_user_init(void)
227 {
228 static struct sigaction act;
229 int err;
230
231 printf("LTTng user init\n");
232
233 /* Activate the signal */
234 act.sa_handler = __lttng_sig_trace_handler;
235 err = sigemptyset(&(act.sa_mask));
236 if(err) perror("Error with sigemptyset");
237 err = sigaddset(&(act.sa_mask), SIGRTMIN+3);
238 if(err) perror("Error with sigaddset");
239 err = sigaction(SIGRTMIN+3, &act, NULL);
240 if(err) perror("Error with sigaction");
241
242 thread_init();
243 }
244
245
246 void lttng_thread_init(void)
247 {
248 thread_init();
249 }
250
251
This page took 0.034569 seconds and 5 git commands to generate.