🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.windows.x
Article #37954

Re: Problem with Signals

#37954
From: der Mouse
Date: Sun, 11 Mar 1990 10:41
89 lines
3615 bytes
> 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
Technical Details
Message-ID: <9003111041.AA24486@Larry.McRCIM.McGill.EDU>
Path: arc1-ca.pugleaf.net!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

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!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