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