From 347e00b800881e11272ad6bdc8a9d81c35c5be14 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Mon, 31 Jul 2017 15:16:17 +0200 Subject: [PATCH] Apply coding style Format code with "make fmt" (indent must be installed). --- Makefile | 11 ++ dtbuf.c | 178 ++++++++++++++-------------- dtbuf.h | 10 +- main.c | 344 +++++++++++++++++++++++++++--------------------------- time_ms.c | 15 +-- 5 files changed, 291 insertions(+), 267 deletions(-) diff --git a/Makefile b/Makefile index 4e3f26b..6f84648 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,17 @@ delay: $(OBJ) $(OBJ): dtbuf.h time_ms.h +fmt: + indent --linux-style \ + --indent-level4 \ + --no-tabs \ + --format-all-comments \ + --braces-on-if-line \ + --space-after-cast \ + *.c *.h + # fix indent breaking pointer alignment on some function signatures + find -name '*.[ch]' -exec sed -i '/^[a-z].*(.*)$$/s/ \* / */' {} ';' + clean: rm -f $(OBJ) $(OUT) diff --git a/dtbuf.c b/dtbuf.c index af8f343..f108040 100644 --- a/dtbuf.c +++ b/dtbuf.c @@ -7,109 +7,115 @@ #define DTBUF_CHUNK_PAYLOAD_SIZE 4000 struct header { - time_ms timestamp; - chunk_length data_length; + time_ms timestamp; + chunk_length data_length; }; #define DTBUF_CHUNK_SIZE (sizeof (struct header) + DTBUF_CHUNK_PAYLOAD_SIZE) -int dtbuf_init(struct dtbuf *dtbuf, size_t capacity) { - // to avoid splitting a chunk on the circular buffer boundaries, add - // (DTBUF_CHUNK_SIZE-1) bytes at the end: a chunk starting at (capacity-1) - // will still fit - dtbuf->real_capacity = capacity + DTBUF_CHUNK_SIZE - 1; - if (!(dtbuf->data = malloc(dtbuf->real_capacity))) { - return 1; - } - dtbuf->capacity = capacity; - dtbuf->head = 0; - dtbuf->tail = 0; - return 0; +int dtbuf_init(struct dtbuf *dtbuf, size_t capacity) +{ + // to avoid splitting a chunk on the circular buffer boundaries, add + // (DTBUF_CHUNK_SIZE-1) bytes at the end: a chunk starting at (capacity-1) + // will still fit + dtbuf->real_capacity = capacity + DTBUF_CHUNK_SIZE - 1; + if (!(dtbuf->data = malloc(dtbuf->real_capacity))) { + return 1; + } + dtbuf->capacity = capacity; + dtbuf->head = 0; + dtbuf->tail = 0; + return 0; } -void dtbuf_free(struct dtbuf *dtbuf) { - free(dtbuf->data); +void dtbuf_free(struct dtbuf *dtbuf) +{ + free(dtbuf->data); } -int dtbuf_is_empty(struct dtbuf *dtbuf) { - return dtbuf->head == dtbuf->tail; +int dtbuf_is_empty(struct dtbuf *dtbuf) +{ + return dtbuf->head == dtbuf->tail; } -int dtbuf_is_full(struct dtbuf *dtbuf) { - // When dtbuf->head >= dtbuf->capacity, it "cycles" (reset to 0) if and - // only if there is enough space at the start for a full chunk. - // Thus, if dtbuf->head has not cycled while it is after capacity, then the - // buffer is full. - // Else, if head >= tail, there is always enough space (by design). - // Else (if head < tail), there is enough space only if dtbuf->tail is far - // enough (ie we can put a full chunk at the start). - return dtbuf->head >= dtbuf->capacity || (dtbuf->head < dtbuf->tail - && dtbuf->tail - dtbuf->head <= - DTBUF_CHUNK_SIZE); +int dtbuf_is_full(struct dtbuf *dtbuf) +{ + // When dtbuf->head >= dtbuf->capacity, it "cycles" (reset to 0) if and + // only if there is enough space at the start for a full chunk. + // Thus, if dtbuf->head has not cycled while it is after capacity, then the + // buffer is full. + // Else, if head >= tail, there is always enough space (by design). + // Else (if head < tail), there is enough space only if dtbuf->tail is far + // enough (ie we can put a full chunk at the start). + return dtbuf->head >= dtbuf->capacity || (dtbuf->head < dtbuf->tail + && dtbuf->tail - dtbuf->head <= + DTBUF_CHUNK_SIZE); } -time_ms dtbuf_next_timestamp(struct dtbuf *dtbuf) { - struct header *header = (struct header *) &dtbuf->data[dtbuf->tail]; - return header->timestamp; +time_ms dtbuf_next_timestamp(struct dtbuf *dtbuf) +{ + struct header *header = (struct header *) &dtbuf->data[dtbuf->tail]; + return header->timestamp; } -ssize_t dtbuf_write_chunk(struct dtbuf *dtbuf, int fd_in, time_ms timestamp) { - ssize_t r; - struct header header; - // directly write to dtbuf, at the right index - int payload_index = dtbuf->head + sizeof(struct header); - if ((r = - read(fd_in, &dtbuf->data[payload_index], - DTBUF_CHUNK_PAYLOAD_SIZE)) > 0) { - // write headers - header.timestamp = timestamp; - header.data_length = (chunk_length) r; - memcpy(&dtbuf->data[dtbuf->head], &header, sizeof(header)); - dtbuf->head = payload_index + r; - if (dtbuf->head >= dtbuf->capacity && dtbuf->tail >= DTBUF_CHUNK_SIZE) { - // not enough space at the end of the buffer, cycle if there is enough - // at the start - dtbuf->head = 0; +ssize_t dtbuf_write_chunk(struct dtbuf *dtbuf, int fd_in, time_ms timestamp) +{ + ssize_t r; + struct header header; + // directly write to dtbuf, at the right index + int payload_index = dtbuf->head + sizeof(struct header); + if ((r = read(fd_in, &dtbuf->data[payload_index], + DTBUF_CHUNK_PAYLOAD_SIZE)) > 0) { + // write headers + header.timestamp = timestamp; + header.data_length = (chunk_length) r; + memcpy(&dtbuf->data[dtbuf->head], &header, sizeof(header)); + dtbuf->head = payload_index + r; + if (dtbuf->head >= dtbuf->capacity && dtbuf->tail >= DTBUF_CHUNK_SIZE) { + // not enough space at the end of the buffer, cycle if there is + // enough at the start + dtbuf->head = 0; + } + } else if (r == -1) { + perror("read()"); } - } else if (r == -1) { - perror("read()"); - } - return r; + return r; } -ssize_t dtbuf_read_chunk(struct dtbuf * dtbuf, int fd_out) { - ssize_t w; - struct header *pheader = (struct header *) &dtbuf->data[dtbuf->tail]; - struct header header; - chunk_length length = pheader->data_length; - // directly read from dtbuf, at the right index - int payload_index = dtbuf->tail + sizeof(struct header); - if ((w = write(fd_out, &dtbuf->data[payload_index], length)) > 0) { - if (w == length) { - // we succeed to write all the data - dtbuf->tail = payload_index + w; - if (dtbuf->tail >= dtbuf->capacity) { - // the next chunk cannot be after capacity - dtbuf->tail = 0; - if (dtbuf->head >= dtbuf->capacity) { - // can happen if capacity < DTBUF_CHUNK_SIZE - dtbuf->head = 0; +ssize_t dtbuf_read_chunk(struct dtbuf *dtbuf, int fd_out) +{ + ssize_t w; + struct header *pheader = (struct header *) &dtbuf->data[dtbuf->tail]; + struct header header; + chunk_length length = pheader->data_length; + // directly read from dtbuf, at the right index + int payload_index = dtbuf->tail + sizeof(struct header); + if ((w = write(fd_out, &dtbuf->data[payload_index], length)) > 0) { + if (w == length) { + // we succeed to write all the data + dtbuf->tail = payload_index + w; + if (dtbuf->tail >= dtbuf->capacity) { + // the next chunk cannot be after capacity + dtbuf->tail = 0; + if (dtbuf->head >= dtbuf->capacity) { + // can happen if capacity < DTBUF_CHUNK_SIZE + dtbuf->head = 0; + } + } + } else { + dtbuf->tail += w; + // set the timestamp for writing at the new tail position + header.timestamp = pheader->timestamp; + // set the remaining length + header.data_length = length - w; + memcpy(&dtbuf->data[dtbuf->tail], &header, sizeof(header)); } - } - } else { - dtbuf->tail += w; - // set the timestamp for writing at the new tail position - header.timestamp = pheader->timestamp; - // set the remaining length - header.data_length = length - w; - memcpy(&dtbuf->data[dtbuf->tail], &header, sizeof(header)); - } - if (dtbuf->head >= dtbuf->capacity && dtbuf->tail >= DTBUF_CHUNK_SIZE) { - // there is enough space at the start now, head can cycle - dtbuf->head = 0; + if (dtbuf->head >= dtbuf->capacity && dtbuf->tail >= DTBUF_CHUNK_SIZE) { + // there is enough space at the start now, head can cycle + dtbuf->head = 0; + } + } else if (w == -1) { + perror("write()"); } - } else if (w == -1) { - perror("write()"); - } - return w; + return w; } diff --git a/dtbuf.h b/dtbuf.h index dd132d0..adb2c0f 100644 --- a/dtbuf.h +++ b/dtbuf.h @@ -22,11 +22,11 @@ typedef uint16_t chunk_length; struct dtbuf { - char *data; - size_t capacity; // expected capacity - size_t real_capacity; // capacity + DTBUF_CHUNK_SIZE - 1 - int head; // index of the next chunk - int tail; // index of the oldest chunk in memory + char *data; + size_t capacity; // expected capacity + size_t real_capacity; // capacity + DTBUF_CHUNK_SIZE - 1 + int head; // index of the next chunk + int tail; // index of the oldest chunk in memory }; // init a dtbuf structure with an expected capacity diff --git a/main.c b/main.c index 5eaf263..8be87ea 100644 --- a/main.c +++ b/main.c @@ -14,16 +14,17 @@ struct dtbuf dtbuf; // stdout is at index 0 because we will always poll it struct pollfd fds_all[] = { - { 1 /* stdout */ , POLLOUT }, - { 0 /* stdin */ , POLLIN } + {1 /* stdout */ , POLLOUT}, + {0 /* stdin */ , POLLIN} }; // default values, changed by parse_cli() int delay = 5000; // in ms size_t dtbufsize = 1024 * 1024; // in bytes -void print_syntax(char *arg0) { - fprintf(stderr, "Syntax: %s [-b ] \n", arg0); +void print_syntax(char *arg0) +{ + fprintf(stderr, "Syntax: %s [-b ] \n", arg0); } // parse command: delay [-b ] @@ -31,186 +32,191 @@ void print_syntax(char *arg0) { // - delay 5s // - delay -b 10m 4000 // - delay 4k -b 10000k -void parse_cli(int argc, char *argv[]) { +void parse_cli(int argc, char *argv[]) +{ #define SYNTAX_ERROR 9 #define OPT_NONE 0 #define OPT_DTBUFSIZE 1 #define ARG_VALUE 1 #define ARG_DTBUFSIZE (1 << 1) - int ctx = OPT_NONE; - char *arg; - int args_handled = 0; - char *garbage; - int i; - for (i = 1; i < argc; i++) { - arg = argv[i]; - handle_arg: - if (ctx == OPT_DTBUFSIZE) { - if (args_handled & ARG_DTBUFSIZE) { - // dtbufsize parameter present twice - print_syntax(argv[0]); - exit(SYNTAX_ERROR); - } - // parse dtbufsize parameter - errno = 0; - dtbufsize = strtol(arg, &garbage, 0); - if (errno) { - perror("strtol()"); - exit(10); - } - // handle modifiers for Kb, Mb and Gb - if (strcmp("k", garbage) == 0) { - dtbufsize <<= 10; - } else if (strcmp("m", garbage) == 0) { - dtbufsize <<= 20; - } else if (strcmp("g", garbage) == 0) { - dtbufsize <<= 30; - } else if (garbage[0] != '\0') { - fprintf(stderr, "dtbufsize value contains garbage: %s\n", garbage); - exit(SYNTAX_ERROR); - } - args_handled |= ARG_DTBUFSIZE; - ctx = OPT_NONE; - } else if (strncmp("-b", arg, 2) == 0) { - ctx = OPT_DTBUFSIZE; - if (strlen(&arg[2]) > 0) { - // handle "-b12" like "-b 12" - arg = &arg[2]; - goto handle_arg; // yeah, this is ugly, but straightforward! - } - } else { - if (args_handled & ARG_VALUE) { - // delay value present twice - print_syntax(argv[0]); - exit(SYNTAX_ERROR); - } - // parse delay value - errno = 0; - delay = strtol(arg, &garbage, 0); - if (errno) { - perror("strtol()"); - exit(10); - } - // handle modifiers for seconds, minutes and hours - if (strcmp("s", garbage) == 0) { - delay *= 1000; - } else if (strcmp("m", garbage) == 0) { - delay *= 60 * 1000; - } else if (strcmp("h", garbage) == 0) { - delay *= 60 * 1000 * 1000; // likely to be useless - } else if (garbage[0] != '\0') { - fprintf(stderr, "delay value contains garbage: %s\n", garbage); - exit(SYNTAX_ERROR); - } - args_handled |= ARG_VALUE; + int ctx = OPT_NONE; + char *arg; + int args_handled = 0; + char *garbage; + int i; + for (i = 1; i < argc; i++) { + arg = argv[i]; + handle_arg: + if (ctx == OPT_DTBUFSIZE) { + if (args_handled & ARG_DTBUFSIZE) { + // dtbufsize parameter present twice + print_syntax(argv[0]); + exit(SYNTAX_ERROR); + } + // parse dtbufsize parameter + errno = 0; + dtbufsize = strtol(arg, &garbage, 0); + if (errno) { + perror("strtol()"); + exit(10); + } + // handle modifiers for Kb, Mb and Gb + if (strcmp("k", garbage) == 0) { + dtbufsize <<= 10; + } else if (strcmp("m", garbage) == 0) { + dtbufsize <<= 20; + } else if (strcmp("g", garbage) == 0) { + dtbufsize <<= 30; + } else if (garbage[0] != '\0') { + fprintf(stderr, "dtbufsize value contains garbage: %s\n", + garbage); + exit(SYNTAX_ERROR); + } + args_handled |= ARG_DTBUFSIZE; + ctx = OPT_NONE; + } else if (strncmp("-b", arg, 2) == 0) { + ctx = OPT_DTBUFSIZE; + if (strlen(&arg[2]) > 0) { + // handle "-b12" like "-b 12" + arg = &arg[2]; + // yeah, this is ugly, but straightforward! + goto handle_arg; + } + } else { + if (args_handled & ARG_VALUE) { + // delay value present twice + print_syntax(argv[0]); + exit(SYNTAX_ERROR); + } + // parse delay value + errno = 0; + delay = strtol(arg, &garbage, 0); + if (errno) { + perror("strtol()"); + exit(10); + } + // handle modifiers for seconds, minutes and hours + if (strcmp("s", garbage) == 0) { + delay *= 1000; + } else if (strcmp("m", garbage) == 0) { + delay *= 60 * 1000; + } else if (strcmp("h", garbage) == 0) { + delay *= 60 * 1000 * 1000; // likely to be useless + } else if (garbage[0] != '\0') { + fprintf(stderr, "delay value contains garbage: %s\n", garbage); + exit(SYNTAX_ERROR); + } + args_handled |= ARG_VALUE; + } } - } } -int main(int argc, char *argv[]) { - int r; // returned by poll() - int fds_count; - int has_next_chunk = 0; - time_ms next_chunk_timestamp = 0; - time_ms now; - time_ms wait_delay; - // Note that stdin and stdout polling is not symetrical: we always poll - // stdout for detecting POLLERR or POLLHUP (in that case, we want to stop - // immediately), and we set POLLOUT only when we need to write. - // On the contrary, we poll stdin only when we need to read (we don't want - // to stop if we have chunks to write, even if stdin is closed). - int poll_stdin; - int pollout_stdout; - int timeout; - int in_closed = 0; - int out_closed = 0; - - parse_cli(argc, argv); - - if (dtbuf_init(&dtbuf, dtbufsize)) { - fprintf(stderr, "dtbuf initialization failed\n"); - exit(1); - } - - do { - // current time - now = get_time_ms(); - - // we want to poll stdin when we can store what we will read - poll_stdin = !in_closed && !dtbuf_is_full(&dtbuf); - - // here, out_closed is always false - // we want to pollout stdout if we have a next chunk to write now - // if we only have a next chunk to write later, we set a timeout instead - if (has_next_chunk) { - wait_delay = next_chunk_timestamp + delay - now; - if (wait_delay <= 0) { - // data to write as soon as possible - pollout_stdout = 1; - timeout = -1; - } else { - // data to write later - pollout_stdout = 0; - timeout = wait_delay; - } - } else { - // no data to write at all - pollout_stdout = 0; - timeout = -1; +int main(int argc, char *argv[]) +{ + int r; // returned by poll() + int fds_count; + int has_next_chunk = 0; + time_ms next_chunk_timestamp = 0; + time_ms now; + time_ms wait_delay; + // Note that stdin and stdout polling is not symetrical: we always poll + // stdout for detecting POLLERR or POLLHUP (in that case, we want to stop + // immediately), and we set POLLOUT only when we need to write. + // On the contrary, we poll stdin only when we need to read (we don't want + // to stop if we have chunks to write, even if stdin is closed). + int poll_stdin; + int pollout_stdout; + int timeout; + int in_closed = 0; + int out_closed = 0; + + parse_cli(argc, argv); + + if (dtbuf_init(&dtbuf, dtbufsize)) { + fprintf(stderr, "dtbuf initialization failed\n"); + exit(1); } - // we always want to poll stdout for detecting POLLERR or POLLHUP - fds_count = poll_stdin ? 2 : 1; - fds_all[0].events = pollout_stdout ? POLLOUT : 0; + do { + // current time + now = get_time_ms(); + + // we want to poll stdin when we can store what we will read + poll_stdin = !in_closed && !dtbuf_is_full(&dtbuf); + + // here, out_closed is always false + // we want to pollout stdout if we have a next chunk to write now + // if we only have a next chunk to write later, we set a timeout + // instead + if (has_next_chunk) { + wait_delay = next_chunk_timestamp + delay - now; + if (wait_delay <= 0) { + // data to write as soon as possible + pollout_stdout = 1; + timeout = -1; + } else { + // data to write later + pollout_stdout = 0; + timeout = wait_delay; + } + } else { + // no data to write at all + pollout_stdout = 0; + timeout = -1; + } - // poll() the selected fds - if ((r = poll(fds_all, fds_count, timeout)) == -1) { - perror("poll()"); - exit(3); - } + // we always want to poll stdout for detecting POLLERR or POLLHUP + fds_count = poll_stdin ? 2 : 1; + fds_all[0].events = pollout_stdout ? POLLOUT : 0; - if (r == 0) { - // timeout occurs: we need to write the next chunk to stdout - // read from dtbuf and write to stdout - if (dtbuf_read_chunk(&dtbuf, 1 /* stdout */ ) <= 0) { - out_closed = 1; - } - } else { - if (fds_all[0].revents) { - // stdout has revents - if (fds_all[0].revents & (POLLOUT | POLLHUP)) { - // read from dtbuf and write to stdout - if (dtbuf_read_chunk(&dtbuf, 1 /* stdout */ ) <= 0) { - out_closed = 1; - } - } else { - out_closed = 1; + // poll() the selected fds + if ((r = poll(fds_all, fds_count, timeout)) == -1) { + perror("poll()"); + exit(3); } - } - if (poll_stdin && fds_all[1].revents) { - // stdin has revents - if (fds_all[1].revents & (POLLIN | POLLHUP)) { - // we may have waited, get the new current time - now = get_time_ms(); - // read from stdin and write to dtbuf - if (dtbuf_write_chunk(&dtbuf, 0 /* stdin */ , now) <= 0) { - in_closed = 1; - } + + if (r == 0) { + // timeout occurs: we need to write the next chunk to stdout + // read from dtbuf and write to stdout + if (dtbuf_read_chunk(&dtbuf, 1 /* stdout */ ) <= 0) { + out_closed = 1; + } } else { - in_closed = 1; + if (fds_all[0].revents) { + // stdout has revents + if (fds_all[0].revents & (POLLOUT | POLLHUP)) { + // read from dtbuf and write to stdout + if (dtbuf_read_chunk(&dtbuf, 1 /* stdout */ ) <= 0) { + out_closed = 1; + } + } else { + out_closed = 1; + } + } + if (poll_stdin && fds_all[1].revents) { + // stdin has revents + if (fds_all[1].revents & (POLLIN | POLLHUP)) { + // we may have waited, get the new current time + now = get_time_ms(); + // read from stdin and write to dtbuf + if (dtbuf_write_chunk(&dtbuf, 0 /* stdin */ , now) <= 0) { + in_closed = 1; + } + } else { + in_closed = 1; + } + } } - } - } - // update next_chunk state - has_next_chunk = !dtbuf_is_empty(&dtbuf); - if (has_next_chunk) { - next_chunk_timestamp = dtbuf_next_timestamp(&dtbuf); - } - // always stop on out_closed - // also stop when there will be no more chunks anymore - } while (!out_closed && (!in_closed || has_next_chunk)); + // update next_chunk state + has_next_chunk = !dtbuf_is_empty(&dtbuf); + if (has_next_chunk) { + next_chunk_timestamp = dtbuf_next_timestamp(&dtbuf); + } + // always stop on out_closed + // also stop when there will be no more chunks anymore + } while (!out_closed && (!in_closed || has_next_chunk)); - dtbuf_free(&dtbuf); - return 0; + dtbuf_free(&dtbuf); + return 0; } diff --git a/time_ms.c b/time_ms.c index 049f7a7..4230077 100644 --- a/time_ms.c +++ b/time_ms.c @@ -3,11 +3,12 @@ #include #include "time_ms.h" -time_ms get_time_ms() { - struct timeval timeval; - if (gettimeofday(&timeval, NULL)) { - perror("gettimeofday()"); - exit(42); - } - return timeval.tv_sec * 1000 + timeval.tv_usec / 1000; +time_ms get_time_ms() +{ + struct timeval timeval; + if (gettimeofday(&timeval, NULL)) { + perror("gettimeofday()"); + exit(42); + } + return timeval.tv_sec * 1000 + timeval.tv_usec / 1000; }