Path: utzoo!censor!geac!torsqnt!jarvis.csri.toronto.edu!mailrus!uwm.edu!zaphod.mps.ohio-state.edu!usc!snorkelwacker!bloom-beacon!LARRY.MCRCIM.MCGILL.EDU!mouse From: mouse@LARRY.MCRCIM.MCGILL.EDU (der Mouse) Newsgroups: comp.windows.x Subject: Re: Problem with Signals Message-ID: <9003111041.AA24486@Larry.McRCIM.McGill.EDU> Date: 11 Mar 90 10:41:19 GMT Sender: daemon@athena.mit.edu (Mr Background) Organization: The Internet Lines: 89 > I've been thinking a little about this problem [races in signal > delivery] and had the following idea: > Boolean sigSet[MAX_SIGNALS]; > static struct timeval pollTimeout = { 0, 0 }; > static struct timeval *timeoutPtr; > static fd_set *inputSetPtr; > > void SetSignalFlag (sig) > { > sigSet[sig] = TRUE; > timeoutPtr = &pollTimeout; > } > > SuperLoop() > { > while (whatever) > { > timeoutPtr = NextTimeoutTime(); > (1) UnblockSignals(); > nready = select (NOFILE, inputSetPtr, 0, 0, timeoutPtr); > (2) BlockSignals(); > ExecuteRunnableThreads(); > } > } > So the question is, will the select always return with EINTR or after > a polling call? Of course it doesn't deliver true async execution > because it assumes that all you do is set the flag in the interrupt > handler, but does it eliminate the race condition (does it *always* > prevent the select call from hanging indefinitely given no scheduled > timeouts)? Do I *always* get what I want no matter what point the > signal or signals hit between (1) and (2) ? Alas, no. If a signal arrives after the last argument to select has been pushed on the stack (I'm assuming a stack-based argument passing scheme, which is common enough to be reasonable) but before select has been called, you'll lose. (Or, if possible, after select has been called but before it's entered the kernel.) Suggested fix: Boolean sigSet[MAX_SIGNALS]; static struct timeval pollTimeout = { 0, 0 }; static struct timeval timeoutValue; static fd_set *inputSetPtr; void SetSignalFlag (sig) { sigSet[sig] = TRUE; timeoutValue = pollTimeout; } SuperLoop() { while (whatever) { timeoutValue = NextTimeoutTime(); UnblockSignals(); nready = select (NOFILE, inputSetPtr, 0, 0, &timeoutValue); BlockSignals(); ExecuteRunnableThreads(); } } That is, instead of changing the pointer, change the value pointed to. (I have assumed your C supports structure assignment and I've also changed the return value of NextTimeoutTime from struct timeval * to plain struct timeval.) This works because the pointer is not followed until select() is inside the kernel and signals have therefore been (implicitly) blocked. This doesn't work if you have a (hypothetical, as far as I know) select that returns the remaining time in the timeout time structure, and you actually use that information, because a signal can arrive after the select returns for some other reason and bash timeoutValue. But since as far as I know nobody's select actually does that yet, and therefore no code depends on it, you should be OK. Select really should take a sixth argument indicating a signal mask and also set the signal mask to that value atomically with the waiting for some file descriptor to come ready or the timeout to expire, and reset it to its previous value upon return, something like sigpause() and the current select() rolled into one. der Mouse old: mcgill-vision!mouse new: mouse@larry.mcrcim.mcgill.edu