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
33 * Copyright 2006 Mathieu Desnoyers
37 #include <sys/types.h>
51 #include "ltt-usertrace-fast.h"
54 /* Writer (the traced application) */
56 __thread
struct ltt_trace_info
*thread_trace_info
= NULL
;
58 void ltt_usertrace_fast_buffer_switch(void)
60 kill(thread_trace_info
->daemon_id
, SIGUSR1
);
63 static void ltt_usertrace_fast_cleanup(void *arg
)
65 kill(thread_trace_info
->daemon_id
, SIGUSR2
);
68 /* Reader (the disk dumper daemon) */
70 static pid_t ppid
= 0;
71 static int parent_exited
= 0;
74 static void handler_sigusr1(int signo
)
76 printf("Signal %d received : parent buffer switch.\n", signo
);
79 static void handler_sigusr2(int signo
)
81 printf("Signal %d received : parent exited.\n", signo
);
85 static void handler_sigalarm(int signo
)
87 printf("Signal %d received\n", signo
);
89 if(getppid() != ppid
) {
91 printf("Parent %lu died, cleaning up\n", ppid
);
98 /* This function is called by ltt_thread_init which has signals blocked */
99 static void ltt_usertrace_fast_daemon(struct ltt_trace_info
*shared_trace_info
,
102 struct sigaction act
;
107 printf("ltt_usertrace_fast_daemon : init is %d, pid is %lu\n",
108 shared_trace_info
->init
, getpid());
110 act
.sa_handler
= handler_sigusr1
;
112 sigemptyset(&(act
.sa_mask
));
113 sigaddset(&(act
.sa_mask
), SIGUSR1
);
114 sigaction(SIGUSR1
, &act
, NULL
);
116 act
.sa_handler
= handler_sigusr2
;
118 sigemptyset(&(act
.sa_mask
));
119 sigaddset(&(act
.sa_mask
), SIGUSR2
);
120 sigaction(SIGUSR2
, &act
, NULL
);
122 act
.sa_handler
= handler_sigalarm
;
124 sigemptyset(&(act
.sa_mask
));
125 sigaddset(&(act
.sa_mask
), SIGALRM
);
126 sigaction(SIGALRM
, &act
, NULL
);
129 ret
= pthread_sigmask(SIG_SETMASK
, &oldset
, NULL
);
131 printf("Error in pthread_sigmask\n");
139 if(ppid
== 0) break; /* parent died */
140 if(parent_exited
) break;
141 printf("Doing a buffer switch read. pid is : %lu\n", getpid());
142 //printf("Test parent. pid is : %lu, ppid is %lu\n", getpid(), getppid());
145 /* Buffer force switch (flush) */
148 /* The parent thread is dead and we have finished with the buffer */
149 munmap(shared_trace_info
, sizeof(*shared_trace_info
));
155 /* Reader-writer initialization */
157 static enum ltt_process_role
{ LTT_ROLE_WRITER
, LTT_ROLE_READER
}
158 role
= LTT_ROLE_WRITER
;
161 void ltt_rw_init(void)
164 struct ltt_trace_info
*shared_trace_info
;
166 sigset_t set
, oldset
;
168 /* parent : create the shared memory map */
169 shared_trace_info
= thread_trace_info
= mmap(0, sizeof(*thread_trace_info
),
170 PROT_READ
|PROT_WRITE
, MAP_SHARED
|MAP_ANONYMOUS
, 0, 0);
171 memset(shared_trace_info
, 0, sizeof(*thread_trace_info
));
172 thread_trace_info
->init
= 1;
174 /* Disable signals */
175 ret
= sigfillset(&set
);
177 printf("Error in sigfillset\n");
181 ret
= pthread_sigmask(SIG_BLOCK
, &set
, &oldset
);
183 printf("Error in pthread_sigmask\n");
189 thread_trace_info
->daemon_id
= pid
;
192 ret
= pthread_sigmask(SIG_SETMASK
, &oldset
, NULL
);
194 printf("Error in pthread_sigmask\n");
196 } else if(pid
== 0) {
198 role
= LTT_ROLE_READER
;
199 ltt_usertrace_fast_daemon(shared_trace_info
, oldset
);
200 /* Should never return */
204 perror("Error in forking ltt-usertrace-fast");
208 static __thread
struct _pthread_cleanup_buffer cleanup_buffer
;
210 void ltt_thread_init(void)
212 _pthread_cleanup_push(&cleanup_buffer
, ltt_usertrace_fast_cleanup
, NULL
);
216 void __attribute__((constructor
)) __ltt_usertrace_fast_init(void)
218 printf("LTT usertrace-fast init\n");
223 void __attribute__((destructor
)) __ltt_usertrace_fast_fini(void)
225 if(role
== LTT_ROLE_WRITER
) {
226 printf("LTT usertrace-fast fini\n");
227 ltt_usertrace_fast_cleanup(NULL
);