aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2010-03-29 22:14:34 -0400
committerSteven Rostedt <rostedt@goodmis.org>2010-03-29 22:14:34 -0400
commit53c63390e822d24a2aa21ea8eca3d101658e361a (patch)
treeed635f1ff4f84bee68039965ca826a381881565d
parent59b432c2f79086082bb0e91cb8c0eaa634edd449 (diff)
trace-cmd: Terminate trace-cmd listen nicely
When killing the trace-cmd listen, it will kill all the listeners and leave the temporary per CPU data files around. This patch adds handlers (also replacing signal() with sigaction()) to allow a Ctrl^C or kill pid, to shutdown the recording nicely and create the final file before exiting. Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--trace-listen.c124
1 files changed, 114 insertions, 10 deletions
diff --git a/trace-listen.c b/trace-listen.c
index 73dc62c..e8c9ba9 100644
--- a/trace-listen.c
+++ b/trace-listen.c
@@ -71,6 +71,17 @@ static void put_temp_file(char *file)
71 71
72#define MAX_PATH 1024 72#define MAX_PATH 1024
73 73
74static void signal_setup(int sig, sighandler_t handle)
75{
76 struct sigaction action;
77
78 sigaction(sig, NULL, &action);
79 /* Make accept return EINTR */
80 action.sa_flags &= ~SA_RESTART;
81 action.sa_handler = handle;
82 sigaction(sig, &action, NULL);
83}
84
74static void delete_temp_file(const char *host, const char *port, int cpu) 85static void delete_temp_file(const char *host, const char *port, int cpu)
75{ 86{
76 char file[MAX_PATH]; 87 char file[MAX_PATH];
@@ -147,10 +158,17 @@ static void plog(const char *fmt, ...)
147static void pdie(const char *fmt, ...) 158static void pdie(const char *fmt, ...)
148{ 159{
149 va_list ap; 160 va_list ap;
161 char *str = "";
150 162
151 va_start(ap, fmt); 163 va_start(ap, fmt);
152 __plog("Error: ", fmt, ap, stderr); 164 __plog("Error: ", fmt, ap, stderr);
153 va_end(ap); 165 va_end(ap);
166 if (errno)
167 str = strerror(errno);
168 if (logfp)
169 fprintf(logfp, "\n%s\n", str);
170 else
171 fprintf(stderr, "\n%s\n", str);
154 exit(-1); 172 exit(-1);
155} 173}
156 174
@@ -166,7 +184,7 @@ static void process_udp_child(int sfd, const char *host, const char *port,
166 int n; 184 int n;
167 int once = 0; 185 int once = 0;
168 186
169 signal(SIGUSR1, finish); 187 signal_setup(SIGUSR1, finish);
170 188
171 tempfile = get_temp_file(host, port, cpu); 189 tempfile = get_temp_file(host, port, cpu);
172 fd = open(tempfile, O_WRONLY | O_TRUNC | O_CREAT, 0644); 190 fd = open(tempfile, O_WRONLY | O_TRUNC | O_CREAT, 0644);
@@ -178,6 +196,8 @@ static void process_udp_child(int sfd, const char *host, const char *port,
178 pdie("listen"); 196 pdie("listen");
179 peer_addr_len = sizeof(peer_addr); 197 peer_addr_len = sizeof(peer_addr);
180 cfd = accept(sfd, (struct sockaddr *)&peer_addr, &peer_addr_len); 198 cfd = accept(sfd, (struct sockaddr *)&peer_addr, &peer_addr_len);
199 if (cfd < 0 && errno == EINTR)
200 goto done;
181 if (cfd < 0) 201 if (cfd < 0)
182 pdie("accept"); 202 pdie("accept");
183 close(sfd); 203 close(sfd);
@@ -187,8 +207,11 @@ static void process_udp_child(int sfd, const char *host, const char *port,
187 do { 207 do {
188 /* TODO, make this copyless! */ 208 /* TODO, make this copyless! */
189 n = read(sfd, buf, page_size); 209 n = read(sfd, buf, page_size);
190 if (n < 0) 210 if (n < 0) {
211 if (errno == EINTR)
212 continue;
191 pdie("reading client"); 213 pdie("reading client");
214 }
192 if (!n) 215 if (!n)
193 break; 216 break;
194 /* UDP requires that we get the full size in one go */ 217 /* UDP requires that we get the full size in one go */
@@ -199,6 +222,7 @@ static void process_udp_child(int sfd, const char *host, const char *port,
199 write(fd, buf, n); 222 write(fd, buf, n);
200 } while (!done); 223 } while (!done);
201 224
225 done:
202 put_temp_file(tempfile); 226 put_temp_file(tempfile);
203 exit(0); 227 exit(0);
204} 228}
@@ -376,16 +400,24 @@ static void process_client(const char *node, const char *port, int fd)
376 /* Now we are ready to start reading data from the client */ 400 /* Now we are ready to start reading data from the client */
377 do { 401 do {
378 n = read(fd, buf, BUFSIZ); 402 n = read(fd, buf, BUFSIZ);
403 if (n < 0) {
404 if (errno == EINTR)
405 continue;
406 pdie("reading client");
407 }
379 t = n; 408 t = n;
380 s = 0; 409 s = 0;
381 do { 410 do {
382 s = write(ofd, buf+s, t); 411 s = write(ofd, buf+s, t);
383 if (s < 0) 412 if (s < 0) {
413 if (errno == EINTR)
414 break;
384 pdie("writing to file"); 415 pdie("writing to file");
416 }
385 t -= s; 417 t -= s;
386 s = n - t; 418 s = n - t;
387 } while (t); 419 } while (t);
388 } while (n > 0); 420 } while (n > 0 && !done);
389 421
390 /* wait a little to let our readers finish reading */ 422 /* wait a little to let our readers finish reading */
391 sleep(1); 423 sleep(1);
@@ -436,10 +468,12 @@ static int do_fork(int cfd)
436 return pid; 468 return pid;
437 } 469 }
438 470
471 signal_setup(SIGINT, finish);
472
439 return 0; 473 return 0;
440} 474}
441 475
442static void do_connection(int cfd, struct sockaddr_storage *peer_addr, 476static int do_connection(int cfd, struct sockaddr_storage *peer_addr,
443 socklen_t peer_addr_len) 477 socklen_t peer_addr_len)
444{ 478{
445 char host[NI_MAXHOST], service[NI_MAXSERV]; 479 char host[NI_MAXHOST], service[NI_MAXSERV];
@@ -448,7 +482,7 @@ static void do_connection(int cfd, struct sockaddr_storage *peer_addr,
448 482
449 ret = do_fork(cfd); 483 ret = do_fork(cfd);
450 if (ret) 484 if (ret)
451 return; 485 return ret;
452 486
453 s = getnameinfo((struct sockaddr *)peer_addr, peer_addr_len, 487 s = getnameinfo((struct sockaddr *)peer_addr, peer_addr_len,
454 host, NI_MAXHOST, 488 host, NI_MAXHOST,
@@ -461,7 +495,7 @@ static void do_connection(int cfd, struct sockaddr_storage *peer_addr,
461 plog("Error with getnameinfo: %s\n", 495 plog("Error with getnameinfo: %s\n",
462 gai_strerror(s)); 496 gai_strerror(s));
463 close(cfd); 497 close(cfd);
464 return; 498 return -1;
465 } 499 }
466 500
467 process_client(host, service, cfd); 501 process_client(host, service, cfd);
@@ -470,6 +504,63 @@ static void do_connection(int cfd, struct sockaddr_storage *peer_addr,
470 504
471 if (!debug) 505 if (!debug)
472 exit(0); 506 exit(0);
507
508 return 0;
509}
510
511static int *client_pids;
512static int saved_pids;
513static int size_pids;
514#define PIDS_BLOCK 32
515
516static void add_process(int pid)
517{
518 if (!client_pids) {
519 size_pids = PIDS_BLOCK;
520 client_pids = malloc_or_die(sizeof(*client_pids) * size_pids);
521 } else if (!(saved_pids % PIDS_BLOCK)) {
522 size_pids += PIDS_BLOCK;
523 client_pids = realloc(client_pids,
524 sizeof(*client_pids) * size_pids);
525 if (!client_pids)
526 pdie("realloc of pids");
527 }
528 client_pids[saved_pids++] = pid;
529}
530
531static void remove_process(int pid)
532{
533 int i;
534
535 for (i = 0; i < saved_pids; i++) {
536 if (client_pids[i] == pid)
537 break;
538 }
539
540 if (i == saved_pids)
541 return;
542
543 saved_pids--;
544
545 if (saved_pids == i)
546 return;
547
548 memmove(&client_pids[i], &client_pids[i+1],
549 sizeof(*client_pids) * (saved_pids - i));
550
551}
552
553static void kill_clients(void)
554{
555 int status;
556 int i;
557
558 for (i = 0; i < saved_pids; i++) {
559 kill(client_pids[i], SIGINT);
560 waitpid(client_pids[i], &status, 0);
561 }
562
563 saved_pids = 0;
473} 564}
474 565
475static void clean_up(int sig) 566static void clean_up(int sig)
@@ -480,6 +571,8 @@ static void clean_up(int sig)
480 /* Clean up any children that has started before */ 571 /* Clean up any children that has started before */
481 do { 572 do {
482 ret = waitpid(0, &status, WNOHANG); 573 ret = waitpid(0, &status, WNOHANG);
574 if (ret > 0)
575 remove_process(ret);
483 } while (ret > 0); 576 } while (ret > 0);
484} 577}
485 578
@@ -490,9 +583,10 @@ static void do_listen(char *port)
490 int sfd, s, cfd; 583 int sfd, s, cfd;
491 struct sockaddr_storage peer_addr; 584 struct sockaddr_storage peer_addr;
492 socklen_t peer_addr_len; 585 socklen_t peer_addr_len;
586 int pid;
493 587
494 if (!debug) 588 if (!debug)
495 signal(SIGCHLD, clean_up); 589 signal_setup(SIGCHLD, clean_up);
496 590
497 memset(&hints, 0, sizeof(hints)); 591 memset(&hints, 0, sizeof(hints));
498 hints.ai_family = AF_UNSPEC; 592 hints.ai_family = AF_UNSPEC;
@@ -527,12 +621,19 @@ static void do_listen(char *port)
527 621
528 do { 622 do {
529 cfd = accept(sfd, (struct sockaddr *)&peer_addr, &peer_addr_len); 623 cfd = accept(sfd, (struct sockaddr *)&peer_addr, &peer_addr_len);
624 printf("connected!\n");
625 if (cfd < 0 && errno == EINTR)
626 continue;
530 if (cfd < 0) 627 if (cfd < 0)
531 pdie("connecting"); 628 pdie("connecting");
532 629
533 do_connection(cfd, &peer_addr, peer_addr_len); 630 pid = do_connection(cfd, &peer_addr, peer_addr_len);
631 if (pid > 0)
632 add_process(pid);
534 633
535 } while (1); 634 } while (!done);
635
636 kill_clients();
536} 637}
537 638
538static void start_daemon(void) 639static void start_daemon(void)
@@ -627,6 +728,9 @@ void trace_listen(int argc, char **argv)
627 if (daemon) 728 if (daemon)
628 start_daemon(); 729 start_daemon();
629 730
731 signal_setup(SIGINT, finish);
732 signal_setup(SIGTERM, finish);
733
630 do_listen(port); 734 do_listen(port);
631 735
632 return; 736 return;