diff options
-rw-r--r-- | lib/lib.c | 17 | ||||
-rw-r--r-- | lib/lib.h | 1 | ||||
-rw-r--r-- | lib/xwrap.c | 25 | ||||
-rw-r--r-- | toys.h | 1 | ||||
-rw-r--r-- | www/code.html | 19 |
5 files changed, 56 insertions, 7 deletions
@@ -757,11 +757,24 @@ void generic_signal(int sig) toys.signal = sig; } -// Install the same handler on every signal that defaults to killing the process +void exit_signal(int sig) +{ + toys.exitval = sig|128; + xexit(); +} + +// Install the same handler on every signal that defaults to killing the +// process, and void sigatexit(void *handler) { + struct arg_list *al = xmalloc(sizeof(struct arg_list)); int i; - for (i=0; signames[i].num != SIGCHLD; i++) signal(signames[i].num, handler); + + for (i=0; signames[i].num != SIGCHLD; i++) + signal(signames[i].num, exit_signal); + al->next = toys.xexit; + al->arg = handler; + toys.xexit = al; } // Convert name to signal number. If name == NULL print names. @@ -96,6 +96,7 @@ void show_help(FILE *out); // xwrap.c void xstrncpy(char *dest, char *src, size_t size); void xstrncat(char *dest, char *src, size_t size); +void _xexit(void) noreturn; void xexit(void) noreturn; void *xmalloc(size_t size); void *xzalloc(size_t size); diff --git a/lib/xwrap.c b/lib/xwrap.c index 78103555..0b1ab8e9 100644 --- a/lib/xwrap.c +++ b/lib/xwrap.c @@ -28,13 +28,32 @@ void xstrncat(char *dest, char *src, size_t size) strcpy(dest+len, src); } +// We replaced exit(), _exit(), and atexit() with xexit(), _xexit(), and +// sigatexit(). This gives _xexit() the option to siglongjmp(toys.rebound, 1) +// instead of exiting, lets xexit() report stdout flush failures to stderr +// and change the exit code to indicate error, lets our toys.exit function +// change happen for signal exit paths and lets us remove the functions +// after we've called them. + +void _xexit(void) +{ + if (toys.rebound) siglongjmp(*toys.rebound, 1); + + _exit(toys.exitval); +} + void xexit(void) { - if (toys.rebound) longjmp(*toys.rebound, 1); + // Call toys.xexit functions in reverse order added. + while (toys.xexit) { + // This is typecasting xexit->arg to a function pointer,then calling it. + ((void (*)(void))(toys.xexit->arg))(); + + free(llist_pop(&toys.xexit)); + } if (fflush(NULL) || ferror(stdout)) if (!toys.exitval) perror_msg("write"); - - exit(toys.exitval); + _xexit(); } // Die unless we can allocate memory. @@ -113,6 +113,7 @@ extern struct toy_context { // This is at the end so toy_init() doesn't zero it. jmp_buf *rebound; // longjmp here instead of exit when do_rebound set + struct arg_list *xexit; // atexit() functions for xexit(), set by sigatexit() void *stacktop; // nested toy_exec() call count, or 0 if vforked } toys; diff --git a/www/code.html b/www/code.html index 7e15e181..c133611c 100644 --- a/www/code.html +++ b/www/code.html @@ -632,13 +632,28 @@ itoa().</p> errors, to eliminate common error checking. This prints an error message and the strerror() string for the errno encountered.</p> -<p>You can intercept this exit by assigning a setjmp/longjmp buffer to +<p>We replaced exit(), _exit(), and atexit() with xexit(), _xexit(), and +sigatexit(). This gives _xexit() the option to siglongjmp(toys.rebound, 1) +instead of exiting, lets xexit() report stdout flush failures to stderr +and change the exit code to indicate error, lets our toys.exit function +change happen for signal exit paths and lets us remove the functions +after we've called them.</p> + +<p>You can intercept our exit by assigning a setjmp/longjmp buffer to toys.rebound (set it back to zero to restore the default behavior). If you do this, cleaning up resource leaks is your problem.</p> <ul> <li><b>void xstrncpy(char *dest, char *src, size_t size)</b></li> -<li><b>void xexit(void)</b></li> +<li><p><b><p>void _xexit(void)</b></p> +<p>Calls siglongjmp(toys.rebound, 1), or else _exit(toys.exitval). This +lets you ignore errors with the NO_EXIT() macro wrapper, or intercept +them with WOULD_EXIT().</p> +<li><b><p>void xexit(void)</b></p> +<p>Calls toys.xexit functions (if any) and flushes stdout/stderr (reporting +failure to write to stdout both to stderr and in the exit code), then +calls _xexit().</p> +</li> <li><b>void *xmalloc(size_t size)</b></li> <li><b>void *xzalloc(size_t size)</b></li> <li><b>void *xrealloc(void *ptr, size_t size)</b></li> |