1 /* LTTng user-space "fast" library
3 * This daemon is spawned by each traced thread (to share the mmap).
5 * Its job is to dump periodically this buffer to disk (when it receives a
6 * SIGUSR1 from its parent).
8 * It uses the control information in the shared memory area (producer/consumer
11 * When the parent thread dies (yes, those thing may happen) ;) , this daemon
12 * will flush the last buffer and write it to disk.
14 * Supplement note for streaming : the daemon is responsible for flushing
15 * periodically the buffer if it is streaming data.
19 * shm memory is typically limited to 4096 units (system wide limit SHMMNI in
20 * /proc/sys/kernel/shmmni). As it requires computation time upon creation, we
21 * do not use it : we will use a shared mmap() instead which is passed through
23 * MAP_SHARED mmap segment. Updated when msync or munmap are called.
25 * Memory mapped by mmap() is preserved across fork(2), with the same
28 * Eventually, there will be two mode :
29 * * Slow thread spawn : a fork() is done for each new thread. If the process
30 * dies, the data is not lost.
31 * * Fast thread spawn : a pthread_create() is done by the application for each
34 * We use a timer to check periodically if the parent died. I think it is less
35 * intrusive than a ptrace() on the parent, which would get every signal. The
36 * side effect of this is that we won't be notified if the parent does an
37 * exec(). In this case, we will just sit there until the parent exits.
40 * Copyright 2006 Mathieu Desnoyers
44 #include <sys/types.h>
58 #include "ltt-usertrace-fast.h"
61 /* Writer (the traced application) */
63 __thread
struct ltt_trace_info
*thread_trace_info
= NULL
;
65 void ltt_usertrace_fast_buffer_switch(void)
67 struct ltt_trace_info
*tmp
= thread_trace_info
;
69 kill(tmp
->daemon_id
, SIGUSR1
);
72 static void ltt_usertrace_fast_cleanup(void *arg
)
74 struct ltt_trace_info
*tmp
= thread_trace_info
;
76 thread_trace_info
= NULL
;
77 kill(tmp
->daemon_id
, SIGUSR2
);
78 munmap(tmp
, sizeof(*tmp
));
82 /* Reader (the disk dumper daemon) */
84 static pid_t traced_pid
= 0;
85 static int parent_exited
= 0;
88 static void handler_sigusr1(int signo
)
90 printf("LTT Signal %d received : parent buffer switch.\n", signo
);
93 static void handler_sigusr2(int signo
)
95 printf("LTT Signal %d received : parent exited.\n", signo
);
99 static void handler_sigalarm(int signo
)
101 printf("LTT Signal %d received\n", signo
);
103 if(getppid() != traced_pid
) {
105 printf("LTT Parent %lu died, cleaning up\n", traced_pid
);
112 /* This function is called by ltt_rw_init which has signals blocked */
113 static void ltt_usertrace_fast_daemon(struct ltt_trace_info
*shared_trace_info
,
114 sigset_t oldset
, pid_t l_traced_pid
)
116 struct sigaction act
;
119 traced_pid
= l_traced_pid
;
121 printf("LTT ltt_usertrace_fast_daemon : init is %d, pid is %lu, traced_pid is %lu\n",
122 shared_trace_info
->init
, getpid(), traced_pid
);
124 act
.sa_handler
= handler_sigusr1
;
126 sigemptyset(&(act
.sa_mask
));
127 sigaddset(&(act
.sa_mask
), SIGUSR1
);
128 sigaction(SIGUSR1
, &act
, NULL
);
130 act
.sa_handler
= handler_sigusr2
;
132 sigemptyset(&(act
.sa_mask
));
133 sigaddset(&(act
.sa_mask
), SIGUSR2
);
134 sigaction(SIGUSR2
, &act
, NULL
);
136 act
.sa_handler
= handler_sigalarm
;
138 sigemptyset(&(act
.sa_mask
));
139 sigaddset(&(act
.sa_mask
), SIGALRM
);
140 sigaction(SIGALRM
, &act
, NULL
);
143 ret
= pthread_sigmask(SIG_SETMASK
, &oldset
, NULL
);
145 printf("LTT Error in pthread_sigmask\n");
152 if(traced_pid
== 0) break; /* parent died */
153 if(parent_exited
) break;
154 printf("LTT Doing a buffer switch read. pid is : %lu\n", getpid());
155 //printf("Test parent. pid is : %lu, ppid is %lu\n", getpid(), getppid());
158 /* Buffer force switch (flush) */
161 /* The parent thread is dead and we have finished with the buffer */
162 munmap(shared_trace_info
, sizeof(*shared_trace_info
));
168 /* Reader-writer initialization */
170 static enum ltt_process_role
{ LTT_ROLE_WRITER
, LTT_ROLE_READER
}
171 role
= LTT_ROLE_WRITER
;
174 void ltt_rw_init(void)
177 struct ltt_trace_info
*shared_trace_info
;
179 sigset_t set
, oldset
;
180 pid_t l_traced_pid
= getpid();
182 /* parent : create the shared memory map */
183 shared_trace_info
= mmap(0, sizeof(*thread_trace_info
),
184 PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANONYMOUS
, 0, 0);
185 memset(shared_trace_info
, 0, sizeof(*shared_trace_info
));
186 shared_trace_info
->init
= 1;
188 /* Disable signals */
189 ret
= sigfillset(&set
);
191 printf("LTT Error in sigfillset\n");
195 ret
= pthread_sigmask(SIG_BLOCK
, &set
, &oldset
);
197 printf("LTT Error in pthread_sigmask\n");
203 shared_trace_info
->daemon_id
= pid
;
204 thread_trace_info
= shared_trace_info
;
207 ret
= pthread_sigmask(SIG_SETMASK
, &oldset
, NULL
);
209 printf("LTT Error in pthread_sigmask\n");
211 } else if(pid
== 0) {
213 role
= LTT_ROLE_READER
;
214 ltt_usertrace_fast_daemon(shared_trace_info
, oldset
, l_traced_pid
);
215 /* Should never return */
219 perror("LTT Error in forking ltt-usertrace-fast");
223 static __thread
struct _pthread_cleanup_buffer cleanup_buffer
;
225 void ltt_thread_init(void)
227 _pthread_cleanup_push(&cleanup_buffer
, ltt_usertrace_fast_cleanup
, NULL
);
231 void __attribute__((constructor
)) __ltt_usertrace_fast_init(void)
233 printf("LTT usertrace-fast init\n");
238 void __attribute__((destructor
)) __ltt_usertrace_fast_fini(void)
240 if(role
== LTT_ROLE_WRITER
) {
241 printf("LTT usertrace-fast fini\n");
242 ltt_usertrace_fast_cleanup(NULL
);