X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2Fruntime%2Fprint.c;fp=src%2Fruntime%2Fprint.c;h=e50da2ec5aaa2df376a1ec004b2acdec5bfd41b7;hb=ebb604b4422ba886e70ce2e531c1f4d28d44e721;hp=5b66b4e9af6e10445a9eac88d300e28b4da35226;hpb=0285aa5ff8416027932daa001b84429be2ca559b;p=sbcl.git diff --git a/src/runtime/print.c b/src/runtime/print.c index 5b66b4e..e50da2e 100644 --- a/src/runtime/print.c +++ b/src/runtime/print.c @@ -24,6 +24,175 @@ #include "sbcl.h" #include "print.h" #include "runtime.h" +#include +#include "thread.h" /* genesis/primitive-objects.h needs this */ +#include + +/* FSHOW and odxprint provide debugging output for low-level information + * (signal handling, exceptions, safepoints) which is hard to debug by + * other means. + * + * If enabled at all, environment variables control whether calls of the + * form odxprint(name, ...) are enabled at run-time, e.g. using + * SBCL_DYNDEBUG="fshow fshow_signal safepoints". + * + * In the case of FSHOW and FSHOW_SIGNAL, old-style code from runtime.h + * can also be used to enable or disable these more aggressively. + */ + +struct dyndebug_config dyndebug_config = { + QSHOW == 2, QSHOW_SIGNALS == 2 +}; + +void +dyndebug_init() +{ +#define DYNDEBUG_NFLAGS (sizeof(struct dyndebug_config) / sizeof(int)) +#define dyndebug_init1(lowercase, uppercase) \ + do { \ + int *ptr = &dyndebug_config.dyndebug_##lowercase; \ + ptrs[n] = ptr; \ + names[n] = #lowercase; \ + char *val = getenv("SBCL_DYNDEBUG__" uppercase); \ + *ptr = val && strlen(val); \ + n++; \ + } while (0) + int n = 0; + char *names[DYNDEBUG_NFLAGS]; + int *ptrs[DYNDEBUG_NFLAGS]; + + dyndebug_init1(fshow, "FSHOW"); + dyndebug_init1(fshow_signal, "FSHOW_SIGNAL"); + dyndebug_init1(gencgc_verbose, "GENCGC_VERBOSE"); + dyndebug_init1(safepoints, "SAFEPOINTS"); + dyndebug_init1(seh, "SEH"); + dyndebug_init1(misc, "MISC"); + dyndebug_init1(pagefaults, "PAGEFAULTS"); + + if (n != DYNDEBUG_NFLAGS) + fprintf(stderr, "Bug in dyndebug_init\n"); + + gencgc_verbose = dyndebug_config.dyndebug_gencgc_verbose; + + char *featurelist = getenv("SBCL_DYNDEBUG"); + if (featurelist) { + int err = 0; + featurelist = strdup(featurelist); + char *ptr = featurelist; + for (;;) { + char *token = strtok(ptr, " "); + if (!token) break; + unsigned i; + if (!strcmp(token, "all")) + for (i = 0; i < DYNDEBUG_NFLAGS; i++) + *ptrs[i] = 1; + else { + for (i = 0; i < DYNDEBUG_NFLAGS; i++) + if (!strcmp(token, names[i])) { + *ptrs[i] = 1; + break; + } + if (i == DYNDEBUG_NFLAGS) { + fprintf(stderr, "No such dyndebug flag: `%s'\n", token); + err = 1; + } + } + ptr = 0; + } + free(featurelist); + if (err) { + fprintf(stderr, "Valid flags are:\n"); + fprintf(stderr, " all ;enables all of the following:\n"); + unsigned i; + for (i = 0; i < DYNDEBUG_NFLAGS; i++) + fprintf(stderr, " %s\n", names[i]); + } + } + +#undef dyndebug_init1 +#undef DYNDEBUG_NFLAGS +} + +/* Temporarily, odxprint merely performs the equivalent of a traditional + * FSHOW call, i.e. it merely formats to stderr. Ultimately, it should + * be restored to its full win32 branch functionality, where output to a + * file or to the debugger can be selected at runtime. */ + +void +odxprint_fun(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vodxprint_fun(fmt, args); + va_end(args); +} + +void +vodxprint_fun(const char *fmt, va_list args) +{ +#ifdef LISP_FEATURE_WIN32 + DWORD lastError = GetLastError(); +#else + int original_errno = errno; +#endif + + QSHOW_BLOCK; + + char buf[1024]; + +#ifdef LISP_FEATURE_SB_THREAD + struct thread *arch_os_get_current_thread(void); + struct thread *self = arch_os_get_current_thread(); + void *pth = self ? (void *) self->os_thread : 0; + snprintf(buf, sizeof(buf), "[%p/%p] ", self, pth); +#endif + + int n = strlen(buf); + vsnprintf(buf + n, sizeof(buf) - n - 1, fmt, args); + /* buf is now zero-terminated (even in case of overflow). + * Our caller took care of the newline (if any) through `fmt'. */ + + /* A sufficiently POSIXy implementation of stdio will provide + * per-FILE locking, as defined in the spec for flockfile. At least + * glibc complies with this. Hence we do not need to perform + * locking ourselves here. (Should it turn out, of course, that + * other libraries opt for speed rather than safety, we need to + * revisit this decision.) */ + fputs(buf, stderr); + +#ifdef LISP_FEATURE_WIN32 + /* stdio's stderr is line-bufferred, i.e. \n ought to flush it. + * Unfortunately, MinGW does not behave the way I would expect it + * to. Let's be safe: */ + fflush(stderr); +#endif + + QSHOW_UNBLOCK; + +#ifdef LISP_FEATURE_WIN32 + SetLastError(lastError); +#else + errno = original_errno; +#endif +} + +/* Translate the rather awkward syntax + * FSHOW((stderr, "xyz")) + * into the new and cleaner + * odxprint("xyz"). + * If we were willing to clean up all existing call sites, we could remove + * this wrapper function. (This is a function, because I don't know how to + * strip the extra parens in a macro.) */ +void +fshow_fun(void __attribute__((__unused__)) *ignored, + const char *fmt, + ...) +{ + va_list args; + va_start(args, fmt); + vodxprint_fun(fmt, args); + va_end(args); +} /* This file can be skipped if we're not supporting LDB. */ #if defined(LISP_FEATURE_SB_LDB) @@ -35,7 +204,6 @@ #include "gencgc-alloc-region.h" /* genesis/thread.h needs this */ #endif #include "genesis/static-symbols.h" -#include "thread.h" /* genesis/primitive-objects.h needs this */ #include "genesis/primitive-objects.h" #include "genesis/static-symbols.h" #include "genesis/tagnames.h"