X-Git-Url: http://git.lttng.org./?a=blobdiff_plain;f=ltt%2Fbranches%2Fpoly%2Flttd%2Flttd.c;h=63d483b6e67b9f7946818b4f0af98272761f323d;hb=469206ed6916b3e84c0f7d5c6d8f01c19b31349c;hp=d4c198b7467abeada6dbb32499735362a3a8c7b9;hpb=617de8e1ba386cdc88a48fa096b657458c6c9bbc;p=ltt-control.git diff --git a/ltt/branches/poly/lttd/lttd.c b/ltt/branches/poly/lttd/lttd.c index d4c198b..63d483b 100644 --- a/ltt/branches/poly/lttd/lttd.c +++ b/ltt/branches/poly/lttd/lttd.c @@ -10,14 +10,34 @@ * Mathieu Desnoyers */ +#define _GNU_SOURCE +#include #include +#include #include #include #include -#include #include #include #include +#include +#include +#include +#include + +/* Relayfs IOCTL */ +#include +#include + +/* Get the next sub buffer that can be read. */ +#define RELAYFS_GET_SUBBUF _IOR(0xF4, 0x00,__u32) +/* Release the oldest reserved (by "get") sub buffer. */ +#define RELAYFS_PUT_SUBBUF _IO(0xF4, 0x01) +/* returns the number of sub buffers in the per cpu channel. */ +#define RELAYFS_GET_N_SUBBUFS _IOR(0xF4, 0x02,__u32) +/* returns the size of the sub buffers. */ +#define RELAYFS_GET_SUBBUF_SIZE _IOR(0xF4, 0x03,__u32) + enum { @@ -30,6 +50,9 @@ enum { struct fd_pair { int channel; int trace; + unsigned int n_subbufs; + unsigned int subbuf_size; + void *mmap; }; struct channel_trace_fd { @@ -40,13 +63,17 @@ struct channel_trace_fd { static char *trace_name = NULL; static char *channel_name = NULL; static int daemon_mode = 0; - +static int append_mode = 0; +static int sig_parent = 0; +volatile static int quit_program = 0; /* For signal handler */ /* Args : * * -t directory Directory name of the trace to write to. Will be created. * -c directory Root directory of the relayfs trace channels. * -d Run in background (daemon). + * -a Trace append mode. + * -s Send SIGIO to parent when ready for IO. */ void show_arguments(void) { @@ -56,6 +83,8 @@ void show_arguments(void) " It will be created.\n"); printf("-c directory Root directory of the relayfs trace channels.\n"); printf("-d Run in background (daemon).\n"); + printf("-a Append to an possibly existing trace.\n"); + printf("-s Send SIGIO to parent when ready for IO.\n"); printf("\n"); } @@ -78,22 +107,32 @@ int parse_arguments(int argc, char **argv) } } - while(argn < argc-1) { + while(argn < argc) { switch(argv[argn][0]) { case '-': switch(argv[argn][1]) { case 't': - trace_name = argv[argn+1]; - argn++; + if(argn+1 < argc) { + trace_name = argv[argn+1]; + argn++; + } break; case 'c': - channel_name = argv[argn+1]; - argn++; + if(argn+1 < argc) { + channel_name = argv[argn+1]; + argn++; + } break; case 'd': daemon_mode = 1; break; + case 'a': + append_mode = 1; + break; + case 's': + sig_parent = 1; + break; default: printf("Invalid argument '%s'.\n", argv[argn]); printf("\n"); @@ -133,6 +172,16 @@ void show_info(void) } +/* signal handling */ + +static void handler(int signo) +{ + printf("Signal %d received : exiting cleanly\n", signo); + quit_program = 1; +} + + + int open_channel_trace_pairs(char *subchannel_name, char *subtrace_name, struct channel_trace_fd *fd_pairs) { @@ -152,13 +201,15 @@ int open_channel_trace_pairs(char *subchannel_name, char *subtrace_name, return ENOENT; } - //FIXME : check if the directory already exist, and ask the user if he wants - //to append to the traces. printf("Creating trace subdirectory %s\n", subtrace_name); ret = mkdir(subtrace_name, S_IRWXU|S_IRWXG|S_IRWXO); if(ret == -1) { - perror(subtrace_name); - return -1; + if(errno == EEXIST && append_mode) { + printf("Appending to directory %s as resquested\n", subtrace_name); + } else { + perror(subtrace_name); + return -1; + } } strncpy(path_channel, subchannel_name, PATH_MAX-1); @@ -193,8 +244,48 @@ int open_channel_trace_pairs(char *subchannel_name, char *subtrace_name, printf("Entering channel subdirectory...\n"); ret = open_channel_trace_pairs(path_channel, path_trace, fd_pairs); if(ret < 0) continue; + } else if(S_ISREG(stat_buf.st_mode)) { + printf("Opening file.\n"); + + fd_pairs->pair = realloc(fd_pairs->pair, + ++fd_pairs->num_pairs * sizeof(struct fd_pair)); + + /* Open the channel in read mode */ + fd_pairs->pair[fd_pairs->num_pairs-1].channel = + open(path_channel, O_RDONLY | O_NONBLOCK); + if(fd_pairs->pair[fd_pairs->num_pairs-1].channel == -1) { + perror(path_channel); + fd_pairs->num_pairs--; + continue; + } + /* Open the trace in write mode, only append if append_mode */ + ret = stat(path_trace, &stat_buf); + if(ret == 0) { + if(append_mode) { + printf("Appending to file %s as requested\n", path_trace); + + fd_pairs->pair[fd_pairs->num_pairs-1].trace = + open(path_trace, O_WRONLY|O_APPEND, + S_IRWXU|S_IRWXG|S_IRWXO); + + if(fd_pairs->pair[fd_pairs->num_pairs-1].trace == -1) { + perror(path_trace); + } + } else { + printf("File %s exists, cannot open. Try append mode.\n", path_trace); + return -1; + } + } else { + if(errno == ENOENT) { + fd_pairs->pair[fd_pairs->num_pairs-1].trace = + open(path_trace, O_WRONLY|O_CREAT|O_EXCL, + S_IRWXU|S_IRWXG|S_IRWXO); + if(fd_pairs->pair[fd_pairs->num_pairs-1].trace == -1) { + perror(path_trace); + } + } + } } - } closedir(channel_dir); @@ -203,15 +294,214 @@ int open_channel_trace_pairs(char *subchannel_name, char *subtrace_name, } +int read_subbuffer(struct fd_pair *pair) +{ + unsigned int subbuf_index; + int err, ret; + + + err = ioctl(pair->channel, RELAYFS_GET_SUBBUF, + &subbuf_index); + printf("index : %u\n", subbuf_index); + if(err != 0) { + perror("Error in reserving sub buffer"); + ret = -EPERM; + goto get_error; + } + + err = TEMP_FAILURE_RETRY(write(pair->trace, + pair->mmap + (subbuf_index * pair->subbuf_size), + pair->subbuf_size)); + + if(err < 0) { + perror("Error in writing to file"); + ret = err; + goto write_error; + } + + +write_error: + err = ioctl(pair->channel, RELAYFS_PUT_SUBBUF); + if(err != 0) { + perror("Error in unreserving sub buffer"); + ret = -EPERM; + goto get_error; + } + +get_error: + return ret; +} + + +/* read_channels + * + * Read the realyfs channels and write them in the paired tracefiles. + * + * @fd_pairs : paired channels and trace files. + * + * returns 0 on success, -1 on error. + * + * Note that the high priority polled channels are consumed first. We then poll + * again to see if these channels are still in priority. Only when no + * high priority channel is left, we start reading low priority channels. + * + * Note that a channel is considered high priority when the buffer is almost + * full. + */ + int read_channels(struct channel_trace_fd *fd_pairs) { - return 0; + struct pollfd *pollfd; + int i,j; + int num_rdy, num_hup; + int high_prio; + int ret; + + if(fd_pairs->num_pairs <= 0) { + printf("No channel to read\n"); + goto end; + } + + /* Get the subbuf sizes and number */ + + for(i=0;inum_pairs;i++) { + struct fd_pair *pair = &fd_pairs->pair[i]; + + ret = ioctl(pair->channel, RELAYFS_GET_N_SUBBUFS, + &pair->n_subbufs); + if(ret != 0) { + perror("Error in getting the number of subbuffers"); + goto end; + } + ret = ioctl(pair->channel, RELAYFS_GET_SUBBUF_SIZE, + &pair->subbuf_size); + if(ret != 0) { + perror("Error in getting the size of the subbuffers"); + goto end; + } + } + + /* Mmap each FD */ + for(i=0;inum_pairs;i++) { + struct fd_pair *pair = &fd_pairs->pair[i]; + + pair->mmap = mmap(0, pair->subbuf_size * pair->n_subbufs, PROT_READ, + MAP_SHARED, pair->channel, 0); + if(pair->mmap == MAP_FAILED) { + perror("Mmap error"); + goto munmap; + } + } + + + /* Start polling the FD */ + + pollfd = malloc(fd_pairs->num_pairs * sizeof(struct pollfd)); + + /* Note : index in pollfd is the same index as fd_pair->pair */ + for(i=0;inum_pairs;i++) { + pollfd[i].fd = fd_pairs->pair[i].channel; + pollfd[i].events = POLLIN|POLLPRI; + } + + /* Signal the parent that ready for IO */ + if(sig_parent) kill(getppid(), SIGIO); + + while(1) { + high_prio = 0; + num_hup = 0; +#ifdef DEBUG + printf("Press a key for next poll...\n"); + char buf[1]; + read(STDIN_FILENO, &buf, 1); + printf("Next poll (polling %d fd) :\n", fd_pairs->num_pairs); +#endif //DEBUG + + /* Have we received a signal ? */ + if(quit_program) break; + + num_rdy = poll(pollfd, fd_pairs->num_pairs, -1); + if(num_rdy == -1) { + perror("Poll error"); + goto free_fd; + } + + printf("Data received\n"); + + for(i=0;inum_pairs;i++) { + switch(pollfd[i].revents) { + case POLLERR: + printf("Error returned in polling fd %d.\n", pollfd[i].fd); + num_hup++; + break; + case POLLHUP: + printf("Polling fd %d tells it has hung up.\n", pollfd[i].fd); + num_hup++; + break; + case POLLNVAL: + printf("Polling fd %d tells fd is not open.\n", pollfd[i].fd); + num_hup++; + break; + case POLLPRI: + printf("Urgent read on fd %d\n", pollfd[i].fd); + /* Take care of high priority channels first. */ + high_prio = 1; + ret |= read_subbuffer(&fd_pairs->pair[i]); + break; + } + } + /* If every FD has hung up, we end the read loop here */ + if(num_hup == fd_pairs->num_pairs) break; + + if(!high_prio) { + for(i=0;inum_pairs;i++) { + switch(pollfd[i].revents) { + case POLLIN: + /* Take care of low priority channels. */ + printf("Normal read on fd %d\n", pollfd[i].fd); + ret |= read_subbuffer(&fd_pairs->pair[i]); + break; + } + } + } + + } + +free_fd: + free(pollfd); + + /* munmap only the successfully mmapped indexes */ + i = fd_pairs->num_pairs; +munmap: + /* Munmap each FD */ + for(j=0;jpair[j]; + int err_ret; + + err_ret = munmap(pair->mmap, pair->subbuf_size * pair->n_subbufs); + if(err_ret != 0) { + perror("Error in munmap"); + } + ret |= err_ret; + } + +end: + return ret; } void close_channel_trace_pairs(struct channel_trace_fd *fd_pairs) { + int i; + int ret; + for(i=0;inum_pairs;i++) { + ret = close(fd_pairs->pair[i].channel); + if(ret == -1) perror("Close error on channel"); + ret = close(fd_pairs->pair[i].trace); + if(ret == -1) perror("Close error on trace"); + } + free(fd_pairs->pair); } int main(int argc, char ** argv) @@ -219,6 +509,7 @@ int main(int argc, char ** argv) int ret; pid_t pid; struct channel_trace_fd fd_pairs = { NULL, 0 }; + struct sigaction act; ret = parse_arguments(argc, argv); @@ -242,14 +533,25 @@ int main(int argc, char ** argv) /* else, we are the child, continue... */ } + /* Connect the signal handlers */ + act.sa_handler = handler; + act.sa_flags = 0; + sigemptyset(&(act.sa_mask)); + sigaddset(&(act.sa_mask), SIGTERM); + sigaddset(&(act.sa_mask), SIGQUIT); + sigaddset(&(act.sa_mask), SIGINT); + sigaction(SIGTERM, &act, NULL); + sigaction(SIGQUIT, &act, NULL); + sigaction(SIGINT, &act, NULL); + + //return 0; if(ret = open_channel_trace_pairs(channel_name, trace_name, &fd_pairs)) - goto end_main; + goto close_channel; ret = read_channels(&fd_pairs); +close_channel: close_channel_trace_pairs(&fd_pairs); -end_main: - return ret; }