From c6bcc344ca66aa3df643604077c64caf4284998a Mon Sep 17 00:00:00 2001 From: Ludwig Ortmann <ludwig.ortmann@fu-berlin.de> Date: Thu, 17 Jul 2014 12:55:24 +0200 Subject: [PATCH] native: uart reconnect buffer replay When using socket stdio, add option to replay what has been written to stdout while not connected (`-r`). The implementation is to simply use the existing log file (which is implicitly created when the option is used), and read from it until EOF upon reconnect. closes #476 --- boards/native/drivers/native-uart0.c | 43 +++++++++++++++++++++++++- boards/native/include/board_internal.h | 2 +- cpu/native/include/native_internal.h | 6 ++++ cpu/native/startup.c | 18 +++++++++-- cpu/native/syscalls.c | 5 +++ 5 files changed, 69 insertions(+), 5 deletions(-) diff --git a/boards/native/drivers/native-uart0.c b/boards/native/drivers/native-uart0.c index d58139aa7a..6ba53fc03c 100644 --- a/boards/native/drivers/native-uart0.c +++ b/boards/native/drivers/native-uart0.c @@ -45,6 +45,9 @@ int _native_uart_sock; int _native_uart_conn; +int _native_replay_enabled; +FILE *_native_replay_buffer; + fd_set _native_uart_rfds; /* uart API */ @@ -227,6 +230,34 @@ void handle_uart_sock(void) if (real_dup2(s, STDIN_FILENO) == -1) { err(EXIT_FAILURE, "handle_uart_sock: dup2()"); } + + /* play back log from last position */ + if (_native_replay_enabled) { + warnx("handle_uart_sock: replaying buffer"); + size_t nread; + char buf[200]; + while ((nread = real_fread(buf, 1, sizeof(buf), _native_replay_buffer)) != 0) { + int nwritten; + int pos = 0; + while ((nwritten = real_write(STDOUT_FILENO, &buf[pos], nread)) != -1) { + nread -= nwritten; + pos += nwritten; + if (nread == 0) { + break; + } + } + if (nwritten == -1) { + err(EXIT_FAILURE, "handle_uart_sock: write"); + } + } + if (real_feof(_native_replay_buffer) != 0) { + real_clearerr(_native_replay_buffer); + } + else if (real_ferror(_native_replay_buffer) != 0) { + err(EXIT_FAILURE, "handle_uart_sock(): fread()"); + } + } + _native_syscall_leave(); _native_uart_conn = s; @@ -260,8 +291,18 @@ int _native_set_uart_fds(void) } #endif -void _native_init_uart0(char *stdiotype, char *ioparam) +void _native_init_uart0(char *stdiotype, char *ioparam, int replay) { + _native_replay_enabled = replay; + + if (_native_replay_enabled) { + char stdout_logname[255]; + snprintf(stdout_logname, sizeof(stdout_logname), "/tmp/riot.stdout.%d", _native_pid); + if ((_native_replay_buffer = real_fopen(stdout_logname, "r+")) == NULL) { + err(EXIT_FAILURE, "_native_init_uart0: fdopen(_native_null_out_file)"); + } + } + if (strcmp(stdiotype, "tcp") == 0) { _native_uart_sock = init_tcp_socket(ioparam); } diff --git a/boards/native/include/board_internal.h b/boards/native/include/board_internal.h index f2cac0bfb2..a364ed24cc 100644 --- a/boards/native/include/board_internal.h +++ b/boards/native/include/board_internal.h @@ -7,7 +7,7 @@ void _native_handle_uart0_input(void); * @param stdiotype: "stdio", "tcp", "udp" io redirection * @param ioparam: a string containing a port number if stdiotype is tcp */ -void _native_init_uart0(char *stdiotype, char *ioparam); +void _native_init_uart0(char *stdiotype, char *ioparam, int replay); int _native_set_uart_fds(void); #endif diff --git a/cpu/native/include/native_internal.h b/cpu/native/include/native_internal.h index 54c38e15d8..5857516048 100644 --- a/cpu/native/include/native_internal.h +++ b/cpu/native/include/native_internal.h @@ -13,6 +13,7 @@ #define _NATIVE_INTERNAL_H #include <signal.h> +#include <stdio.h> /* enable signal handler register access on different platforms * check here for more: * http://sourceforge.net/p/predef/wiki/OperatingSystems/ @@ -54,18 +55,23 @@ void _native_syscall_enter(void); */ extern ssize_t (*real_read)(int fd, void *buf, size_t count); extern ssize_t (*real_write)(int fd, const void *buf, size_t count); +extern size_t (*real_fread)(void *ptr, size_t size, size_t nmemb, FILE *stream); extern void* (*real_malloc)(size_t size); +extern void (*real_clearerr)(FILE *stream); extern void (*real_free)(void *ptr); extern void* (*real_calloc)(size_t nmemb, size_t size); extern void* (*real_realloc)(void *ptr, size_t size); extern int (*real_getpid)(void); extern int (*real_pipe)(int[2]); extern int (*real_close)(int); +extern int (*real_feof)(FILE *stream); +extern int (*real_ferror)(FILE *stream); extern int (*real_fork)(void); extern int (*real_dup2)(int, int); extern int (*real_unlink)(const char *); extern int (*real_execve)(const char *, char *const[], char *const[]); extern int (*real_pause)(void); +extern FILE* (*real_fopen)(const char *path, const char *mode); /** * data structures diff --git a/cpu/native/startup.c b/cpu/native/startup.c index 9a70f3e3db..bc0e894c0a 100644 --- a/cpu/native/startup.c +++ b/cpu/native/startup.c @@ -161,7 +161,7 @@ void usage_exit(void) #endif #ifdef MODULE_UART0 - real_printf(" [-t <port>|-u [path]]"); + real_printf(" [-t <port>|-u [path]] [-r]"); #endif real_printf(" [-i <id>] [-d] [-e|-E] [-o]\n"); @@ -175,7 +175,9 @@ void usage_exit(void) real_printf("\ -t <port> redirect stdio to TCP socket listening on <port>\n\ -u <path> redirect stdio to UNIX socket (<path> if given,\n\ - /tmp/riot.tty.PID otherwise)\n"); + /tmp/riot.tty.PID otherwise)\n\ +-r replay missed output when (re-)attaching to socket\n\ + (implies -o)\n"); #endif real_printf("\ -i <id> specify instance id (set by config module)\n\ @@ -209,6 +211,11 @@ __attribute__((constructor)) static void startup(int argc, char **argv) *(void **)(&real_unlink) = dlsym(RTLD_NEXT, "unlink"); *(void **)(&real_execve) = dlsym(RTLD_NEXT, "execve"); *(void **)(&real_pause) = dlsym(RTLD_NEXT, "pause"); + *(void **)(&real_fopen) = dlsym(RTLD_NEXT, "fopen"); + *(void **)(&real_fread) = dlsym(RTLD_NEXT, "fread"); + *(void **)(&real_feof) = dlsym(RTLD_NEXT, "feof"); + *(void **)(&real_ferror) = dlsym(RTLD_NEXT, "ferror"); + *(void **)(&real_clearerr) = dlsym(RTLD_NEXT, "clearerr"); _native_argv = argv; _progname = argv[0]; @@ -223,6 +230,7 @@ __attribute__((constructor)) static void startup(int argc, char **argv) char *stdiotype = "stdio"; #ifdef MODULE_UART0 char *ioparam = NULL; + int replay = 0; #endif #ifdef MODULE_NATIVENET @@ -274,6 +282,10 @@ __attribute__((constructor)) static void startup(int argc, char **argv) stdouttype = "file"; } #ifdef MODULE_UART0 + else if (strcmp("-r", arg) == 0) { + stdouttype = "file"; + replay = 1; + } else if (strcmp("-t", arg) == 0) { stdiotype = "tcp"; if (argp + 1 < argc) { @@ -314,7 +326,7 @@ __attribute__((constructor)) static void startup(int argc, char **argv) _native_null_in(stdiotype); #ifdef MODULE_UART0 - _native_init_uart0(stdiotype, ioparam); + _native_init_uart0(stdiotype, ioparam, replay); #endif native_hwtimer_pre_init(); diff --git a/cpu/native/syscalls.c b/cpu/native/syscalls.c index f7aba006e6..cc3abda816 100644 --- a/cpu/native/syscalls.c +++ b/cpu/native/syscalls.c @@ -50,7 +50,9 @@ extern volatile tcb_t *sched_active_thread; ssize_t (*real_read)(int fd, void *buf, size_t count); ssize_t (*real_write)(int fd, const void *buf, size_t count); +size_t (*real_fread)(void *ptr, size_t size, size_t nmemb, FILE *stream); void* (*real_malloc)(size_t size); +void (*real_clearerr)(FILE *stream); void (*real_free)(void *ptr); void* (*real_calloc)(size_t nmemb, size_t size); void* (*real_realloc)(void *ptr, size_t size); @@ -60,7 +62,10 @@ int (*real_fork)(void); int (*real_dup2)(int, int); int (*real_unlink)(const char *); int (*real_execve)(const char *, char *const[], char *const[]); +int (*real_feof)(FILE *stream); +int (*real_ferror)(FILE *stream); int (*real_pause)(void); +FILE* (*real_fopen)(const char *path, const char *mode); void _native_syscall_enter(void) { -- GitLab