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>
60 #include <sys/param.h>
62 #include <asm/timex.h> //for get_cycles()
64 #include "ltt-usertrace-fast.h"
67 /* Writer (the traced application) */
69 __thread
struct ltt_trace_info
*thread_trace_info
= NULL
;
71 void ltt_usertrace_fast_buffer_switch(void)
73 struct ltt_trace_info
*tmp
= thread_trace_info
;
75 kill(tmp
->daemon_id
, SIGUSR1
);
78 /* The cleanup should never be called from a signal handler */
79 static void ltt_usertrace_fast_cleanup(void *arg
)
81 struct ltt_trace_info
*tmp
= thread_trace_info
;
83 thread_trace_info
= NULL
;
84 kill(tmp
->daemon_id
, SIGUSR2
);
85 munmap(tmp
, sizeof(*tmp
));
89 /* Reader (the disk dumper daemon) */
91 static pid_t traced_pid
= 0;
92 static pthread_t traced_thread
= 0;
93 static int parent_exited
= 0;
96 static void handler_sigusr1(int signo
)
98 printf("LTT Signal %d received : parent buffer switch.\n", signo
);
101 static void handler_sigusr2(int signo
)
103 printf("LTT Signal %d received : parent exited.\n", signo
);
107 static void handler_sigalarm(int signo
)
109 printf("LTT Signal %d received\n", signo
);
111 if(getppid() != traced_pid
) {
113 printf("LTT Parent %lu died, cleaning up\n", traced_pid
);
120 /* This function is called by ltt_rw_init which has signals blocked */
121 static void ltt_usertrace_fast_daemon(struct ltt_trace_info
*shared_trace_info
,
122 sigset_t oldset
, pid_t l_traced_pid
, pthread_t l_traced_thread
)
124 struct sigaction act
;
128 char outfile_name
[PATH_MAX
];
129 char identifier_name
[PATH_MAX
];
132 traced_pid
= l_traced_pid
;
133 traced_thread
= l_traced_thread
;
135 printf("LTT ltt_usertrace_fast_daemon : init is %d, pid is %lu, traced_pid is %lu\n",
136 shared_trace_info
->init
, getpid(), traced_pid
);
138 act
.sa_handler
= handler_sigusr1
;
140 sigemptyset(&(act
.sa_mask
));
141 sigaddset(&(act
.sa_mask
), SIGUSR1
);
142 sigaction(SIGUSR1
, &act
, NULL
);
144 act
.sa_handler
= handler_sigusr2
;
146 sigemptyset(&(act
.sa_mask
));
147 sigaddset(&(act
.sa_mask
), SIGUSR2
);
148 sigaction(SIGUSR2
, &act
, NULL
);
150 act
.sa_handler
= handler_sigalarm
;
152 sigemptyset(&(act
.sa_mask
));
153 sigaddset(&(act
.sa_mask
), SIGALRM
);
154 sigaction(SIGALRM
, &act
, NULL
);
157 ret
= pthread_sigmask(SIG_SETMASK
, &oldset
, NULL
);
159 printf("LTT Error in pthread_sigmask\n");
164 /* Open output files */
166 ret
= mkdir(LTT_USERTRACE_ROOT
, 0777);
167 if(ret
< 0 && errno
!= EEXIST
) {
168 perror("LTT Error in creating output (mkdir)");
171 ret
= chdir(LTT_USERTRACE_ROOT
);
173 perror("LTT Error in creating output (chdir)");
176 snprintf(identifier_name
, PATH_MAX
-1, "%lu.%lu.%llu",
177 traced_pid
, traced_thread
, get_cycles());
178 snprintf(outfile_name
, PATH_MAX
-1, "facilities-%s", identifier_name
);
179 fd_fac
= creat(outfile_name
, 0666);
181 snprintf(outfile_name
, PATH_MAX
-1, "cpu-%s", identifier_name
);
182 fd_cpu
= creat(outfile_name
, 0666);
187 if(traced_pid
== 0) break; /* parent died */
188 if(parent_exited
) break;
189 printf("LTT Doing a buffer switch read. pid is : %lu\n", getpid());
190 //printf("Test parent. pid is : %lu, ppid is %lu\n", getpid(), getppid());
193 /* Buffer force switch (flush) */
199 /* The parent thread is dead and we have finished with the buffer */
200 munmap(shared_trace_info
, sizeof(*shared_trace_info
));
206 /* Reader-writer initialization */
208 static enum ltt_process_role
{ LTT_ROLE_WRITER
, LTT_ROLE_READER
}
209 role
= LTT_ROLE_WRITER
;
212 void ltt_rw_init(void)
215 struct ltt_trace_info
*shared_trace_info
;
217 sigset_t set
, oldset
;
218 pid_t l_traced_pid
= getpid();
219 pthread_t l_traced_thread
= pthread_self();
221 /* parent : create the shared memory map */
222 shared_trace_info
= mmap(0, sizeof(*thread_trace_info
),
223 PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANONYMOUS
, 0, 0);
224 memset(shared_trace_info
, 0, sizeof(*shared_trace_info
));
225 shared_trace_info
->init
= 1;
227 /* Disable signals */
228 ret
= sigfillset(&set
);
230 printf("LTT Error in sigfillset\n");
234 ret
= pthread_sigmask(SIG_BLOCK
, &set
, &oldset
);
236 printf("LTT Error in pthread_sigmask\n");
242 shared_trace_info
->daemon_id
= pid
;
243 thread_trace_info
= shared_trace_info
;
246 ret
= pthread_sigmask(SIG_SETMASK
, &oldset
, NULL
);
248 printf("LTT Error in pthread_sigmask\n");
250 } else if(pid
== 0) {
252 role
= LTT_ROLE_READER
;
253 ltt_usertrace_fast_daemon(shared_trace_info
, oldset
, l_traced_pid
,
255 /* Should never return */
259 perror("LTT Error in forking ltt-usertrace-fast");
263 static __thread
struct _pthread_cleanup_buffer cleanup_buffer
;
265 void ltt_thread_init(void)
267 _pthread_cleanup_push(&cleanup_buffer
, ltt_usertrace_fast_cleanup
, NULL
);
271 void __attribute__((constructor
)) __ltt_usertrace_fast_init(void)
273 printf("LTT usertrace-fast init\n");
278 void __attribute__((destructor
)) __ltt_usertrace_fast_fini(void)
280 if(role
== LTT_ROLE_WRITER
) {
281 printf("LTT usertrace-fast fini\n");
282 ltt_usertrace_fast_cleanup(NULL
);