From 51b1bf34b96d8f41118b46939fb633531334e676 Mon Sep 17 00:00:00 2001 From: kojima Date: Wed, 14 Mar 2001 02:54:54 +0000 Subject: [PATCH] fixed some signal handling bugs --- ChangeLog | 4 ++ WINGs/ChangeLog | 1 + WINGs/WINGs/WINGs.h | 5 +- WINGs/WINGs/WINGsP.h | 4 +- WINGs/wevent.c | 98 ++++++++++++++++++++++++++++++--------- WINGs/wfont.c | 7 +-- WINGs/widgets.c | 6 +-- src/WindowMaker.h | 20 ++++++-- src/dialog.c | 3 +- src/main.c | 2 + src/startup.c | 128 +++++++++++++++++++++++++++------------------------ 11 files changed, 181 insertions(+), 97 deletions(-) diff --git a/ChangeLog b/ChangeLog index ccba92e0..05be18ea 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,10 @@ Changes since version 0.64.0: - added WINDOWS_MENU submenu type for root menu (Bastien Nocera ) - added kbd shortcuts for icon chooser - use Hermes in wrlib +- removed MOUSE_WS_WHEEL #defines +- fixed bug with multibyte text on libc5 systems (Osamu Ajiki ) +- fixed race conditions on signal handlers +- SIGINT will gently exit, SIGTERM will not be handled Changes since version 0.63.1: ............................. diff --git a/WINGs/ChangeLog b/WINGs/ChangeLog index 071483e1..1d27b548 100644 --- a/WINGs/ChangeLog +++ b/WINGs/ChangeLog @@ -4,6 +4,7 @@ Changes since wmaker 0.64.0: - made programmatic scroller changes send notifications - replaced WMSetBoxExpandsToParent with WMSetViewExpands... - added WMGetLabelFont() +- added WMAddEternalTimerHandler() changes since wmaker 0.63.1: ............................ diff --git a/WINGs/WINGs/WINGs.h b/WINGs/WINGs/WINGs.h index af6a6ec1..e358292f 100644 --- a/WINGs/WINGs/WINGs.h +++ b/WINGs/WINGs/WINGs.h @@ -604,7 +604,7 @@ char *WMGetApplicationName(); char *WMPathForResourceOfType(char *resource, char *ext); -WMScreen *WMOpenScreen(); +WMScreen *WMOpenScreen(const char *display); WMScreen *WMCreateScreenWithRContext(Display *display, int screen, RContext *context); @@ -658,6 +658,9 @@ void WMMaskEvent(Display *dpy, long mask, XEvent *event); WMHandlerID WMAddTimerHandler(int milliseconds, WMCallback *callback, void *cdata); +WMHandlerID WMAddEternalTimerHandler(int milliseconds, WMCallback *callback, + void *cdata); + void WMDeleteTimerWithClientData(void *cdata); void WMDeleteTimerHandler(WMHandlerID handlerID); diff --git a/WINGs/WINGs/WINGsP.h b/WINGs/WINGs/WINGsP.h index 24caa833..8dde6f18 100644 --- a/WINGs/WINGs/WINGsP.h +++ b/WINGs/WINGs/WINGsP.h @@ -528,9 +528,9 @@ void W_HandleSelectionEvent(XEvent *event); void W_HandleDNDClientMessage(WMView *toplevel, XClientMessageEvent *event); -void W_FlushASAPNotificationQueue(); +void W_FlushASAPNotificationQueue(void); -void W_FlushIdleNotificationQueue(); +void W_FlushIdleNotificationQueue(void); struct W_Balloon *W_CreateBalloon(WMScreen *scr); diff --git a/WINGs/wevent.c b/WINGs/wevent.c index 201f3e02..89d4df5c 100644 --- a/WINGs/wevent.c +++ b/WINGs/wevent.c @@ -38,6 +38,7 @@ typedef struct TimerHandler { struct timeval when; /* when to call the callback */ void *clientData; struct TimerHandler *next; + Bool permanent; } TimerHandler; @@ -125,6 +126,9 @@ rightNow(struct timeval *tv) { (((t1).tv_sec == (t2).tv_sec) \ && ((t1).tv_usec > (t2).tv_usec))) +#define IS_ZERO(tv) (tv.tv_sec == 0 && tv.tv_usec == 0) + +#define SET_ZERO(tv) tv.tv_sec = 0, tv.tv_usec = 0 static void addmillisecs(struct timeval *tv, int milliseconds) @@ -136,19 +140,11 @@ addmillisecs(struct timeval *tv, int milliseconds) } -WMHandlerID -WMAddTimerHandler(int milliseconds, WMCallback *callback, void *cdata) +static void +enqueueTimerHandler(TimerHandler *handler) { - TimerHandler *handler, *tmp; - - handler = malloc(sizeof(TimerHandler)); - if (!handler) - return NULL; + TimerHandler *tmp; - rightNow(&handler->when); - addmillisecs(&handler->when, milliseconds); - handler->callback = callback; - handler->clientData = cdata; /* insert callback in queue, sorted by time left */ if (!timerHandler || !IS_AFTER(handler->when, timerHandler->when)) { /* first in the queue */ @@ -161,7 +157,39 @@ WMAddTimerHandler(int milliseconds, WMCallback *callback, void *cdata) } handler->next = tmp->next; tmp->next = handler; - } + } +} + + +WMHandlerID +WMAddTimerHandler(int milliseconds, WMCallback *callback, void *cdata) +{ + TimerHandler *handler; + + handler = malloc(sizeof(TimerHandler)); + if (!handler) + return NULL; + + rightNow(&handler->when); + addmillisecs(&handler->when, milliseconds); + handler->callback = callback; + handler->clientData = cdata; + handler->permanent = False; + + enqueueTimerHandler(handler); + + return handler; +} + + +WMHandlerID +WMAddEternalTimerHandler(int milliseconds, WMCallback *callback, void *cdata) +{ + TimerHandler *handler = WMAddTimerHandler(milliseconds, callback, cdata); + + if (handler != NULL) + handler->permanent = True; + return handler; } @@ -174,15 +202,21 @@ WMDeleteTimerWithClientData(void *cdata) if (!cdata || !timerHandler) return; - + tmp = timerHandler; if (tmp->clientData==cdata) { - timerHandler = tmp->next; - wfree(tmp); + tmp->permanent = False; + if (!IS_ZERO(tmp->when)) { + timerHandler = tmp->next; + wfree(tmp); + } } else { while (tmp->next) { if (tmp->next->clientData==cdata) { handler = tmp->next; + handler->permanent = False; + if (IS_ZERO(handler->when)) + break; tmp->next = handler->next; wfree(handler); break; @@ -203,6 +237,12 @@ WMDeleteTimerHandler(WMHandlerID handlerID) return; tmp = timerHandler; + + handler->permanent = False; + + if (IS_ZERO(handler->when)) + return; + if (tmp==handler) { timerHandler = handler->next; wfree(handler); @@ -241,7 +281,6 @@ WMAddIdleHandler(WMCallback *callback, void *cdata) } - void WMDeleteIdleHandler(WMHandlerID handlerID) { @@ -306,6 +345,7 @@ checkIdleHandlers() WMBag *handlerCopy; WMBagIterator iter; + if (!idleHandler || WMGetBagItemCount(idleHandler)==0) { W_FlushIdleNotificationQueue(); /* make sure an observer in queue didn't added an idle handler */ @@ -349,14 +389,26 @@ checkTimerHandlers() rightNow(&now); - while (timerHandler && IS_AFTER(now, timerHandler->when)) { - handler = timerHandler; - timerHandler = timerHandler->next; - handler->next = NULL; + handler = timerHandler; + while (handler && IS_AFTER(now, handler->when)) { + SET_ZERO(handler->when); (*handler->callback)(handler->clientData); - wfree(handler); + handler = handler->next; } + while (timerHandler && IS_ZERO(handler->when)) { + handler = timerHandler; + timerHandler = timerHandler->next; + + if (handler->permanent) { + rightNow(&handler->when); + addmillisecs(&handler->when, milliseconds); + enqueueTimerHandler(handler); + } else { + wfree(handler); + } + } + W_FlushASAPNotificationQueue(); } @@ -932,7 +984,7 @@ WMNextEvent(Display *dpy, XEvent *event) while (XPending(dpy) == 0) { /* Do idle stuff */ /* Do idle and timer stuff while there are no timer or X events */ - while (!XPending(dpy) && checkIdleHandlers()) { + while (XPending(dpy) == 0 && checkIdleHandlers()) { /* dispatch timer events */ checkTimerHandlers(); } @@ -942,7 +994,7 @@ WMNextEvent(Display *dpy, XEvent *event) * timer/idle stuff. Or we might block forever waiting for * an event that already arrived. */ - /* wait to something happen */ + /* wait for something to happen or a timer to expire */ W_WaitForEvent(dpy, 0); /* Check any expired timers */ diff --git a/WINGs/wfont.c b/WINGs/wfont.c index 9a81d662..c764dd02 100644 --- a/WINGs/wfont.c +++ b/WINGs/wfont.c @@ -42,9 +42,10 @@ generalize_xlfd (const char *xlfd) char *slant = xlfd_get_element(xlfd, 4); char *pxlsz = xlfd_get_element(xlfd, 7); - len = snprintf(NULL, 0, "%s,-*-*-%s-%s-*-*-%s-*-*-*-*-*-*-*," - "-*-*-*-*-*-*-%s-*-*-*-*-*-*-*,*", - xlfd, weight, slant, pxlsz, pxlsz); +#define Xstrlen(A) ((A)?strlen(A):0) + len = Xstrlen(xlfd)+Xstrlen(weight)+Xstrlen(slant)+Xstrlen(pxlsz)*2+50; +#undef Xstrlen + buf = wmalloc(len + 1); snprintf(buf, len + 1, "%s,-*-*-%s-%s-*-*-%s-*-*-*-*-*-*-*," "-*-*-*-*-*-*-%s-*-*-*-*-*-*-*,*", diff --git a/WINGs/widgets.c b/WINGs/widgets.c index 9a9051fc..dda50776 100644 --- a/WINGs/widgets.c +++ b/WINGs/widgets.c @@ -516,13 +516,13 @@ loadPixmaps(WMScreen *scr) WMScreen* -WMOpenScreen() +WMOpenScreen(const char *display) { - Display *dpy = XOpenDisplay(""); + Display *dpy = XOpenDisplay(display); if (!dpy) { wwarning("WINGs: could not open display %s", - XDisplayName("")); + XDisplayName(display)); return NULL; } diff --git a/src/WindowMaker.h b/src/WindowMaker.h index ca89941b..91b0e27a 100644 --- a/src/WindowMaker.h +++ b/src/WindowMaker.h @@ -247,10 +247,22 @@ typedef enum { #define WCHECK_STATE(state) (state == WProgramState) -#define WCHANGE_STATE(nstate) \ - if (WProgramState == WSTATE_NORMAL\ - || nstate != WSTATE_MODAL)\ - WProgramState = (nstate) + + +#define WCHANGE_STATE(nstate) {\ + if (WProgramState == WSTATE_NORMAL\ + || nstate != WSTATE_MODAL)\ + WProgramState = (nstate); \ + if (WProgramSigState != 0)\ + WProgramState = WProgramSigState;\ +} + + +/* only call inside signal handlers, with signals blocked */ +#define SIG_WCHANGE_STATE(nstate) {\ + WProgramSigState = (nstate);\ + WProgramState = (nstate);\ +} /* notifications */ diff --git a/src/dialog.c b/src/dialog.c index a77835a5..c61cbc82 100644 --- a/src/dialog.c +++ b/src/dialog.c @@ -1062,8 +1062,7 @@ handleLogoPush(XEvent *event, void *data) static char *msgs[] = { "Have a nice day!", "Focus follow mouse users will burn in hell!!!", - "F'ck Canada!!!!", - "F'ck Bastard Imperialists!!!", + "Mooo Canada!!!!", "Hi! My name is bobby...", "AHH! The neurotic monkeys are after me!", "WHAT YOU SAY??", diff --git a/src/main.c b/src/main.c index b53dc54d..f2861609 100644 --- a/src/main.c +++ b/src/main.c @@ -138,9 +138,11 @@ int wXkbEventBase; #endif /* special flags */ +char WProgramSigState = 0; char WProgramState = WSTATE_NORMAL; char WDelayedActionSet = 0; + /* temporary stuff */ int wVisualID = -1; diff --git a/src/startup.c b/src/startup.c index 87b64d05..224ae4a6 100644 --- a/src/startup.c +++ b/src/startup.c @@ -228,6 +228,8 @@ handleXIO(Display *xio_dpy) static void delayedAction(void *cdata) { + if (WDelatedActionSet == 0) + return; WDelayedActionSet = 0; /* * Make the event dispatcher do whatever it needs to do, @@ -238,30 +240,20 @@ delayedAction(void *cdata) } - /* *---------------------------------------------------------------------- - * handleSig-- - * general signal handler. Exits the program gently. + * handleExitSig-- + * User generated exit signal handler. *---------------------------------------------------------------------- */ static RETSIGTYPE -handleSig(int sig) +handleExitSig(int sig) { - static int already_crashed = 0; - int dumpcore = 0; -#ifndef NO_EMERGENCY_AUTORESTART - int crashAction; - char *argv[2]; - - argv[1] = NULL; -#endif + sigset_t sigs; + + sigfillset(&sigs); + sigprocmask(SIG_BLOCK, &sigs, NULL); - /* - * No functions that potentially do Xlib calls should be called from - * here. Xlib calls are not reentrant so the integrity of Xlib is - * not guaranteed if a Xlib call is made from a signal handler. - */ if (sig == SIGUSR1) { #ifdef SYS_SIGLIST_DECLARED wwarning(_("got signal %i (%s) - restarting\n"), sig, sys_siglist[sig]); @@ -269,15 +261,11 @@ handleSig(int sig) wwarning(_("got signal %i - restarting\n"), sig); #endif - WCHANGE_STATE(WSTATE_NEED_RESTART); + SIG_WCHANGE_STATE(WSTATE_NEED_RESTART); /* setup idle handler, so that this will be handled when * the select() is returned becaused of the signal, even if * there are no X events in the queue */ - if (!WDelayedActionSet) { - WDelayedActionSet = 1; - WMAddIdleHandler(delayedAction, NULL); - } - return; + WDelayedActionSet = 1; } else if (sig == SIGUSR2) { #ifdef SYS_SIGLIST_DECLARED wwarning(_("got signal %i (%s) - rereading defaults\n"), sig, sys_siglist[sig]); @@ -285,30 +273,49 @@ handleSig(int sig) wwarning(_("got signal %i - rereading defaults\n"), sig); #endif - WCHANGE_STATE(WSTATE_NEED_REREAD); + SIG_WCHANGE_STATE(WSTATE_NEED_REREAD); /* setup idle handler, so that this will be handled when * the select() is returned becaused of the signal, even if * there are no X events in the queue */ - if (!WDelayedActionSet) { - WDelayedActionSet = 1; - WMAddIdleHandler(delayedAction, NULL); - } - return; - } else if (sig == SIGTERM || sig == SIGHUP) { + WDelayedActionSet = 1; + } else if (sig == SIGINT || sig == SIGHUP) { #ifdef SYS_SIGLIST_DECLARED wwarning(_("got signal %i (%s) - exiting...\n"), sig, sys_siglist[sig]); #else wwarning(_("got signal %i - exiting...\n"), sig); #endif - WCHANGE_STATE(WSTATE_NEED_EXIT); + SIG_WCHANGE_STATE(WSTATE_NEED_EXIT); - if (!WDelayedActionSet) { - WDelayedActionSet = 1; - WMAddIdleHandler(delayedAction, NULL); - } - return; + WDelayedActionSet = 1; } + + sigprocmask(SIG_UNBLOCK, &sigs, NULL); +} + +/* + *---------------------------------------------------------------------- + * handleSig-- + * general signal handler. Exits the program gently. + *---------------------------------------------------------------------- + */ +static RETSIGTYPE +handleSig(int sig) +{ + static int already_crashed = 0; + int dumpcore = 0; +#ifndef NO_EMERGENCY_AUTORESTART + int crashAction; + char *argv[2]; + + argv[1] = NULL; +#endif + + /* + * No functions that potentially do Xlib calls should be called from + * here. Xlib calls are not reentrant so the integrity of Xlib is + * not guaranteed if a Xlib call is made from a signal handler. + */ #ifdef SYS_SIGLIST_DECLARED wfatal(_("got signal %i (%s)\n"), sig, sys_siglist[sig]); @@ -333,6 +340,10 @@ handleSig(int sig) dumpcore = 1; + /* + * Yeah, we shouldn't do this, but it's already crashed anyway :P + */ + #ifndef NO_EMERGENCY_AUTORESTART /* Close the X connection and open a new one. This is to avoid messing * Xlib because we call to Xlib functions in a signal handler. @@ -385,17 +396,16 @@ handleSig(int sig) static RETSIGTYPE -ignoreSig(int signal) -{ - return; -} - - -static RETSIGTYPE buryChild(int foo) { pid_t pid; int status; + int save_errno = errno; + sigset_t sigs; + + sigfillset(&sigs); + /* Block signals so that NotifyDeadProcess() doesn't get fux0red */ + sigprocmask(SIG_BLOCK, &sigs, NULL); /* R.I.P. */ /* If 2 or more kids exit in a small time window, before this handler gets @@ -406,15 +416,13 @@ buryChild(int foo) */ while ((pid=waitpid(-1, &status, WNOHANG))>0 || (pid<0 && errno==EINTR)) { NotifyDeadProcess(pid, WEXITSTATUS(status)); - /* - * Make sure that the kid will be buried even if there are - * no events in the X event queue - */ - if (!WDelayedActionSet) { - WDelayedActionSet = 1; - WMAddIdleHandler(delayedAction, NULL); - } } + + WDelayedActionSet = 1; + + sigprocmask(SIG_UNBLOCK, &sigs, NULL); + + errno = save_errno; } @@ -790,32 +798,34 @@ StartUp(Bool defaultScreenOnly) wCursor[WCUR_TEXT] = XCreateFontCursor(dpy, XC_xterm); /* odd name???*/ wCursor[WCUR_SELECT] = XCreateFontCursor(dpy, XC_cross); + /* signal handler stuff that gets called when a signal is caught */ + WMAddEternalTimerHandler(500, delayedAction, NULL); + /* emergency exit... */ sig_action.sa_handler = handleSig; sigemptyset(&sig_action.sa_mask); - /* Here we don't care about SA_RESTART since these signals will close - * wmaker anyway. - * -Dan */ - sig_action.sa_flags = 0; - sigaction(SIGINT, &sig_action, NULL); - sigaction(SIGTERM, &sig_action, NULL); - sigaction(SIGHUP, &sig_action, NULL); + sig_action.sa_flags = SA_RESTART; sigaction(SIGQUIT, &sig_action, NULL); sigaction(SIGSEGV, &sig_action, NULL); sigaction(SIGBUS, &sig_action, NULL); sigaction(SIGFPE, &sig_action, NULL); sigaction(SIGABRT, &sig_action, NULL); + sig_action.sa_handler = handleExitSig; + /* Here we set SA_RESTART for safety, because SIGUSR1 may not be handled * immediately. * -Dan */ sig_action.sa_flags = SA_RESTART; +/* sigaction(SIGTERM, &sig_action, NULL);*/ + sigaction(SIGINT, &sig_action, NULL); + sigaction(SIGHUP, &sig_action, NULL); sigaction(SIGUSR1, &sig_action, NULL); sigaction(SIGUSR2, &sig_action, NULL); /* ignore dead pipe */ - sig_action.sa_handler = ignoreSig; + sig_action.sa_handler = SIG_IGN; sig_action.sa_flags = SA_RESTART; sigaction(SIGPIPE, &sig_action, NULL); -- 2.11.4.GIT