mirror of
https://github.com/gryf/wmaker.git
synced 2025-12-19 20:38:08 +01:00
fixed some signal handling bugs
This commit is contained in:
@@ -7,6 +7,10 @@ Changes since version 0.64.0:
|
||||
- added WINDOWS_MENU submenu type for root menu (Bastien Nocera <hadess@hadess.net>)
|
||||
- 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 <osam-a@astroarts.co.jp>)
|
||||
- fixed race conditions on signal handlers
|
||||
- SIGINT will gently exit, SIGTERM will not be handled
|
||||
|
||||
Changes since version 0.63.1:
|
||||
.............................
|
||||
|
||||
@@ -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:
|
||||
............................
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
TimerHandler *tmp;
|
||||
|
||||
handler = malloc(sizeof(TimerHandler));
|
||||
if (!handler)
|
||||
return NULL;
|
||||
|
||||
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 */
|
||||
@@ -162,6 +158,38 @@ 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;
|
||||
}
|
||||
|
||||
@@ -177,12 +205,18 @@ WMDeleteTimerWithClientData(void *cdata)
|
||||
|
||||
tmp = timerHandler;
|
||||
if (tmp->clientData==cdata) {
|
||||
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,13 +389,25 @@ checkTimerHandlers()
|
||||
|
||||
rightNow(&now);
|
||||
|
||||
while (timerHandler && IS_AFTER(now, timerHandler->when)) {
|
||||
handler = timerHandler;
|
||||
while (handler && IS_AFTER(now, handler->when)) {
|
||||
SET_ZERO(handler->when);
|
||||
(*handler->callback)(handler->clientData);
|
||||
handler = handler->next;
|
||||
}
|
||||
|
||||
while (timerHandler && IS_ZERO(handler->when)) {
|
||||
handler = timerHandler;
|
||||
timerHandler = timerHandler->next;
|
||||
handler->next = NULL;
|
||||
(*handler->callback)(handler->clientData);
|
||||
|
||||
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 */
|
||||
|
||||
@@ -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-*-*-*-*-*-*-*,*",
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -247,10 +247,22 @@ typedef enum {
|
||||
|
||||
|
||||
#define WCHECK_STATE(state) (state == WProgramState)
|
||||
#define WCHANGE_STATE(nstate) \
|
||||
|
||||
|
||||
#define WCHANGE_STATE(nstate) {\
|
||||
if (WProgramState == WSTATE_NORMAL\
|
||||
|| nstate != WSTATE_MODAL)\
|
||||
WProgramState = (nstate)
|
||||
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 */
|
||||
|
||||
@@ -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??",
|
||||
|
||||
@@ -138,9 +138,11 @@ int wXkbEventBase;
|
||||
#endif
|
||||
|
||||
/* special flags */
|
||||
char WProgramSigState = 0;
|
||||
char WProgramState = WSTATE_NORMAL;
|
||||
char WDelayedActionSet = 0;
|
||||
|
||||
|
||||
/* temporary stuff */
|
||||
int wVisualID = -1;
|
||||
|
||||
|
||||
150
src/startup.c
150
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,6 +240,58 @@ delayedAction(void *cdata)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
* handleExitSig--
|
||||
* User generated exit signal handler.
|
||||
*----------------------------------------------------------------------
|
||||
*/
|
||||
static RETSIGTYPE
|
||||
handleExitSig(int sig)
|
||||
{
|
||||
sigset_t sigs;
|
||||
|
||||
sigfillset(&sigs);
|
||||
sigprocmask(SIG_BLOCK, &sigs, NULL);
|
||||
|
||||
if (sig == SIGUSR1) {
|
||||
#ifdef SYS_SIGLIST_DECLARED
|
||||
wwarning(_("got signal %i (%s) - restarting\n"), sig, sys_siglist[sig]);
|
||||
#else
|
||||
wwarning(_("got signal %i - restarting\n"), sig);
|
||||
#endif
|
||||
|
||||
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 */
|
||||
WDelayedActionSet = 1;
|
||||
} else if (sig == SIGUSR2) {
|
||||
#ifdef SYS_SIGLIST_DECLARED
|
||||
wwarning(_("got signal %i (%s) - rereading defaults\n"), sig, sys_siglist[sig]);
|
||||
#else
|
||||
wwarning(_("got signal %i - rereading defaults\n"), sig);
|
||||
#endif
|
||||
|
||||
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 */
|
||||
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
|
||||
|
||||
SIG_WCHANGE_STATE(WSTATE_NEED_EXIT);
|
||||
|
||||
WDelayedActionSet = 1;
|
||||
}
|
||||
|
||||
sigprocmask(SIG_UNBLOCK, &sigs, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
*----------------------------------------------------------------------
|
||||
@@ -262,53 +316,6 @@ handleSig(int sig)
|
||||
* 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]);
|
||||
#else
|
||||
wwarning(_("got signal %i - restarting\n"), sig);
|
||||
#endif
|
||||
|
||||
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;
|
||||
} else if (sig == SIGUSR2) {
|
||||
#ifdef SYS_SIGLIST_DECLARED
|
||||
wwarning(_("got signal %i (%s) - rereading defaults\n"), sig, sys_siglist[sig]);
|
||||
#else
|
||||
wwarning(_("got signal %i - rereading defaults\n"), sig);
|
||||
#endif
|
||||
|
||||
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) {
|
||||
#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);
|
||||
|
||||
if (!WDelayedActionSet) {
|
||||
WDelayedActionSet = 1;
|
||||
WMAddIdleHandler(delayedAction, NULL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#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.
|
||||
@@ -384,18 +395,17 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user