From c51453808288c394b64784940e4428710d2b5be4 Mon Sep 17 00:00:00 2001 From: Paulo Cesar Pereira de Andrade Date: Wed, 5 Dec 2007 13:06:10 -0200 Subject: [PATCH] SAVE_CONTEXT Mandriva Custom X Server patch. --- configure.ac | 19 +++ dix/dispatch.c | 43 ++++++- hw/xfree86/common/xf86Events.c | 247 ++++++++++++++++------------------ hw/xfree86/os-support/shared/sigio.c | 7 + include/dix-config.h.in | 3 + include/opaque.h | 14 ++ include/xorg-config.h.in | 3 + include/xorg-server.h.in | 6 + 8 files changed, 212 insertions(+), 130 deletions(-) diff --git a/configure.ac b/configure.ac index dfb2950..efd0055 100644 --- a/configure.ac +++ b/configure.ac @@ -467,6 +467,9 @@ AC_ARG_ENABLE(builtin-fonts, AS_HELP_STRING([--enable-builtin-fonts], [Use only AC_ARG_ENABLE(null-root-cursor, AS_HELP_STRING([--enable-null-root-cursor], [Use an empty root cursor (default: use core cursor)]), [NULL_ROOT_CURSOR=$enableval], [NULL_ROOT_CURSOR=no]) +AC_ARG_WITH(pstack, AS_HELP_STRING([--with-pstack=PATH], [Path to the pstack program (default: /usr/bin/gstack)]), + [PSTACKPATH="$withval"], + [PSTACKPATH="/usr/bin/gstack"]) dnl GLX build options AC_ARG_WITH(mesa-source, AS_HELP_STRING([--with-mesa-source=MESA_SOURCE], [Path to Mesa source tree]), @@ -542,6 +545,19 @@ dnl xprint AC_ARG_ENABLE(freetype, AS_HELP_STRING([ --enable-freetype], [Build Xprint FreeType backend (default: yes)]), [XP_USE_FREETYPE=$enableval],[XP_USE_FREETYPE=no]) AC_ARG_WITH(freetype-config, AS_HELP_STRING([ --with-freetype-config=PROG], [Use FreeType configuration program PROG (default: auto)]), freetype_config=$withval, freetype_config=auto) +dnl sigsetjmp/siglongjmp support required to try to recover from errors +AC_ARG_ENABLE(save-context, + AS_HELP_STRING([--enable-save-context], + [Save stack context to try to recover from locks and crashes (default: auto)]), + [SAVECONTEXT=$enableval], + [SAVECONTEXT=auto]) +if [ x"$SAVECONTEXT" != no ]; then + AC_CHECK_FUNC(siglongjmp, + [SAVECONTEXT=yes], + [ if test x"$SAVECONTEXT" != auto; then + AC_MSG_ERROR([Save context enabled but required functions not available]) + fi]) +fi dnl chown/chmod to be setuid root as part of build dnl Replaces InstallXserverSetUID in imake @@ -956,6 +972,7 @@ AC_DEFINE_UNQUOTED(XVENDORNAMESHORT, ["$VENDOR_NAME_SHORT"], [Short vendor name] AC_DEFINE_UNQUOTED(XORG_DATE, ["$RELEASE_DATE"], [Vendor release]) AC_DEFINE_UNQUOTED(XORG_MAN_VERSION, ["$VENDOR_MAN_VERSION"], [Vendor man version]) AC_DEFINE_UNQUOTED(BUILDERADDR, ["$BUILDERADDR"], [Builder address]) +AC_DEFINE_DIR(PSTACK_PATH, PSTACKPATH, [pstack path]) if test -z "$OSNAME"; then OSNAME="UNKNOWN" @@ -1567,6 +1584,7 @@ return 0;} AC_DEFINE_DIR(DEFAULT_LIBRARY_PATH, libdir, [Default library install path]) AC_DEFINE_DIR(DEFAULT_LOGPREFIX, LOGPREFIX, [Default log location]) AC_DEFINE_UNQUOTED(__VENDORDWEBSUPPORT__, ["$VENDOR_WEB"], [Vendor web address for support]) + AC_DEFINE(SAVE_CONTEXT, 1, [Save stack context support]) driverdir="$moduledir/drivers" AC_SUBST([moduledir]) @@ -1596,6 +1614,7 @@ AM_CONDITIONAL([XQUARTZ],[test "X$XQUARTZ" = Xyes]) AM_CONDITIONAL([DGA], [test "x$DGA" = xyes]) AM_CONDITIONAL([XF86MISC], [test "x$XF86MISC" = xyes]) AM_CONDITIONAL([XF86VIDMODE], [test "x$XF86VIDMODE" = xyes]) +AM_CONDITIONAL(SAVECONTEXT, [test "x$SAVECONTEXT" = xyes]) dnl legacy fb support test "x$MFB" = xauto && MFB="$XORG" diff --git a/dix/dispatch.c b/dix/dispatch.c index c313796..ba9a3fe 100644 --- a/dix/dispatch.c +++ b/dix/dispatch.c @@ -157,6 +157,15 @@ static void FreeRequestNames(void); #define GetRequestName(i) (RequestNames[i]) #endif +#ifdef SAVE_CONTEXT +_X_EXPORT sigjmp_buf serverJumpBuf; +_X_EXPORT sigjmp_buf clientJumpBuf; +_X_EXPORT volatile char serverException = 0; +#define _X_VOLATILE volatile +#else +#define _X_VOLATILE /**/ +#endif + #define mskcnt ((MAXCLIENTS + 31) / 32) #define BITMASK(i) (1U << ((i) & 31)) #define MASKIDX(i) ((i) >> 5) @@ -394,8 +403,8 @@ void Dispatch(void) { int *clientReady; /* array of request ready clients */ - int result; - ClientPtr client; + _X_VOLATILE int result; + _X_VOLATILE ClientPtr client; int nready; HWEventQueuePtr* icheck = checkForInput; #ifdef SMART_SCHEDULE @@ -410,6 +419,23 @@ Dispatch(void) if (!clientReady) return; +#if defined(SAVE_CONTEXT) + if (sigsetjmp(serverJumpBuf, 1) == 0) { + serverException |= SE_SERVERTRAP; + } + else { + serverException &= ~SE_SERVERTRAP; + dispatchException |= DE_TERMINATE; + dispatchExceptionAtReset |= DE_TERMINATE; + goto dispatchServerException; + } + if (sigsetjmp(clientJumpBuf, 1) != 0) { + serverException &= ~SE_CLIENTTRAP; + result = client->noClientException = BadImplementation; + goto dispatchClientException; + } +#endif + #ifdef XSERVER_DTRACE LoadRequestNames(); #endif @@ -456,6 +482,9 @@ Dispatch(void) #ifdef SMART_SCHEDULE start_tick = SmartScheduleTime; #endif +#ifdef SAVE_CONTEXT + serverException |= SE_CLIENTTRAP; +#endif while (!isItTimeToYield) { if (*icheck[0] != *icheck[1]) @@ -507,6 +536,9 @@ Dispatch(void) client->sequence, client->index, result); #endif +#ifdef SAVE_CONTEXT + dispatchClientException: +#endif if (result != Success) { if (client->noClientException != Success) @@ -522,6 +554,9 @@ Dispatch(void) #endif } FlushAllOutput(); +#ifdef SAVE_CONTEXT + serverException &= ~SE_CLIENTTRAP; +#endif #ifdef SMART_SCHEDULE client = clients[clientReady[nready]]; if (client) @@ -531,6 +566,10 @@ Dispatch(void) } dispatchException &= ~DE_PRIORITYCHANGE; } + +#if defined(SAVE_CONTEXT) +dispatchServerException: +#endif #if defined(DDXBEFORERESET) ddxBeforeReset (); #endif diff --git a/hw/xfree86/common/xf86Events.c b/hw/xfree86/common/xf86Events.c index 46fae08..35ea4e3 100644 --- a/hw/xfree86/common/xf86Events.c +++ b/hw/xfree86/common/xf86Events.c @@ -100,6 +100,11 @@ extern Bool noXkbExtension; #define XE_POINTER 1 #define XE_KEYBOARD 2 +#ifdef SAVE_CONTEXT +extern sigjmp_buf serverJumpBuf; +extern sigjmp_buf clientJumpBuf; +#endif + #define EqEnqueue(pDev, ev) { \ int __sigstate = xf86BlockSIGIO (); \ mieqEnqueue (pDev, ev); \ @@ -561,40 +566,21 @@ xf86InterceptSigIll(void (*sigillhandler)(void)) xf86SigIllHandler = sigillhandler; } -#ifdef HAVE_BACKTRACE -#include - -static __inline__ void xorg_backtrace(void) -{ - void *array[32]; /* deeper nesting than this means something's wrong */ - size_t size, i; - char **strings; - ErrorF("\nBacktrace:\n"); - size = backtrace(array, 32); - strings = backtrace_symbols(array, size); - for (i = 0; i < size; i++) - ErrorF("%d: %s\n", i, strings[i]); - free(strings); -} - -#else /* not glibc or glibc < 2.1 */ - -# if defined(sun) && defined(__SVR4) -# define HAVE_PSTACK -# endif - -# if defined(HAVE_WALKCONTEXT) /* Solaris 9 & later */ +#ifdef HAVE_BACKTRACE /* glibc >= 2.1 */ +# include +#endif -# include -# include -# include -# include +#if defined(HAVE_WALKCONTEXT) /* Solaris 9 & later */ +# include +# include +# include +# include -#ifdef _LP64 -# define ElfSym Elf64_Sym -#else -# define ElfSym Elf32_Sym -#endif +# ifdef _LP64 +# define ElfSym Elf64_Sym +# else +# define ElfSym Elf32_Sym +# endif /* Called for each frame on the stack to print it's contents */ static int xorg_backtrace_frame(uintptr_t pc, int signo, void *arg) @@ -641,99 +627,79 @@ static int xorg_backtrace_frame(uintptr_t pc, int signo, void *arg) return 0; } -# endif /* HAVE_WALKCONTEXT */ - -# ifdef HAVE_PSTACK -static int xorg_backtrace_pstack(void) { - pid_t kidpid; - int pipefd[2]; +#endif /* HAVE_WALKCONTEXT */ - if (pipe(pipefd) != 0) { - return -1; - } - - kidpid = fork1(); - - if (kidpid == -1) { - /* ERROR */ - return -1; - } else if (kidpid == 0) { - /* CHILD */ - char parent[16]; - - seteuid(0); - close(STDIN_FILENO); - close(STDOUT_FILENO); - dup2(pipefd[1],STDOUT_FILENO); - closefrom(STDERR_FILENO); - - snprintf(parent, sizeof(parent), "%d", getppid()); - execle("/usr/bin/pstack", "pstack", parent, NULL); - exit(1); - } else { - /* PARENT */ - char btline[256]; - int kidstat; - int bytesread; - int done = 0; - - close(pipefd[1]); - - while (!done) { - bytesread = read(pipefd[0], btline, sizeof(btline) - 1); - - if (bytesread > 0) { - btline[bytesread] = 0; - ErrorF("%s", btline); - } - else if ((bytesread < 0) || - ((errno != EINTR) && (errno != EAGAIN))) - done = 1; +static int +xorg_backtrace_pstack(void) +{ + char buffer[256]; + int bytes; + FILE *fp; + + if (access(PSTACK_PATH, X_OK) != 0) + return (-1); + + /* Can this deadlock? Maybe need a special Popen that makes sure fp + * is buffered and stream buffer is large enough for all backtrace */ + snprintf(buffer, sizeof(buffer), "%s %d", PSTACK_PATH, getpid()); + if ((fp = Popen(buffer, "r"))) { + while ((bytes = fread(buffer, sizeof(char), + sizeof(buffer) - 1, fp)) > 0) { + buffer[bytes] = 0; + ErrorF("%s", buffer); } - close(pipefd[0]); - waitpid(kidpid, &kidstat, 0); - if (kidstat != 0) - return -1; + return (Pclose(fp) < 0 ? -1 : 0); } - return 0; + return (-1); } -# endif /* HAVE_PSTACK */ - - -# if defined(HAVE_PSTACK) || defined(HAVE_WALKCONTEXT) static __inline__ void xorg_backtrace(void) { +#if defined(HAVE_BACKTRACE) + void *array[32]; + size_t size, i; + char **strings; + int failed = 1; +#endif ErrorF("\nBacktrace:\n"); -# ifdef HAVE_PSTACK -/* First try fork/exec of pstack - otherwise fall back to walkcontext - pstack is preferred since it can print names of non-exported functions */ +#if defined(HAVE_BACKTRACE) + /* Print this trace also even if other method did not fail */ + size = backtrace(array, 32); + strings = backtrace_symbols(array, size); + for (i = 0; i < size; i++) + ErrorF("%d: %s\n", i, strings[i]); + free(strings); + failed = 0; +#endif - if (xorg_backtrace_pstack() < 0) -# endif +#ifdef SAVE_CONTEXT + /* Don't try to fork/exec pstack if server will try to recover */ + if (!serverException & (SE_SERVERTRAP | SE_CLIENTTRAP)) +#endif { -# ifdef HAVE_WALKCONTEXT - ucontext_t u; - int depth = 1; - - if (getcontext(&u) == 0) - walkcontext(&u, xorg_backtrace_frame, &depth); + /* First try fork/exec of pstack - otherwise fall back to walkcontext + * pstack is preferred since it can print names of non-exported functions + */ + if (xorg_backtrace_pstack() < 0) + { +#if defined(HAVE_WALKCONTEXT) + ucontext_t u; + int depth = 1; + + failed = getcontext(&u) == 0; + if (!failed) + walkcontext(&u, xorg_backtrace_frame, &depth); +#endif + } else -# endif - Error("Failed to get backtrace info"); + failed = 0; } - ErrorF("\n"); + if (failed) + ErrorF("Failed to get backtrace info"); + ErrorF("\n"); } -# else - -/* Default fallback if we can't find any way to get a backtrace */ -static __inline__ void xorg_backtrace(void) { return; } - -# endif -#endif - /* * xf86SigHandler -- * Catch unexpected signals and exit or continue cleanly. @@ -741,29 +707,54 @@ static __inline__ void xorg_backtrace(void) { return; } void xf86SigHandler(int signo) { - if ((signo == SIGILL) && xf86SigIllHandler) { - (*xf86SigIllHandler)(); - /* Re-arm handler just in case we unexpectedly return here */ - (void) signal(signo, xf86SigHandler); - return; - } + if ((signo == SIGILL) && xf86SigIllHandler) { + (*xf86SigIllHandler)(); + /* Re-arm handler just in case we unexpectedly return here */ + (void) signal(signo, xf86SigHandler); + return; + } - if (xf86SignalIntercept && (*xf86SignalIntercept < 0)) { - *xf86SignalIntercept = signo; - /* Re-arm handler just in case */ - (void) signal(signo, xf86SigHandler); - return; - } + if (xf86SignalIntercept && (*xf86SignalIntercept < 0)) { + *xf86SignalIntercept = signo; + /* Re-arm handler just in case */ + (void) signal(signo, xf86SigHandler); + return; + } - signal(signo,SIG_IGN); - xf86Info.caughtSignal = TRUE; -#ifdef XF86BIGFONT - XF86BigfontCleanup(); +#ifndef SAVE_CONTEXT + signal(signo,SIG_IGN); + xf86Info.caughtSignal = TRUE; #endif - xorg_backtrace(); + xorg_backtrace(); + +#ifdef SAVE_CONTEXT + if ((serverException & SE_SERVERTRAP) && !xf86Info.dontZap) { + ErrorF("Caught signal %d. ", signo); + /* Remember crashed (at least) once as current cleanup is most likely + * to, at best, create a memory leak, if not just crashing again */ + serverException |= SE_SERVERCRASH; + if (serverException & SE_CLIENTTRAP) { + /* Try to kill client and keep running */ + ErrorF("Trying to kill client.\n"); + siglongjmp(clientJumpBuf, 1); + } + else { + ErrorF("Giving up.\n"); + xf86ProcessActionEvent(ACTION_TERMINATE, NULL); + siglongjmp(serverJumpBuf, 1); + } + } + + signal(signo, SIG_IGN); + xf86Info.caughtSignal = TRUE; +#endif + +#ifdef XF86BIGFONT + XF86BigfontCleanup(); +#endif - FatalError("Caught signal %d. Server aborting\n", signo); + FatalError("Caught signal %d. Server aborting\n", signo); } static void diff --git a/hw/xfree86/os-support/shared/sigio.c b/hw/xfree86/os-support/shared/sigio.c index c97f503..e856a78 100644 --- a/hw/xfree86/os-support/shared/sigio.c +++ b/hw/xfree86/os-support/shared/sigio.c @@ -243,6 +243,10 @@ xf86BlockSIGIO (void) sigaddset (&set, SIGIO); sigprocmask (SIG_BLOCK, &set, &old); ret = sigismember (&old, SIGIO); +#ifdef SAVE_CONTEXT + if (ret) + serverException |= SE_SIGIOBLOCKED; +#endif return ret; } @@ -256,6 +260,9 @@ xf86UnblockSIGIO (int wasset) sigemptyset (&set); sigaddset (&set, SIGIO); sigprocmask (SIG_UNBLOCK, &set, NULL); +#ifdef SAVE_CONTEXT + serverException &= ~SE_SIGIOBLOCKED; +#endif } } diff --git a/include/dix-config.h.in b/include/dix-config.h.in index 69fab5e..a8395b4 100644 --- a/include/dix-config.h.in +++ b/include/dix-config.h.in @@ -504,4 +504,7 @@ /* Define to 64-bit byteswap macro */ #undef bswap_64 +/* Save stack context support */ +#undef SAVE_CONTEXT + #endif /* _DIX_CONFIG_H_ */ diff --git a/include/opaque.h b/include/opaque.h index 3d19d27..4957452 100644 --- a/include/opaque.h +++ b/include/opaque.h @@ -44,6 +44,20 @@ extern volatile char dispatchException; #define DE_TERMINATE 2 #define DE_PRIORITYCHANGE 4 /* set when a client's priority changes */ +#ifdef SAVE_CONTEXT +#include +/* bit values for serverException */ +#define SE_SERVERTRAP 1 /* In main dispatch loop */ +#define SE_CLIENTTRAP 2 /* Handling a client request */ +#define SE_SERVERLOCK 4 /* Server interrupted at least once */ +#define SE_SERVERCRASH 8 /* Server crashed at least once */ +#define SE_SIGIOBLOCKED 128 /* In case keyboard is modified to + * use a method other than SIGIO */ +extern sigjmp_buf serverJumpBuf; +extern sigjmp_buf clientJumpBuf; +extern volatile char serverException; +#endif + extern CARD32 TimeOutValue; extern int ScreenSaverBlanking; extern int ScreenSaverAllowExposures; diff --git a/include/xorg-config.h.in b/include/xorg-config.h.in index b9643a2..06c8a91 100644 --- a/include/xorg-config.h.in +++ b/include/xorg-config.h.in @@ -115,4 +115,7 @@ /* Have execinfo.h */ #undef HAVE_EXECINFO_H +/* pstack path */ +#undef PSTACK_PATH + #endif /* _XORG_CONFIG_H_ */ diff --git a/include/xorg-server.h.in b/include/xorg-server.h.in index 3c2ff47..6652d28 100644 --- a/include/xorg-server.h.in +++ b/include/xorg-server.h.in @@ -82,6 +82,12 @@ /* Support X resource extension */ #undef RES +/* Save stack context support */ +#undef SAVE_CONTEXT + +/* pstack path */ +#undef PSTACK_PATH + /* Support MIT-SCREEN-SAVER extension */ #undef SCREENSAVER -- 1.5.4.3