3732bc03714ae585297dd3b933e86a912b3c7a29
[ust.git] / libtracectl / tracectl.c
1 #include <stdio.h>
2 #include <stdint.h>
3 #include <signal.h>
4 #include <sys/types.h>
5 #include <sys/socket.h>
6 #include <sys/un.h>
7 #include <sched.h>
8 #include <fcntl.h>
9
10 #include "marker.h"
11 #include "tracer.h"
12 #include "localerr.h"
13 #include "ustcomm.h"
14 #include "relay.h" /* FIXME: remove */
15
16 //#define USE_CLONE
17
18 #define USTSIGNAL SIGIO
19
20 #define MAX_MSG_SIZE (100)
21 #define MSG_NOTIF 1
22 #define MSG_REGISTER_NOTIF 2
23
24 char consumer_stack[10000];
25
26 static struct ustcomm_app ustcomm_app;
27
28 struct tracecmd { /* no padding */
29 uint32_t size;
30 uint16_t command;
31 };
32
33 //struct listener_arg {
34 // int pipe_fd;
35 //};
36
37 struct trctl_msg {
38 /* size: the size of all the fields except size itself */
39 uint32_t size;
40 uint16_t type;
41 /* Only the necessary part of the payload is transferred. It
42 * may even be none of it.
43 */
44 char payload[94];
45 };
46
47 struct consumer_channel {
48 int fd;
49 struct ltt_channel_struct *chan;
50 };
51
52 int consumer(void *arg)
53 {
54 int result;
55 int fd;
56 char str[] = "Hello, this is the consumer.\n";
57 struct ltt_trace_struct *trace;
58 struct consumer_channel *consumer_channels;
59 int i;
60 char trace_name[] = "auto";
61
62 ltt_lock_traces();
63 trace = _ltt_trace_find(trace_name);
64 ltt_unlock_traces();
65
66 if(trace == NULL) {
67 CPRINTF("cannot find trace!");
68 return 1;
69 }
70
71 consumer_channels = (struct consumer_channel *) malloc(trace->nr_channels * sizeof(struct consumer_channel));
72 if(consumer_channels == NULL) {
73 ERR("malloc returned NULL");
74 return 1;
75 }
76
77 CPRINTF("opening trace files");
78 for(i=0; i<trace->nr_channels; i++) {
79 char tmp[100];
80 struct ltt_channel_struct *chan = &trace->channels[i];
81
82 consumer_channels[i].chan = chan;
83
84 snprintf(tmp, sizeof(tmp), "trace/%s_0", chan->channel_name);
85 result = consumer_channels[i].fd = open(tmp, O_WRONLY | O_CREAT | O_TRUNC, 00600);
86 if(result == -1) {
87 perror("open");
88 return -1;
89 }
90 CPRINTF("\topened trace file %s", tmp);
91
92 }
93 CPRINTF("done opening trace files");
94
95 for(;;) {
96 /*wait*/
97
98 for(i=0; i<trace->nr_channels; i++) {
99 struct rchan *rchan = consumer_channels[i].chan->trans_channel_data;
100 struct rchan_buf *rbuf = rchan->buf;
101 struct ltt_channel_buf_struct *lttbuf = consumer_channels[i].chan->buf;
102 long consumed_old;
103
104 result = ltt_do_get_subbuf(rbuf, lttbuf, &consumed_old);
105 if(result < 0) {
106 DBG("ltt_do_get_subbuf: error: %s", strerror(-result));
107 }
108 else {
109 DBG("success!");
110
111 result = write(consumer_channels[i].fd, rbuf->buf_data + (consumed_old & (2 * 4096-1)), 4096);
112 ltt_do_put_subbuf(rbuf, lttbuf, consumed_old);
113 }
114 }
115
116 sleep(1);
117 }
118 }
119
120 void start_consumer(void)
121 {
122 #ifdef USE_CLONE
123 int result;
124
125 result = clone(consumer, consumer_stack+sizeof(consumer_stack)-1, CLONE_FS | CLONE_FILES | CLONE_VM | CLONE_SIGHAND | CLONE_THREAD, NULL);
126 if(result == -1) {
127 perror("clone");
128 }
129 #else
130 pthread_t thread;
131
132 pthread_create(&thread, NULL, consumer, NULL);
133 #endif
134 }
135
136 static void print_markers(void)
137 {
138 struct marker_iter iter;
139
140 lock_markers();
141 marker_iter_reset(&iter);
142 marker_iter_start(&iter);
143
144 while(iter.marker) {
145 fprintf(stderr, "marker: %s_%s \"%s\"\n", iter.marker->channel, iter.marker->name, iter.marker->format);
146 marker_iter_next(&iter);
147 }
148 unlock_markers();
149 }
150
151 void do_command(struct tracecmd *cmd)
152 {
153 }
154
155 void receive_commands()
156 {
157 }
158
159 int fd_notif = -1;
160 void notif_cb(void)
161 {
162 int result;
163 struct trctl_msg msg;
164
165 /* FIXME: fd_notif should probably be protected by a spinlock */
166
167 if(fd_notif == -1)
168 return;
169
170 msg.type = MSG_NOTIF;
171 msg.size = sizeof(msg.type);
172
173 /* FIXME: don't block here */
174 result = write(fd_notif, &msg, msg.size+sizeof(msg.size));
175 if(result == -1) {
176 PERROR("write");
177 return;
178 }
179 }
180
181 static int inform_consumer_daemon(void)
182 {
183 ustcomm_request_consumer(getpid(), "metadata");
184 ustcomm_request_consumer(getpid(), "ust");
185 }
186
187 int listener_main(void *p)
188 {
189 int result;
190
191 DBG("LISTENER");
192
193 for(;;) {
194 uint32_t size;
195 struct sockaddr_un addr;
196 socklen_t addrlen = sizeof(addr);
197 char trace_name[] = "auto";
198 char trace_type[] = "ustrelay";
199 char *recvbuf;
200 int len;
201 struct ustcomm_source src;
202
203 result = ustcomm_app_recv_message(&ustcomm_app, &recvbuf, &src, -1);
204 if(result <= 0) {
205 WARN("error in ustcomm_app_recv_message");
206 continue;
207 }
208
209 DBG("received a message! it's: %s\n", recvbuf);
210 len = strlen(recvbuf);
211
212 if(!strcmp(recvbuf, "print_markers")) {
213 print_markers();
214 }
215 else if(!strcmp(recvbuf, "trace_setup")) {
216 DBG("trace setup");
217
218 result = ltt_trace_setup(trace_name);
219 if(result < 0) {
220 ERR("ltt_trace_setup failed");
221 return;
222 }
223
224 result = ltt_trace_set_type(trace_name, trace_type);
225 if(result < 0) {
226 ERR("ltt_trace_set_type failed");
227 return;
228 }
229 }
230 else if(!strcmp(recvbuf, "trace_alloc")) {
231 DBG("trace alloc");
232
233 result = ltt_trace_alloc(trace_name);
234 if(result < 0) {
235 ERR("ltt_trace_alloc failed");
236 return;
237 }
238 }
239 else if(!strcmp(recvbuf, "trace_start")) {
240 DBG("trace start");
241
242 result = ltt_trace_start(trace_name);
243 if(result < 0) {
244 ERR("ltt_trace_start failed");
245 continue;
246 }
247 }
248 else if(!strcmp(recvbuf, "trace_stop")) {
249 DBG("trace stop");
250
251 result = ltt_trace_stop(trace_name);
252 if(result < 0) {
253 ERR("ltt_trace_stop failed");
254 return;
255 }
256 }
257 else if(!strcmp(recvbuf, "trace_destroy")) {
258
259 DBG("trace destroy");
260
261 result = ltt_trace_destroy(trace_name);
262 if(result < 0) {
263 ERR("ltt_trace_destroy failed");
264 return;
265 }
266 }
267 else if(nth_token_is(recvbuf, "get_shmid", 0) == 1) {
268 struct ltt_trace_struct *trace;
269 char trace_name[] = "auto";
270 int i;
271 char *channel_name;
272
273 DBG("get_shmid");
274
275 channel_name = nth_token(recvbuf, 1);
276 if(channel_name == NULL) {
277 ERR("get_shmid: cannot parse channel");
278 goto next_cmd;
279 }
280
281 ltt_lock_traces();
282 trace = _ltt_trace_find(trace_name);
283 ltt_unlock_traces();
284
285 if(trace == NULL) {
286 CPRINTF("cannot find trace!");
287 return 1;
288 }
289
290 for(i=0; i<trace->nr_channels; i++) {
291 struct rchan *rchan = trace->channels[i].trans_channel_data;
292 struct rchan_buf *rbuf = rchan->buf;
293
294 if(!strcmp(trace->channels[i].channel_name, channel_name)) {
295 char *reply;
296
297 DBG("the shmid for the requested channel is %d", rbuf->shmid);
298 asprintf(&reply, "%d", rbuf->shmid);
299
300 result = ustcomm_send_reply(&ustcomm_app.server, reply, &src);
301 if(result) {
302 ERR("listener: get_shmid: ustcomm_send_reply failed");
303 goto next_cmd;
304 }
305
306 free(reply);
307
308 break;
309 }
310 }
311 }
312 else if(nth_token_is(recvbuf, "get_n_subbufs", 0) == 1) {
313 struct ltt_trace_struct *trace;
314 char trace_name[] = "auto";
315 int i;
316 char *channel_name;
317
318 DBG("get_n_subbufs");
319
320 channel_name = nth_token(recvbuf, 1);
321 if(channel_name == NULL) {
322 ERR("get_n_subbufs: cannot parse channel");
323 goto next_cmd;
324 }
325
326 ltt_lock_traces();
327 trace = _ltt_trace_find(trace_name);
328 ltt_unlock_traces();
329
330 if(trace == NULL) {
331 CPRINTF("cannot find trace!");
332 return 1;
333 }
334
335 for(i=0; i<trace->nr_channels; i++) {
336 struct rchan *rchan = trace->channels[i].trans_channel_data;
337
338 if(!strcmp(trace->channels[i].channel_name, channel_name)) {
339 char *reply;
340
341 DBG("the n_subbufs for the requested channel is %d", rchan->n_subbufs);
342 asprintf(&reply, "%d", rchan->n_subbufs);
343
344 result = ustcomm_send_reply(&ustcomm_app.server, reply, &src);
345 if(result) {
346 ERR("listener: get_n_subbufs: ustcomm_send_reply failed");
347 goto next_cmd;
348 }
349
350 free(reply);
351
352 break;
353 }
354 }
355 }
356 else if(nth_token_is(recvbuf, "get_subbuf_size", 0) == 1) {
357 struct ltt_trace_struct *trace;
358 char trace_name[] = "auto";
359 int i;
360 char *channel_name;
361
362 DBG("get_subbuf_size");
363
364 channel_name = nth_token(recvbuf, 1);
365 if(channel_name == NULL) {
366 ERR("get_subbuf_size: cannot parse channel");
367 goto next_cmd;
368 }
369
370 ltt_lock_traces();
371 trace = _ltt_trace_find(trace_name);
372 ltt_unlock_traces();
373
374 if(trace == NULL) {
375 CPRINTF("cannot find trace!");
376 return 1;
377 }
378
379 for(i=0; i<trace->nr_channels; i++) {
380 struct rchan *rchan = trace->channels[i].trans_channel_data;
381
382 if(!strcmp(trace->channels[i].channel_name, channel_name)) {
383 char *reply;
384
385 DBG("the subbuf_size for the requested channel is %d", rchan->subbuf_size);
386 asprintf(&reply, "%d", rchan->subbuf_size);
387
388 result = ustcomm_send_reply(&ustcomm_app.server, reply, &src);
389 if(result) {
390 ERR("listener: get_subbuf_size: ustcomm_send_reply failed");
391 goto next_cmd;
392 }
393
394 free(reply);
395
396 break;
397 }
398 }
399 }
400 else if(nth_token_is(recvbuf, "load_probe_lib", 0) == 1) {
401 char *libfile;
402
403 libfile = nth_token(recvbuf, 1);
404
405 DBG("load_probe_lib loading %s", libfile);
406 }
407 else if(nth_token_is(recvbuf, "get_subbuffer", 0) == 1) {
408 struct ltt_trace_struct *trace;
409 char trace_name[] = "auto";
410 int i;
411 char *channel_name;
412
413 DBG("get_subbuf");
414
415 channel_name = nth_token(recvbuf, 1);
416 if(channel_name == NULL) {
417 ERR("get_subbuf: cannot parse channel");
418 goto next_cmd;
419 }
420
421 ltt_lock_traces();
422 trace = _ltt_trace_find(trace_name);
423 ltt_unlock_traces();
424
425 if(trace == NULL) {
426 CPRINTF("cannot find trace!");
427 return 1;
428 }
429
430 for(i=0; i<trace->nr_channels; i++) {
431 struct rchan *rchan = trace->channels[i].trans_channel_data;
432
433 if(!strcmp(trace->channels[i].channel_name, channel_name)) {
434 struct rchan_buf *rbuf = rchan->buf;
435 struct ltt_channel_buf_struct *lttbuf = trace->channels[i].buf;
436 char *reply;
437 long consumed_old=0;
438
439 result = ltt_do_get_subbuf(rbuf, lttbuf, &consumed_old);
440 if(result < 0) {
441 DBG("ltt_do_get_subbuf: error: %s", strerror(-result));
442 asprintf(&reply, "%s %ld", "UNAVAIL", 0);
443 }
444 else {
445 DBG("ltt_do_get_subbuf: success");
446 asprintf(&reply, "%s %ld", "OK", consumed_old);
447 }
448
449 result = ustcomm_send_reply(&ustcomm_app.server, reply, &src);
450 if(result) {
451 ERR("listener: get_subbuf: ustcomm_send_reply failed");
452 goto next_cmd;
453 }
454
455 free(reply);
456
457 break;
458 }
459 }
460 }
461 else if(nth_token_is(recvbuf, "put_subbuffer", 0) == 1) {
462 struct ltt_trace_struct *trace;
463 char trace_name[] = "auto";
464 int i;
465 char *channel_name;
466 long consumed_old;
467 char *consumed_old_str;
468 char *endptr;
469
470 DBG("put_subbuf");
471
472 channel_name = strdup_malloc(nth_token(recvbuf, 1));
473 if(channel_name == NULL) {
474 ERR("put_subbuf_size: cannot parse channel");
475 goto next_cmd;
476 }
477
478 consumed_old_str = strdup_malloc(nth_token(recvbuf, 2));
479 if(consumed_old_str == NULL) {
480 ERR("put_subbuf: cannot parse consumed_old");
481 goto next_cmd;
482 }
483 consumed_old = strtol(consumed_old_str, &endptr, 10);
484 if(*endptr != '\0') {
485 ERR("put_subbuf: invalid value for consumed_old");
486 goto next_cmd;
487 }
488
489 ltt_lock_traces();
490 trace = _ltt_trace_find(trace_name);
491 ltt_unlock_traces();
492
493 if(trace == NULL) {
494 CPRINTF("cannot find trace!");
495 return 1;
496 }
497
498 for(i=0; i<trace->nr_channels; i++) {
499 struct rchan *rchan = trace->channels[i].trans_channel_data;
500
501 if(!strcmp(trace->channels[i].channel_name, channel_name)) {
502 struct rchan_buf *rbuf = rchan->buf;
503 struct ltt_channel_buf_struct *lttbuf = trace->channels[i].buf;
504 char *reply;
505 long consumed_old=0;
506
507 result = ltt_do_put_subbuf(rbuf, lttbuf, consumed_old);
508 if(result < 0) {
509 WARN("ltt_do_put_subbuf: error");
510 }
511 else {
512 DBG("ltt_do_put_subbuf: success");
513 }
514 asprintf(&reply, "%s", "OK", consumed_old);
515
516 result = ustcomm_send_reply(&ustcomm_app.server, reply, &src);
517 if(result) {
518 ERR("listener: put_subbuf: ustcomm_send_reply failed");
519 goto next_cmd;
520 }
521
522 free(reply);
523
524 break;
525 }
526 }
527
528 free(channel_name);
529 free(consumed_old_str);
530 }
531 else if(nth_token_is(recvbuf, "get_notifications", 0) == 1) {
532 struct ltt_trace_struct *trace;
533 char trace_name[] = "auto";
534 int i;
535 char *channel_name;
536
537 DBG("get_notifications");
538
539 channel_name = strdup_malloc(nth_token(recvbuf, 1));
540 if(channel_name == NULL) {
541 ERR("put_subbuf_size: cannot parse channel");
542 goto next_cmd;
543 }
544
545 ltt_lock_traces();
546 trace = _ltt_trace_find(trace_name);
547 ltt_unlock_traces();
548
549 if(trace == NULL) {
550 CPRINTF("cannot find trace!");
551 return 1;
552 }
553
554 for(i=0; i<trace->nr_channels; i++) {
555 struct rchan *rchan = trace->channels[i].trans_channel_data;
556 int fd;
557
558 if(!strcmp(trace->channels[i].channel_name, channel_name)) {
559 struct rchan_buf *rbuf = rchan->buf;
560 struct ltt_channel_buf_struct *lttbuf = trace->channels[i].buf;
561
562 result = fd = ustcomm_app_detach_client(&ustcomm_app, &src);
563 if(result == -1) {
564 ERR("ustcomm_app_detach_client failed");
565 goto next_cmd;
566 }
567
568 lttbuf->wake_consumer_arg = (void *) fd;
569
570 smp_wmb();
571
572 lttbuf->call_wake_consumer = 1;
573
574 break;
575 }
576 }
577
578 free(channel_name);
579 }
580 else {
581 ERR("unable to parse message: %s", recvbuf);
582 }
583
584 next_cmd:
585 free(recvbuf);
586 }
587 }
588
589 static char listener_stack[16384];
590
591 void create_listener(void)
592 {
593 int result;
594 static char listener_stack[16384];
595 //char *listener_stack = malloc(16384);
596
597 #ifdef USE_CLONE
598 result = clone(listener_main, listener_stack+sizeof(listener_stack)-1, CLONE_FS | CLONE_FILES | CLONE_VM | CLONE_SIGHAND | CLONE_THREAD, NULL);
599 if(result == -1) {
600 perror("clone");
601 }
602 #else
603 pthread_t thread;
604
605 pthread_create(&thread, NULL, listener_main, NULL);
606 #endif
607 }
608
609 /* The signal handler itself. Signals must be setup so there cannot be
610 nested signals. */
611
612 void sighandler(int sig)
613 {
614 static char have_listener = 0;
615 DBG("sighandler");
616
617 if(!have_listener) {
618 create_listener();
619 have_listener = 1;
620 }
621 }
622
623 /* Called by the app signal handler to chain it to us. */
624
625 void chain_signal(void)
626 {
627 sighandler(USTSIGNAL);
628 }
629
630 static int init_socket(void)
631 {
632 return ustcomm_init_app(getpid(), &ustcomm_app);
633 }
634
635 static void destroy_socket(void)
636 {
637 // int result;
638 //
639 // if(mysocketfile[0] == '\0')
640 // return;
641 //
642 // result = unlink(mysocketfile);
643 // if(result == -1) {
644 // PERROR("unlink");
645 // }
646 }
647
648 static int init_signal_handler(void)
649 {
650 /* Attempt to handler SIGIO. If the main program wants to
651 * handle it, fine, it'll override us. They it'll have to
652 * use the chaining function.
653 */
654
655 int result;
656 struct sigaction act;
657
658 result = sigemptyset(&act.sa_mask);
659 if(result == -1) {
660 PERROR("sigemptyset");
661 return -1;
662 }
663
664 act.sa_handler = sighandler;
665 act.sa_flags = SA_RESTART;
666
667 /* Only defer ourselves. Also, try to restart interrupted
668 * syscalls to disturb the traced program as little as possible.
669 */
670 result = sigaction(SIGIO, &act, NULL);
671 if(result == -1) {
672 PERROR("sigaction");
673 return -1;
674 }
675
676 return 0;
677 }
678
679 static void auto_probe_connect(struct marker *m)
680 {
681 int result;
682
683 result = ltt_marker_connect(m->channel, m->name, "default");
684 if(result)
685 ERR("ltt_marker_connect");
686
687 DBG("just auto connected marker %s %s to probe default", m->channel, m->name);
688 }
689
690 /* Wake the consumer of a buffer
691 *
692 * wake_consumer_cb is called in tracing context so it must haste.
693 *
694 * FIXME: don't do a system call here; maybe schedule work to be done
695 * in listener context? Once this is done in listener context, we can
696 * check for the return value of send_message_fd and remove the fd if necessary
697 *
698 * @arg: the buffer
699 * @finished: 0: subbuffer full; 1: buffer being destroyed
700 */
701
702 static void wake_consumer_cb(void *arg, int finished)
703 {
704 struct ltt_channel_buf_struct *ltt_buf = (struct ltt_channel_buf_struct *) arg;
705 int fd = (int)ACCESS_ONCE(arg);
706
707 if(!finished) {
708 send_message_fd(fd, "consume", NULL);
709 }
710 else {
711 send_message_fd(fd, "destroyed", NULL);
712 }
713 }
714
715 static void __attribute__((constructor(101))) init0()
716 {
717 DBG("UST_AUTOPROBE constructor");
718 if(getenv("UST_AUTOPROBE")) {
719 marker_set_new_marker_cb(auto_probe_connect);
720 }
721
722 relay_set_wake_consumer(wake_consumer_cb);
723 }
724
725 static void fini(void);
726
727 static void __attribute__((constructor(1000))) init()
728 {
729 int result;
730
731 DBG("UST_TRACE constructor");
732
733 /* Must create socket before signal handler to prevent races.
734 */
735 result = init_socket();
736 if(result == -1) {
737 ERR("init_socket error");
738 return;
739 }
740 result = init_signal_handler();
741 if(result == -1) {
742 ERR("init_signal_handler error");
743 return;
744 }
745
746 if(getenv("UST_TRACE")) {
747 char trace_name[] = "auto";
748 char trace_type[] = "ustrelay";
749
750 DBG("starting early tracing");
751
752 /* Ensure marker control is initialized */
753 init_marker_control();
754
755 /* Ensure relay is initialized */
756 init_ustrelay_transport();
757
758 /* Ensure markers are initialized */
759 init_markers();
760
761 /* In case. */
762 ltt_channels_register("ust");
763
764 result = ltt_trace_setup(trace_name);
765 if(result < 0) {
766 ERR("ltt_trace_setup failed");
767 return;
768 }
769
770 result = ltt_trace_set_type(trace_name, trace_type);
771 if(result < 0) {
772 ERR("ltt_trace_set_type failed");
773 return;
774 }
775
776 result = ltt_trace_alloc(trace_name);
777 if(result < 0) {
778 ERR("ltt_trace_alloc failed");
779 return;
780 }
781
782 result = ltt_trace_start(trace_name);
783 if(result < 0) {
784 ERR("ltt_trace_start failed");
785 return;
786 }
787 //start_consumer();
788 inform_consumer_daemon();
789 }
790
791
792 return;
793
794 /* should decrementally destroy stuff if error */
795
796 }
797
798 /* This is only called if we terminate normally, not with an unhandled signal,
799 * so we cannot rely on it. */
800
801 static void __attribute__((destructor)) fini()
802 {
803 int result;
804
805 /* if trace running, finish it */
806
807 DBG("destructor stopping traces");
808
809 result = ltt_trace_stop("auto");
810 if(result == -1) {
811 ERR("ltt_trace_stop error");
812 }
813
814 result = ltt_trace_destroy("auto");
815 if(result == -1) {
816 ERR("ltt_trace_destroy error");
817 }
818
819 /* FIXME: wait for the consumer to be done */
820 DBG("waiting 5 sec for consume");
821 sleep(5);
822
823 destroy_socket();
824 }
This page took 0.044413 seconds and 3 git commands to generate.