use liburcu-bp
[lttng-ust.git] / libust / tracectl.c
... / ...
CommitLineData
1/* Copyright (C) 2009 Pierre-Marc Fournier
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17
18#define _GNU_SOURCE
19#include <stdio.h>
20#include <stdint.h>
21#include <signal.h>
22#include <sys/types.h>
23#include <sys/socket.h>
24#include <sys/un.h>
25#include <sched.h>
26#include <fcntl.h>
27#include <poll.h>
28#include <regex.h>
29
30#include <urcu-bp.h>
31
32#include "marker.h"
33#include "tracer.h"
34#include "localerr.h"
35#include "ustcomm.h"
36#include "relay.h" /* FIXME: remove */
37#include "marker-control.h"
38
39//#define USE_CLONE
40
41#define USTSIGNAL SIGIO
42
43#define MAX_MSG_SIZE (100)
44#define MSG_NOTIF 1
45#define MSG_REGISTER_NOTIF 2
46
47char consumer_stack[10000];
48
49/* This should only be accessed by the constructor, before the creation
50 * of the listener, and then only by the listener.
51 */
52s64 pidunique = -1LL;
53
54struct list_head blocked_consumers = LIST_HEAD_INIT(blocked_consumers);
55
56static struct ustcomm_app ustcomm_app;
57
58struct tracecmd { /* no padding */
59 uint32_t size;
60 uint16_t command;
61};
62
63/* volatile because shared between the listener and the main thread */
64volatile sig_atomic_t buffers_to_export = 0;
65
66//struct listener_arg {
67// int pipe_fd;
68//};
69
70struct trctl_msg {
71 /* size: the size of all the fields except size itself */
72 uint32_t size;
73 uint16_t type;
74 /* Only the necessary part of the payload is transferred. It
75 * may even be none of it.
76 */
77 char payload[94];
78};
79
80struct consumer_channel {
81 int fd;
82 struct ltt_channel_struct *chan;
83};
84
85struct blocked_consumer {
86 int fd_consumer;
87 int fd_producer;
88 int tmp_poll_idx;
89
90 /* args to ustcomm_send_reply */
91 struct ustcomm_server server;
92 struct ustcomm_source src;
93
94 /* args to ltt_do_get_subbuf */
95 struct rchan_buf *rbuf;
96 struct ltt_channel_buf_struct *lttbuf;
97
98 struct list_head list;
99};
100
101static long long make_pidunique(void)
102{
103 s64 retval;
104 struct timeval tv;
105
106 gettimeofday(&tv, NULL);
107
108 retval = tv.tv_sec;
109 retval <<= 32;
110 retval |= tv.tv_usec;
111
112 return retval;
113}
114
115static void print_markers(FILE *fp)
116{
117 struct marker_iter iter;
118
119 lock_markers();
120 marker_iter_reset(&iter);
121 marker_iter_start(&iter);
122
123 while(iter.marker) {
124 fprintf(fp, "marker: %s/%s %d \"%s\"\n", iter.marker->channel, iter.marker->name, (int)imv_read(iter.marker->state), iter.marker->format);
125 marker_iter_next(&iter);
126 }
127 unlock_markers();
128}
129
130static int init_socket(void);
131
132/* This needs to be called whenever a new thread is created. It notifies
133 * liburcu of the new thread.
134 */
135
136void ust_register_thread(void)
137{
138 rcu_register_thread();
139}
140
141int fd_notif = -1;
142void notif_cb(void)
143{
144 int result;
145 struct trctl_msg msg;
146
147 /* FIXME: fd_notif should probably be protected by a spinlock */
148
149 if(fd_notif == -1)
150 return;
151
152 msg.type = MSG_NOTIF;
153 msg.size = sizeof(msg.type);
154
155 /* FIXME: don't block here */
156 result = write(fd_notif, &msg, msg.size+sizeof(msg.size));
157 if(result == -1) {
158 PERROR("write");
159 return;
160 }
161}
162
163/* Ask the daemon to collect a trace called trace_name and being
164 * produced by this pid.
165 *
166 * The trace must be at least allocated. (It can also be started.)
167 * This is because _ltt_trace_find is used.
168 */
169
170static void inform_consumer_daemon(const char *trace_name)
171{
172 int i;
173 struct ltt_trace_struct *trace;
174 pid_t pid = getpid();
175 int result;
176
177 ltt_lock_traces();
178
179 trace = _ltt_trace_find(trace_name);
180 if(trace == NULL) {
181 WARN("inform_consumer_daemon: could not find trace \"%s\"; it is probably already destroyed", trace_name);
182 goto finish;
183 }
184
185 for(i=0; i < trace->nr_channels; i++) {
186 result = ustcomm_request_consumer(pid, trace->channels[i].channel_name);
187 if(result == -1) {
188 WARN("Failed to request collection for channel %s. Is the daemon available?", trace->channels[i].channel_name);
189 /* continue even if fail */
190 }
191 buffers_to_export++;
192 }
193
194 finish:
195 ltt_unlock_traces();
196}
197
198void process_blocked_consumers(void)
199{
200 int n_fds = 0;
201 struct pollfd *fds;
202 struct blocked_consumer *bc;
203 int idx = 0;
204 char inbuf;
205 int result;
206
207 list_for_each_entry(bc, &blocked_consumers, list) {
208 n_fds++;
209 }
210
211 fds = (struct pollfd *) malloc(n_fds * sizeof(struct pollfd));
212 if(fds == NULL) {
213 ERR("malloc returned NULL");
214 return;
215 }
216
217 list_for_each_entry(bc, &blocked_consumers, list) {
218 fds[idx].fd = bc->fd_producer;
219 fds[idx].events = POLLIN;
220 bc->tmp_poll_idx = idx;
221 idx++;
222 }
223
224 while((result = poll(fds, n_fds, 0)) == -1 && errno == EINTR)
225 /* nothing */;
226 if(result == -1) {
227 PERROR("poll");
228 return;
229 }
230
231 list_for_each_entry(bc, &blocked_consumers, list) {
232 if(fds[bc->tmp_poll_idx].revents) {
233 long consumed_old = 0;
234 char *reply;
235
236 result = read(bc->fd_producer, &inbuf, 1);
237 if(result == -1) {
238 PERROR("read");
239 continue;
240 }
241 if(result == 0) {
242 DBG("PRODUCER END");
243
244 close(bc->fd_producer);
245
246 list_del(&bc->list);
247
248 result = ustcomm_send_reply(&bc->server, "END", &bc->src);
249 if(result < 0) {
250 ERR("ustcomm_send_reply failed");
251 continue;
252 }
253
254 continue;
255 }
256
257 result = ltt_do_get_subbuf(bc->rbuf, bc->lttbuf, &consumed_old);
258 if(result == -EAGAIN) {
259 WARN("missed buffer?");
260 continue;
261 }
262 else if(result < 0) {
263 DBG("ltt_do_get_subbuf: error: %s", strerror(-result));
264 }
265 asprintf(&reply, "%s %ld", "OK", consumed_old);
266 result = ustcomm_send_reply(&bc->server, reply, &bc->src);
267 if(result < 0) {
268 ERR("ustcomm_send_reply failed");
269 free(reply);
270 continue;
271 }
272 free(reply);
273
274 list_del(&bc->list);
275 }
276 }
277
278}
279
280void *listener_main(void *p)
281{
282 int result;
283
284 ust_register_thread();
285
286 DBG("LISTENER");
287
288 for(;;) {
289 char trace_name[] = "auto";
290 char trace_type[] = "ustrelay";
291 char *recvbuf;
292 int len;
293 struct ustcomm_source src;
294
295 process_blocked_consumers();
296
297 result = ustcomm_app_recv_message(&ustcomm_app, &recvbuf, &src, 5);
298 if(result < 0) {
299 WARN("error in ustcomm_app_recv_message");
300 continue;
301 }
302 else if(result == 0) {
303 /* no message */
304 continue;
305 }
306
307 DBG("received a message! it's: %s", recvbuf);
308 len = strlen(recvbuf);
309
310 if(!strcmp(recvbuf, "print_markers")) {
311 print_markers(stderr);
312 }
313 else if(!strcmp(recvbuf, "list_markers")) {
314 char *ptr;
315 size_t size;
316 FILE *fp;
317
318 fp = open_memstream(&ptr, &size);
319 print_markers(fp);
320 fclose(fp);
321
322 result = ustcomm_send_reply(&ustcomm_app.server, ptr, &src);
323
324 free(ptr);
325 }
326 else if(!strcmp(recvbuf, "start")) {
327 /* start is an operation that setups the trace, allocates it and starts it */
328 result = ltt_trace_setup(trace_name);
329 if(result < 0) {
330 ERR("ltt_trace_setup failed");
331 return (void *)1;
332 }
333
334 result = ltt_trace_set_type(trace_name, trace_type);
335 if(result < 0) {
336 ERR("ltt_trace_set_type failed");
337 return (void *)1;
338 }
339
340 result = ltt_trace_alloc(trace_name);
341 if(result < 0) {
342 ERR("ltt_trace_alloc failed");
343 return (void *)1;
344 }
345
346 inform_consumer_daemon(trace_name);
347
348 result = ltt_trace_start(trace_name);
349 if(result < 0) {
350 ERR("ltt_trace_start failed");
351 continue;
352 }
353 }
354 else if(!strcmp(recvbuf, "trace_setup")) {
355 DBG("trace setup");
356
357 result = ltt_trace_setup(trace_name);
358 if(result < 0) {
359 ERR("ltt_trace_setup failed");
360 return (void *)1;
361 }
362
363 result = ltt_trace_set_type(trace_name, trace_type);
364 if(result < 0) {
365 ERR("ltt_trace_set_type failed");
366 return (void *)1;
367 }
368 }
369 else if(!strcmp(recvbuf, "trace_alloc")) {
370 DBG("trace alloc");
371
372 result = ltt_trace_alloc(trace_name);
373 if(result < 0) {
374 ERR("ltt_trace_alloc failed");
375 return (void *)1;
376 }
377 }
378 else if(!strcmp(recvbuf, "trace_start")) {
379 DBG("trace start");
380
381 result = ltt_trace_start(trace_name);
382 if(result < 0) {
383 ERR("ltt_trace_start failed");
384 continue;
385 }
386 }
387 else if(!strcmp(recvbuf, "trace_stop")) {
388 DBG("trace stop");
389
390 result = ltt_trace_stop(trace_name);
391 if(result < 0) {
392 ERR("ltt_trace_stop failed");
393 return (void *)1;
394 }
395 }
396 else if(!strcmp(recvbuf, "trace_destroy")) {
397
398 DBG("trace destroy");
399
400 result = ltt_trace_destroy(trace_name);
401 if(result < 0) {
402 ERR("ltt_trace_destroy failed");
403 return (void *)1;
404 }
405 }
406 else if(nth_token_is(recvbuf, "get_shmid", 0) == 1) {
407 struct ltt_trace_struct *trace;
408 char trace_name[] = "auto";
409 int i;
410 char *channel_name;
411
412 DBG("get_shmid");
413
414 channel_name = nth_token(recvbuf, 1);
415 if(channel_name == NULL) {
416 ERR("get_shmid: cannot parse channel");
417 goto next_cmd;
418 }
419
420 ltt_lock_traces();
421 trace = _ltt_trace_find(trace_name);
422 ltt_unlock_traces();
423
424 if(trace == NULL) {
425 ERR("cannot find trace!");
426 return (void *)1;
427 }
428
429 for(i=0; i<trace->nr_channels; i++) {
430 struct rchan *rchan = trace->channels[i].trans_channel_data;
431 struct rchan_buf *rbuf = rchan->buf;
432 struct ltt_channel_struct *ltt_channel = (struct ltt_channel_struct *)rchan->private_data;
433
434 if(!strcmp(trace->channels[i].channel_name, channel_name)) {
435 char *reply;
436
437 DBG("the shmid for the requested channel is %d", rbuf->shmid);
438 DBG("the shmid for its buffer structure is %d", ltt_channel->buf_shmid);
439 asprintf(&reply, "%d %d", rbuf->shmid, ltt_channel->buf_shmid);
440
441 result = ustcomm_send_reply(&ustcomm_app.server, reply, &src);
442 if(result) {
443 ERR("listener: get_shmid: ustcomm_send_reply failed");
444 goto next_cmd;
445 }
446
447 free(reply);
448
449 break;
450 }
451 }
452
453 buffers_to_export--;
454 }
455 else if(nth_token_is(recvbuf, "get_n_subbufs", 0) == 1) {
456 struct ltt_trace_struct *trace;
457 char trace_name[] = "auto";
458 int i;
459 char *channel_name;
460
461 DBG("get_n_subbufs");
462
463 channel_name = nth_token(recvbuf, 1);
464 if(channel_name == NULL) {
465 ERR("get_n_subbufs: cannot parse channel");
466 goto next_cmd;
467 }
468
469 ltt_lock_traces();
470 trace = _ltt_trace_find(trace_name);
471 ltt_unlock_traces();
472
473 if(trace == NULL) {
474 ERR("cannot find trace!");
475 return (void *)1;
476 }
477
478 for(i=0; i<trace->nr_channels; i++) {
479 struct rchan *rchan = trace->channels[i].trans_channel_data;
480
481 if(!strcmp(trace->channels[i].channel_name, channel_name)) {
482 char *reply;
483
484 DBG("the n_subbufs for the requested channel is %zd", rchan->n_subbufs);
485 asprintf(&reply, "%zd", rchan->n_subbufs);
486
487 result = ustcomm_send_reply(&ustcomm_app.server, reply, &src);
488 if(result) {
489 ERR("listener: get_n_subbufs: ustcomm_send_reply failed");
490 goto next_cmd;
491 }
492
493 free(reply);
494
495 break;
496 }
497 }
498 }
499 else if(nth_token_is(recvbuf, "get_subbuf_size", 0) == 1) {
500 struct ltt_trace_struct *trace;
501 char trace_name[] = "auto";
502 int i;
503 char *channel_name;
504
505 DBG("get_subbuf_size");
506
507 channel_name = nth_token(recvbuf, 1);
508 if(channel_name == NULL) {
509 ERR("get_subbuf_size: cannot parse channel");
510 goto next_cmd;
511 }
512
513 ltt_lock_traces();
514 trace = _ltt_trace_find(trace_name);
515 ltt_unlock_traces();
516
517 if(trace == NULL) {
518 ERR("cannot find trace!");
519 return (void *)1;
520 }
521
522 for(i=0; i<trace->nr_channels; i++) {
523 struct rchan *rchan = trace->channels[i].trans_channel_data;
524
525 if(!strcmp(trace->channels[i].channel_name, channel_name)) {
526 char *reply;
527
528 DBG("the subbuf_size for the requested channel is %zd", rchan->subbuf_size);
529 asprintf(&reply, "%zd", rchan->subbuf_size);
530
531 result = ustcomm_send_reply(&ustcomm_app.server, reply, &src);
532 if(result) {
533 ERR("listener: get_subbuf_size: ustcomm_send_reply failed");
534 goto next_cmd;
535 }
536
537 free(reply);
538
539 break;
540 }
541 }
542 }
543 else if(nth_token_is(recvbuf, "load_probe_lib", 0) == 1) {
544 char *libfile;
545
546 libfile = nth_token(recvbuf, 1);
547
548 DBG("load_probe_lib loading %s", libfile);
549 }
550 else if(nth_token_is(recvbuf, "get_subbuffer", 0) == 1) {
551 struct ltt_trace_struct *trace;
552 char trace_name[] = "auto";
553 int i;
554 char *channel_name;
555
556 DBG("get_subbuf");
557
558 channel_name = nth_token(recvbuf, 1);
559 if(channel_name == NULL) {
560 ERR("get_subbuf: cannot parse channel");
561 goto next_cmd;
562 }
563
564 ltt_lock_traces();
565 trace = _ltt_trace_find(trace_name);
566 ltt_unlock_traces();
567
568 if(trace == NULL) {
569 ERR("cannot find trace!");
570 return (void *)1;
571 }
572
573 for(i=0; i<trace->nr_channels; i++) {
574 struct rchan *rchan = trace->channels[i].trans_channel_data;
575
576 if(!strcmp(trace->channels[i].channel_name, channel_name)) {
577 struct rchan_buf *rbuf = rchan->buf;
578 struct ltt_channel_buf_struct *lttbuf = trace->channels[i].buf;
579 struct blocked_consumer *bc;
580
581 bc = (struct blocked_consumer *) malloc(sizeof(struct blocked_consumer));
582 if(bc == NULL) {
583 ERR("malloc returned NULL");
584 goto next_cmd;
585 }
586 bc->fd_consumer = src.fd;
587 bc->fd_producer = lttbuf->data_ready_fd_read;
588 bc->rbuf = rbuf;
589 bc->lttbuf = lttbuf;
590 bc->src = src;
591 bc->server = ustcomm_app.server;
592
593 list_add(&bc->list, &blocked_consumers);
594
595 break;
596 }
597 }
598 }
599 else if(nth_token_is(recvbuf, "put_subbuffer", 0) == 1) {
600 struct ltt_trace_struct *trace;
601 char trace_name[] = "auto";
602 int i;
603 char *channel_name;
604 long consumed_old;
605 char *consumed_old_str;
606 char *endptr;
607
608 DBG("put_subbuf");
609
610 channel_name = strdup_malloc(nth_token(recvbuf, 1));
611 if(channel_name == NULL) {
612 ERR("put_subbuf_size: cannot parse channel");
613 goto next_cmd;
614 }
615
616 consumed_old_str = strdup_malloc(nth_token(recvbuf, 2));
617 if(consumed_old_str == NULL) {
618 ERR("put_subbuf: cannot parse consumed_old");
619 goto next_cmd;
620 }
621 consumed_old = strtol(consumed_old_str, &endptr, 10);
622 if(*endptr != '\0') {
623 ERR("put_subbuf: invalid value for consumed_old");
624 goto next_cmd;
625 }
626
627 ltt_lock_traces();
628 trace = _ltt_trace_find(trace_name);
629 ltt_unlock_traces();
630
631 if(trace == NULL) {
632 ERR("cannot find trace!");
633 return (void *)1;
634 }
635
636 for(i=0; i<trace->nr_channels; i++) {
637 struct rchan *rchan = trace->channels[i].trans_channel_data;
638
639 if(!strcmp(trace->channels[i].channel_name, channel_name)) {
640 struct rchan_buf *rbuf = rchan->buf;
641 struct ltt_channel_buf_struct *lttbuf = trace->channels[i].buf;
642 char *reply;
643 long consumed_old=0;
644
645 result = ltt_do_put_subbuf(rbuf, lttbuf, consumed_old);
646 if(result < 0) {
647 WARN("ltt_do_put_subbuf: error (subbuf=%s)", channel_name);
648 asprintf(&reply, "%s", "ERROR");
649 }
650 else {
651 DBG("ltt_do_put_subbuf: success (subbuf=%s)", channel_name);
652 asprintf(&reply, "%s", "OK");
653 }
654
655 result = ustcomm_send_reply(&ustcomm_app.server, reply, &src);
656 if(result) {
657 ERR("listener: put_subbuf: ustcomm_send_reply failed");
658 goto next_cmd;
659 }
660
661 free(reply);
662
663 break;
664 }
665 }
666
667 free(channel_name);
668 free(consumed_old_str);
669 }
670 else if(nth_token_is(recvbuf, "enable_marker", 0) == 1) {
671 char *channel_slash_name = nth_token(recvbuf, 1);
672 char channel_name[256]="";
673 char marker_name[256]="";
674
675 result = sscanf(channel_slash_name, "%255[^/]/%255s", channel_name, marker_name);
676
677 if(channel_name == NULL || marker_name == NULL) {
678 WARN("invalid marker name");
679 goto next_cmd;
680 }
681 printf("%s %s\n", channel_name, marker_name);
682
683 result = ltt_marker_connect(channel_name, marker_name, "default");
684 if(result < 0) {
685 WARN("could not enable marker; channel=%s, name=%s", channel_name, marker_name);
686 }
687 }
688 else if(nth_token_is(recvbuf, "disable_marker", 0) == 1) {
689 char *channel_slash_name = nth_token(recvbuf, 1);
690 char *marker_name;
691 char *channel_name;
692
693 result = sscanf(channel_slash_name, "%a[^/]/%as", &channel_name, &marker_name);
694
695 if(marker_name == NULL) {
696 }
697 printf("%s %s\n", channel_name, marker_name);
698
699 result = ltt_marker_disconnect(channel_name, marker_name, "default");
700 if(result < 0) {
701 WARN("could not disable marker; channel=%s, name=%s", channel_name, marker_name);
702 }
703 }
704 else if(nth_token_is(recvbuf, "get_pidunique", 0) == 1) {
705 char *reply;
706
707 asprintf(&reply, "%lld", pidunique);
708
709 result = ustcomm_send_reply(&ustcomm_app.server, reply, &src);
710 if(result) {
711 ERR("listener: get_pidunique: ustcomm_send_reply failed");
712 goto next_cmd;
713 }
714
715 free(reply);
716 }
717// else if(nth_token_is(recvbuf, "get_notifications", 0) == 1) {
718// struct ltt_trace_struct *trace;
719// char trace_name[] = "auto";
720// int i;
721// char *channel_name;
722//
723// DBG("get_notifications");
724//
725// channel_name = strdup_malloc(nth_token(recvbuf, 1));
726// if(channel_name == NULL) {
727// ERR("put_subbuf_size: cannot parse channel");
728// goto next_cmd;
729// }
730//
731// ltt_lock_traces();
732// trace = _ltt_trace_find(trace_name);
733// ltt_unlock_traces();
734//
735// if(trace == NULL) {
736// ERR("cannot find trace!");
737// return (void *)1;
738// }
739//
740// for(i=0; i<trace->nr_channels; i++) {
741// struct rchan *rchan = trace->channels[i].trans_channel_data;
742// int fd;
743//
744// if(!strcmp(trace->channels[i].channel_name, channel_name)) {
745// struct rchan_buf *rbuf = rchan->buf;
746// struct ltt_channel_buf_struct *lttbuf = trace->channels[i].buf;
747//
748// result = fd = ustcomm_app_detach_client(&ustcomm_app, &src);
749// if(result == -1) {
750// ERR("ustcomm_app_detach_client failed");
751// goto next_cmd;
752// }
753//
754// lttbuf->wake_consumer_arg = (void *) fd;
755//
756// smp_wmb();
757//
758// lttbuf->call_wake_consumer = 1;
759//
760// break;
761// }
762// }
763//
764// free(channel_name);
765// }
766 else {
767 ERR("unable to parse message: %s", recvbuf);
768 }
769
770 next_cmd:
771 free(recvbuf);
772 }
773}
774
775volatile sig_atomic_t have_listener = 0;
776
777void create_listener(void)
778{
779#ifdef USE_CLONE
780 static char listener_stack[16384];
781#else
782 pthread_t thread;
783#endif
784
785 if(have_listener)
786 return;
787
788#ifdef USE_CLONE
789 result = clone(listener_main, listener_stack+sizeof(listener_stack)-1, CLONE_FS | CLONE_FILES | CLONE_VM | CLONE_SIGHAND | CLONE_THREAD, NULL);
790 if(result == -1) {
791 perror("clone");
792 return;
793 }
794#else
795
796 pthread_create(&thread, NULL, listener_main, NULL);
797#endif
798
799 have_listener = 1;
800}
801
802/* The signal handler itself. Signals must be setup so there cannot be
803 nested signals. */
804
805void sighandler(int sig)
806{
807 DBG("sighandler");
808
809 if(!have_listener) {
810 create_listener();
811 }
812}
813
814/* Called by the app signal handler to chain it to us. */
815
816void chain_signal(void)
817{
818 sighandler(USTSIGNAL);
819}
820
821static int init_socket(void)
822{
823 return ustcomm_init_app(getpid(), &ustcomm_app);
824}
825
826static int init_signal_handler(void)
827{
828 /* Attempt to handler SIGIO. If the main program wants to
829 * handle it, fine, it'll override us. They it'll have to
830 * use the chaining function.
831 */
832
833 int result;
834 struct sigaction act;
835
836 result = sigemptyset(&act.sa_mask);
837 if(result == -1) {
838 PERROR("sigemptyset");
839 return -1;
840 }
841
842 act.sa_handler = sighandler;
843 act.sa_flags = SA_RESTART;
844
845 /* Only defer ourselves. Also, try to restart interrupted
846 * syscalls to disturb the traced program as little as possible.
847 */
848 result = sigaction(SIGIO, &act, NULL);
849 if(result == -1) {
850 PERROR("sigaction");
851 return -1;
852 }
853
854 return 0;
855}
856
857#define AUTOPROBE_DISABLED 0
858#define AUTOPROBE_ENABLE_ALL 1
859#define AUTOPROBE_ENABLE_REGEX 2
860static int autoprobe_method = AUTOPROBE_DISABLED;
861static regex_t autoprobe_regex;
862
863static void auto_probe_connect(struct marker *m)
864{
865 int result;
866
867 char* concat_name = NULL;
868 const char *probe_name = "default";
869
870 if(autoprobe_method == AUTOPROBE_DISABLED) {
871 return;
872 }
873 else if(autoprobe_method == AUTOPROBE_ENABLE_REGEX) {
874 result = asprintf(&concat_name, "%s/%s", m->channel, m->name);
875 if(result == -1) {
876 ERR("auto_probe_connect: asprintf failed (marker %s/%s)",
877 m->channel, m->name);
878 return;
879 }
880 if (regexec(&autoprobe_regex, concat_name, 0, NULL, 0)) {
881 free(concat_name);
882 return;
883 }
884 free(concat_name);
885 }
886
887 result = ltt_marker_connect(m->channel, m->name, probe_name);
888 if(result && result != -EEXIST)
889 ERR("ltt_marker_connect (marker = %s/%s, errno = %d)", m->channel, m->name, -result);
890
891 DBG("auto connected marker %s %s to probe default", m->channel, m->name);
892
893}
894
895static void __attribute__((constructor(1000))) init()
896{
897 int result;
898 char* autoprobe_val = NULL;
899
900 /* Assign the pidunique, to be able to differentiate the processes with same
901 * pid, (before and after an exec).
902 */
903 pidunique = make_pidunique();
904
905 /* Initialize RCU in case the constructor order is not good. */
906 urcu_init();
907
908 /* It is important to do this before events start to be generated. */
909 ust_register_thread();
910
911 DBG("Tracectl constructor");
912
913 /* Must create socket before signal handler to prevent races.
914 */
915 result = init_socket();
916 if(result == -1) {
917 ERR("init_socket error");
918 return;
919 }
920 result = init_signal_handler();
921 if(result == -1) {
922 ERR("init_signal_handler error");
923 return;
924 }
925
926 autoprobe_val = getenv("UST_AUTOPROBE");
927 if(autoprobe_val) {
928 struct marker_iter iter;
929
930 DBG("Autoprobe enabled.");
931
932 /* Ensure markers are initialized */
933 //init_markers();
934
935 /* Ensure marker control is initialized, for the probe */
936 init_marker_control();
937
938 /* first, set the callback that will connect the
939 * probe on new markers
940 */
941 if(autoprobe_val[0] == '/') {
942 result = regcomp(&autoprobe_regex, autoprobe_val+1, 0);
943 if (result) {
944 char regexerr[150];
945
946 regerror(result, &autoprobe_regex, regexerr, sizeof(regexerr));
947 ERR("cannot parse regex %s (%s), will ignore UST_AUTOPROBE", autoprobe_val, regexerr);
948 /* don't crash the application just for this */
949 }
950 else {
951 autoprobe_method = AUTOPROBE_ENABLE_REGEX;
952 }
953 }
954 else {
955 /* just enable all instrumentation */
956 autoprobe_method = AUTOPROBE_ENABLE_ALL;
957 }
958
959 marker_set_new_marker_cb(auto_probe_connect);
960
961 /* Now, connect the probes that were already registered. */
962 marker_iter_reset(&iter);
963 marker_iter_start(&iter);
964
965 DBG("now iterating on markers already registered");
966 while(iter.marker) {
967 DBG("now iterating on marker %s", iter.marker->name);
968 auto_probe_connect(iter.marker);
969 marker_iter_next(&iter);
970 }
971 }
972
973 if(getenv("UST_TRACE")) {
974 char trace_name[] = "auto";
975 char trace_type[] = "ustrelay";
976
977 DBG("starting early tracing");
978
979 /* Ensure marker control is initialized */
980 init_marker_control();
981
982 /* Ensure relay is initialized */
983 init_ustrelay_transport();
984
985 /* Ensure markers are initialized */
986 init_markers();
987
988 /* In case. */
989 ltt_channels_register("ust");
990
991 result = ltt_trace_setup(trace_name);
992 if(result < 0) {
993 ERR("ltt_trace_setup failed");
994 return;
995 }
996
997 result = ltt_trace_set_type(trace_name, trace_type);
998 if(result < 0) {
999 ERR("ltt_trace_set_type failed");
1000 return;
1001 }
1002
1003 result = ltt_trace_alloc(trace_name);
1004 if(result < 0) {
1005 ERR("ltt_trace_alloc failed");
1006 return;
1007 }
1008
1009 result = ltt_trace_start(trace_name);
1010 if(result < 0) {
1011 ERR("ltt_trace_start failed");
1012 return;
1013 }
1014
1015 /* Do this after the trace is started in order to avoid creating confusion
1016 * if the trace fails to start. */
1017 inform_consumer_daemon(trace_name);
1018 }
1019
1020
1021 return;
1022
1023 /* should decrementally destroy stuff if error */
1024
1025}
1026
1027/* This is only called if we terminate normally, not with an unhandled signal,
1028 * so we cannot rely on it. However, for now, LTTV requires that the header of
1029 * the last sub-buffer contain a valid end time for the trace. This is done
1030 * automatically only when the trace is properly stopped.
1031 *
1032 * If the traced program crashed, it is always possible to manually add the
1033 * right value in the header, or to open the trace in text mode.
1034 *
1035 * FIXME: Fix LTTV so it doesn't need this.
1036 */
1037
1038static void destroy_traces(void)
1039{
1040 int result;
1041
1042 /* if trace running, finish it */
1043
1044 DBG("destructor stopping traces");
1045
1046 result = ltt_trace_stop("auto");
1047 if(result == -1) {
1048 ERR("ltt_trace_stop error");
1049 }
1050
1051 result = ltt_trace_destroy("auto");
1052 if(result == -1) {
1053 ERR("ltt_trace_destroy error");
1054 }
1055}
1056
1057static int trace_recording(void)
1058{
1059 int retval = 0;
1060 struct ltt_trace_struct *trace;
1061
1062 ltt_lock_traces();
1063
1064 list_for_each_entry(trace, &ltt_traces.head, list) {
1065 if(trace->active) {
1066 retval = 1;
1067 break;
1068 }
1069 }
1070
1071 ltt_unlock_traces();
1072
1073 return retval;
1074}
1075
1076#if 0
1077static int have_consumer(void)
1078{
1079 return !list_empty(&blocked_consumers);
1080}
1081#endif
1082
1083int restarting_usleep(useconds_t usecs)
1084{
1085 struct timespec tv;
1086 int result;
1087
1088 tv.tv_sec = 0;
1089 tv.tv_nsec = usecs * 1000;
1090
1091 do {
1092 result = nanosleep(&tv, &tv);
1093 } while(result == -1 && errno == EINTR);
1094
1095 return result;
1096}
1097
1098/* This destructor keeps the process alive for a few seconds in order
1099 * to leave time to ustd to connect to its buffers. This is necessary
1100 * for programs whose execution is very short. It is also useful in all
1101 * programs when tracing is started close to the end of the program
1102 * execution.
1103 *
1104 * FIXME: For now, this only works for the first trace created in a
1105 * process.
1106 */
1107
1108static void __attribute__((destructor)) keepalive()
1109{
1110 if(trace_recording() && buffers_to_export) {
1111 int total = 0;
1112 DBG("Keeping process alive for consumer daemon...");
1113 while(buffers_to_export) {
1114 const int interv = 200000;
1115 restarting_usleep(interv);
1116 total += interv;
1117
1118 if(total >= 3000000) {
1119 WARN("non-consumed buffers remaining after wait limit; not waiting anymore");
1120 break;
1121 }
1122 }
1123 DBG("Finally dying...");
1124 }
1125
1126 destroy_traces();
1127
1128 ustcomm_fini_app(&ustcomm_app);
1129}
1130
1131void ust_potential_exec(void)
1132{
1133 trace_mark(ust, potential_exec, MARK_NOARGS);
1134
1135 keepalive();
1136}
1137
1138/* Notify ust that there was a fork. This needs to be called inside
1139 * the new process, anytime a process whose memory is not shared with
1140 * the parent is created. If this function is not called, the events
1141 * of the new process will not be collected.
1142 */
1143
1144void ust_fork(void)
1145{
1146 struct blocked_consumer *bc;
1147 struct blocked_consumer *deletable_bc = NULL;
1148 int result;
1149
1150 DBG("ust: forking");
1151 ltt_trace_stop("auto");
1152 ltt_trace_destroy("auto");
1153 /* Delete all active connections */
1154 ustcomm_close_all_connections(&ustcomm_app.server);
1155
1156 /* Delete all blocked consumers */
1157 list_for_each_entry(bc, &blocked_consumers, list) {
1158 close(bc->fd_producer);
1159 close(bc->fd_consumer);
1160 free(deletable_bc);
1161 deletable_bc = bc;
1162 list_del(&bc->list);
1163 }
1164
1165 have_listener = 0;
1166 create_listener();
1167 init_socket();
1168 ltt_trace_setup("auto");
1169 result = ltt_trace_set_type("auto", "ustrelay");
1170 if(result < 0) {
1171 ERR("ltt_trace_set_type failed");
1172 return;
1173 }
1174
1175 ltt_trace_alloc("auto");
1176 ltt_trace_start("auto");
1177 inform_consumer_daemon("auto");
1178}
1179
This page took 0.029962 seconds and 4 git commands to generate.