b8b00688 |
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> |
92f441a7 |
12 | #include <stdlib.h> |
b8b00688 |
13 | #include <stdio.h> |
14 | #include <signal.h> |
15 | #include <syscall.h> |
92f441a7 |
16 | #include <features.h> |
17 | #include <pthread.h> |
18 | #include <malloc.h> |
19 | #include <string.h> |
b8b00688 |
20 | |
92f441a7 |
21 | #include <asm/atomic.h> |
b8b00688 |
22 | #include "lttng_usertrace.h" |
23 | |
92f441a7 |
24 | #define MAX_TRACES 16 |
25 | |
26 | struct ltt_buf { |
27 | void *start; |
28 | atomic_t offset; |
29 | atomic_t reserve_count; |
30 | atomic_t commit_count; |
31 | |
32 | atomic_t events_lost; |
33 | }; |
34 | |
35 | struct lttng_trace_info { |
92f441a7 |
36 | int active:1; |
9d45fe0f |
37 | int filter; |
92f441a7 |
38 | struct { |
39 | struct ltt_buf facilities; |
40 | struct ltt_buf cpu; |
41 | } channel; |
42 | }; |
43 | |
44 | |
9d45fe0f |
45 | /* TLS for the trace info |
46 | * http://www.dis.com/gnu/gcc/C--98-Thread-Local-Edits.html |
78d75b00 |
47 | * |
48 | * Add after paragraph 4 |
49 | * |
50 | * The storage for an object of thread storage duration shall be statically |
51 | * initialized before the first statement of the thread startup function. An |
52 | * object of thread storage duration shall not require dynamic |
53 | * initialization. |
54 | * GCC extention permits init of a range. |
55 | */ |
92f441a7 |
56 | |
78d75b00 |
57 | static __thread struct lttng_trace_info lttng_trace_info[MAX_TRACES] = |
58 | { [ 0 ... MAX_TRACES-1 ].active = 0, |
9d45fe0f |
59 | [ 0 ... MAX_TRACES-1 ].filter = 0, |
78d75b00 |
60 | [ 0 ... MAX_TRACES-1 ].channel = |
61 | { NULL, |
62 | ATOMIC_INIT(0), |
63 | ATOMIC_INIT(0), |
64 | ATOMIC_INIT(0), |
65 | ATOMIC_INIT(0), |
66 | ATOMIC_INIT(0) |
67 | } |
68 | }; |
92f441a7 |
69 | |
9d45fe0f |
70 | |
71 | static void lttng_get_new_info(void) |
72 | { |
73 | unsigned long cpu_addr, fac_addr; |
74 | unsigned int i, first_empty; |
75 | int active, filter; |
76 | int ret; |
77 | |
78 | /* Get all the new traces */ |
79 | while(1) { |
80 | cpu_addr = fac_addr = 0; |
81 | active = filter = 0; |
82 | ret = ltt_update(&cpu_addr, &fac_addr, &active, &filter); |
83 | if(ret) { |
84 | printf("LTTng : error in ltt_update\n"); |
85 | exit(1); |
86 | } |
87 | |
88 | if(!cpu_addr || !fac_addr) break; |
89 | |
90 | first_empty = MAX_TRACES; |
91 | /* Try to find the trace */ |
92 | for(i=0;i<MAX_TRACES;i++) { |
93 | if(i<first_empty && !lttng_trace_info[i].channel.cpu.start) |
94 | first_empty = i; |
95 | if(cpu_addr == |
96 | (unsigned long)lttng_trace_info[i].channel.cpu.start && |
97 | fac_addr == |
98 | (unsigned long)lttng_trace_info[i].channel.facilities.start) { |
99 | |
100 | lttng_trace_info[i].filter = filter; |
101 | lttng_trace_info[i].active = active; |
102 | } |
103 | |
104 | } |
105 | if(i == MAX_TRACES) { |
106 | /* Not found. Must take an empty slot */ |
107 | if(first_empty == MAX_TRACES) { |
108 | printf( |
109 | "LTTng WARNING : too many traces requested for pid %d by the kernel.\n" |
110 | " Compilation defined maximum is %u\n", |
111 | getpid(), MAX_TRACES); |
112 | |
113 | } else { |
114 | lttng_trace_info[first_empty].channel.cpu.start = (void*)cpu_addr; |
115 | lttng_trace_info[first_empty].channel.facilities.start = |
116 | (void*)fac_addr; |
117 | lttng_trace_info[first_empty].filter = filter; |
118 | lttng_trace_info[first_empty].active = active; |
119 | } |
120 | } |
121 | } |
122 | } |
123 | |
124 | |
b8b00688 |
125 | /* signal handler */ |
126 | void __lttng_sig_trace_handler(int signo) |
127 | { |
92f441a7 |
128 | int ret; |
129 | sigset_t set, oldset; |
130 | |
1a1e2a8c |
131 | printf("LTTng signal handler : thread id : %lu, pid %lu\n", pthread_self(), getpid()); |
132 | #if 0 |
92f441a7 |
133 | /* Disable signals */ |
134 | ret = sigfillset(&set); |
135 | if(ret) { |
136 | printf("Error in sigfillset\n"); |
137 | exit(1); |
138 | } |
139 | |
140 | ret = sigprocmask(SIG_BLOCK, &set, &oldset); |
141 | if(ret) { |
142 | printf("Error in sigprocmask\n"); |
143 | exit(1); |
144 | } |
1a1e2a8c |
145 | #endif //0 |
1a1e2a8c |
146 | #if 0 |
92f441a7 |
147 | /* Enable signals */ |
148 | ret = sigprocmask(SIG_SETMASK, &oldset, NULL); |
149 | if(ret) { |
150 | printf("Error in sigprocmask\n"); |
151 | exit(1); |
152 | } |
1a1e2a8c |
153 | #endif //0 |
b8b00688 |
154 | } |
155 | |
156 | |
1a1e2a8c |
157 | static void thread_init(void) |
b8b00688 |
158 | { |
9d45fe0f |
159 | lttng_get_new_info(); |
b8b00688 |
160 | int err; |
161 | |
92f441a7 |
162 | /* Make some ltt_switch syscalls */ |
163 | err = ltt_switch((unsigned long)NULL); |
164 | if(err) { |
165 | printf("Error in ltt_switch system call\n"); |
166 | exit(1); |
167 | } |
1a1e2a8c |
168 | } |
169 | |
170 | void __attribute__((constructor)) __lttng_user_init(void) |
171 | { |
172 | static struct sigaction act; |
173 | int err; |
174 | |
175 | printf("LTTng user init\n"); |
176 | |
177 | /* Activate the signal */ |
178 | act.sa_handler = __lttng_sig_trace_handler; |
179 | err = sigemptyset(&(act.sa_mask)); |
180 | if(err) perror("Error with sigemptyset"); |
181 | err = sigaddset(&(act.sa_mask), SIGRTMIN+3); |
182 | if(err) perror("Error with sigaddset"); |
183 | err = sigaction(SIGRTMIN+3, &act, NULL); |
184 | if(err) perror("Error with sigaction"); |
92f441a7 |
185 | |
1a1e2a8c |
186 | thread_init(); |
187 | } |
92f441a7 |
188 | |
189 | |
1a1e2a8c |
190 | void lttng_thread_init(void) |
191 | { |
192 | thread_init(); |
b8b00688 |
193 | } |
1a1e2a8c |
194 | |
195 | |
196 | |
197 | |
198 | |