1
0
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:
kojima
2001-03-14 02:54:54 +00:00
parent b85df20ba2
commit 51b1bf34b9
11 changed files with 192 additions and 108 deletions

View File

@@ -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:
.............................

View File

@@ -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:
............................

View File

@@ -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);

View File

@@ -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);

View File

@@ -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 */

View File

@@ -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-*-*-*-*-*-*-*,*",

View File

@@ -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;
}

View File

@@ -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 */

View File

@@ -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??",

View File

@@ -138,9 +138,11 @@ int wXkbEventBase;
#endif
/* special flags */
char WProgramSigState = 0;
char WProgramState = WSTATE_NORMAL;
char WDelayedActionSet = 0;
/* temporary stuff */
int wVisualID = -1;

View File

@@ -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);