jcarson@WILKINS.BCM.TMC.EDU (Janet L. Carson) (03/01/90)
I've been watching the "problem with signals" thread, and I agree with Bob Scheifler that no one has really explained clearly what the problems are. I am in the process of writing a tool which is going to be an interface to FTP, and I am including a SIGPIPE error handler to handle the "connection lost" case. Where do I need to look out for problems? Thanks for any info, --Janet Janet L. Carson internet: jcarson@bcm.tmc.edu Baylor College of Medicine uucp: {rutgers,mailrus}!bcm!jcarson
argv%turnpike@Sun.COM (Dan Heller) (03/02/90)
From: jcarson@WILKINS.BCM.TMC.EDU (Janet L. Carson) Subject: Problem with Signals I've been watching the "problem with signals" thread, and I agree with Bob Scheifler that no one has really explained clearly what the problems are. I am in the process of writing a tool which is going to be an interface to FTP, and I am including a SIGPIPE error handler to handle the "connection lost" case. Where do I need to look out for problems? Janet L. Carson internet: jcarson@bcm.tmc.edu Baylor College of Medicine uucp: {rutgers,mailrus}!bcm!jcarson The problem with signals and X is rather simple. X is asynchronous and relies on a communication between the client (application) and the server (the X server). This "protocol" is defined and implemented using Xlib. If you are putting together a packet to send over the wire to the server and a signal "interrupts" your client side application, then you have interrupted the protocol and *may* result in a protocol error with the server. You may even get a core dump. This is not guaranteed to happen, but the case becomes much more likely if your event handler attempts to make any Xlib calls (which includes many, but not all, Xt calls). Perhaps the most common case of this is the SIGALRM signal, which is delivered as a result of such things as "setitimer". Note Brian's problem below: From: envbvs@epb2.lbl.gov (Brian V. Smith) I have put patch3 to xfig2.0 on expo.lcs.mit.edu. ... Changes from patchlevel 2: o now uses XtAddTimer instead of setitimer() for blinking text cursor The reason he did this was because xfig suffered from random core dumps as a result of the timer interfering with the X protocol and attempting to "blink" the cursor by turning it off and on. As you can see, he fixed the problem by using XtAddTimeOut() to replace the use of the timer. Xt doesn't use signals to do this -- it simulates signals by simply checking the time in the main looping mechanism. Because this particular problem is solved, and because it is the most commonly utilized signal so far, many people don't perceive the fundamental problem as being that bad. However, the "fundamental problem" still exists: if you interrupt the protocol betwween the client and server, then you must be sure to return to the place in the application that was interrupted before making further attempts to communicate with the X server. Therefore, you signal handler should not display dialog boxes, make Xlib calls, or do much any anything until it is guaranteed that you are not going to interfere with a protocol exachange. So, what do you do? Well, your signal handler could be written to set a flag to note the delivery of the signal and then return so that the code being execute may continue with whatever it's doing till you know it's safe. *that* is the problem -- you never know when it's safe. And when it *is* safe, you are not in any application-specific code. There may not be any more events in the queue so that your next event handling function won't be called for quite some time. My proposed solution is to implement a routine: XtSigRet XtAddSignalHandler(signal, handler) int signal; XtSigRet (*handler)(); XtSigRet is either void or int depending on what your UNIX OS uses for signal(). When you register your signal handler for the specified signal, when the signal is delivered, *Xt* catches the signal and notes the signal context, resources, etc.. Then, when all is well with the events and protocol, etc, your handler is called. Your handler is written _exactly the same_ as it would be had you called "signal(sig, handler)" because the same parameters are passed back into the signal handler. (XtAddSignalHandler returns the previously set handler just like signal() does.) Now, you could implement this yourself via "work procs" (see XtAddWorkProc()), but the granularity isn't fine enough. That is, work procs are only called when there are no events pending. Implemented properly, the internals to Xt would check in between event delivery to event handlers. Like rws, I don't know VMS's ASTs well enough to know how this mechasnism fits in with the sceme programmatically. However, I do know that this implementation can fit in conceptually. "signal()" can be #ifdef'ed out if necessary and those systems that don't have signal() are simply unaffected since the check for nonexistent signals does nothing. That is, I envision the implementation as being: signal is delvered, Xt sets a bit in a flag indicating that the signal has been delivered. Signal number, contenxt resource usage, etc.. are saved. At appropriate time, Xt checks signal flags and see swhich signals have been delivered and calls the signal handler with appropriate parameters saved from the real signal delivery. If VMS's ASTs has similar parameters, use those, too. dan ----------------------------------------------------------- O'Reilly && Associates argv@sun.com / argv@ora.com 632 Petaluma Ave, Sebastopol, CA 95472 800-338-NUTS, in CA: 800-533-NUTS, FAX 707-829-0104 Opinions expressed reflect those of the author only.
karlton@sgi.com (Phil Karlton) (03/03/90)
This is what happened to VMS as the result of X (if memory serves me right). The LockDisplay and UnlockDisplay macro invocations that surround every Xlib routine were defined to set or clear a particular bit in the client's address space. (This is a relatively cheap operation.) Then the OS was changed so that if the bit was set the AST was not delivered to the process until the bit was cleared. This prevents the "interrupt" routines from running while a partial X request was in an I/O buffer. I am not going to hold my breath until all of the various UNIX vendors add a similar feature. One might consider merely using a different X connection for communicating with the server while in any interrupt routine. Adequate support within the intrinsics for dealing with mulitple connections and reentrancy would be necessary to make this viable for Xt based clients. PK
JONESD@kcgl1.eng.ohio-state.edu (David Jones) (03/03/90)
Instead of hacking up tookits to allow your application to add signal handlers, I'd rather see them hacked up to convert signals into client events. The application would deal with with the signal as another event to deal and not as something to be dealt with by a signal handler. David L. Jones | Phone: (614) 292-6929 Ohio State Unviversity | Internet: 1971 Neil Ave. Rm. 406 | jonesd@kcgl1.eng.ohio-state.edu Columbus, OH 43210 | jones-d@eng.ohio-state.edu Disclaimer: A repudiation of a claim.
argv%turnpike@Sun.COM (Dan Heller) (03/04/90)
In article <4429@quanta.eng.ohio-state.edu> JONESD@kcgl1.eng.ohio-state.edu (David Jones) writes: > Instead of hacking up tookits to allow your application to add signal handlers, > I'd rather see them hacked up to convert signals into client events. The > application would deal with with the signal as another event to deal and > not as something to be dealt with by a signal handler. That's fundamentally the same thing I'm talking about. That is, you register signals and handlers (functions) associated with those signals in case a signal is delivered. The toolkit then calls the function registered. However, the idea asbout converting signals into events odesn't make sense -- signals don't happen in windows [%] and they don't have x,y values or serial IDs etc.. associated with them so the generic event type can't fill in anything. Keep the signals as signals... [%] SIGWINCH is a possible exception and an interesting case.. altho not that interesting... From: PARCEL@INTELLICORP.COM (Scott Parcel) Subject: X & Signals Message-ID: <9002281442.aa11275@mintaka.lcs.mit.edu> Date: 28 Feb 90 19:37:02 GMT I have some questions and comments about the recent discussion of handling events inside of Unix signal handlers. My particular interest is in using signals to do all X event processing. Can you please explain this? This makes no sense to me. What kind of interface do you provide for an application that does nothing but trap signals? What kind of functionality does such an application serve? The following is my understanding of signal handling problems and methodology: dan ----------------------------------------------------------- O'Reilly && Associates argv@sun.com / argv@ora.com 632 Petaluma Ave, Sebastopol, CA 95472 800-338-NUTS, in CA: 800-533-NUTS, FAX 707-829-0104 Opinions expressed reflect those of the author only.
argv%turnpike@Sun.COM (Dan Heller) (03/04/90)
Geez, not only did I forget to proofread my last message, I forgot to *finish* it before I posted it.. It's been a very long week.... My previous message was supposed to look like this: In article <4429@quanta.eng.ohio-state.edu> JONESD@kcgl1.eng.ohio-state.edu (David Jones) writes: > Instead of hacking up tookits to allow your application to add signal handlers, > I'd rather see them hacked up to convert signals into client events. The > application would deal with with the signal as another event to deal and > not as something to be dealt with by a signal handler. That's fundamentally the same thing I'm talking about. That is, you should register signals and handlers (functions) for those signals with a toolkit or its intrinsics (Xt, in this case). The toolkit calls the function registered for the signal in case one is delivered. However, the idea about converting signals into events doesn't make sense -- signals don't happen in windows [%] and they don't have any of the associated values that accompany existing X events such as a serial #, window ID, x/y values, etc... Signals are associated with processes, not X clients. The problem may become more complicated as subprocesses are created (fork(), for example). [%] SIGWINCH is a possible exception and an interesting case.. altho not that interesting... From: PARCEL@INTELLICORP.COM (Scott Parcel) Subject: X & Signals Message-ID: <9002281442.aa11275@mintaka.lcs.mit.edu> Date: 28 Feb 90 19:37:02 GMT I have some questions and comments about the recent discussion of handling events inside of Unix signal handlers. My particular interest is in using signals to do all X event processing. Can you please explain this? This makes no sense to me. What kind of interface do you provide for an application that does nothing but trap signals? What kind of functionality does such an application serve? dan ----------------------------------------------------------- O'Reilly && Associates argv@sun.com / argv@ora.com 632 Petaluma Ave, Sebastopol, CA 95472 800-338-NUTS, in CA: 800-533-NUTS, FAX 707-829-0104 Opinions expressed reflect those of the author only.
evgabb@sdrc.UUCP (Rob Gabbard) (03/05/90)
In article <4429@quanta.eng.ohio-state.edu>, JONESD@kcgl1.eng.ohio-state.edu (David Jones) writes: > Instead of hacking up tookits to allow your application to add signal handlers, > I'd rather see them hacked up to convert signals into client events. The > application would deal with with the signal as another event to deal and > not as something to be dealt with by a signal handler. This wouldn't solve the original problem I had that started all this. I wanted a way for my process to wake up periodically and flush out the event queue to keep it from overflowing. For instance, what if I had a model solver that was going to take 7 hours to run a solve on a model. The user clicks a SOLVE widget and its out of the event loop for 7 hours. During that time all kinds of events could be received into the queue and not serviced causing it to eventually overflow. I wanted to use setitimer and signal to periodically check the queue, but the problems I had are what started this discussion. -- ________ _________ _______ ________ / _______| | ____ \ | ___ \ / _______| Rob Gabbard (uunet!sdrc!evgabb) | |______ | | \ \ | | \ | | / Technical Development Engineer \_______ \ | | | | | |___/ / | | Structural Dynamics Research Corp. ______| | | |____/ / | ____ \ | \_______ #include <std/disclaimer.h> |________/ |________/ |_| |_| \________|
mitch@mouse..westford.ccur.com (Mitchel Kuninsky) (03/06/90)
argv wrote the following: >...long description of the problem with X and signals... > >Now, you could implement this yourself via "work procs" >(see XtAddWorkProc()), but the granularity isn't fine enough. >That is, work procs are only called when there are no events >pending. Implemented properly, the internals to Xt would >check in between event delivery to event handlers. > > >dan Are you suggesting that you do an XtAddWorkProc from the signal handler? You really can't even do that safely because the client code being interrupted by the signal might also be in the middle of a call to XtAddWorkProc and the workproc queue (or whatever database is used to keep track of them) might be in some inconsistent state. Just about the ONLY thing you can do safely from a signal handler is set a flag. One solution to this problem, as you mention in your message, is to set a flag and use a modified XtMainLoop that checks the flag upon return from XtNextEvent before calling XtDispatchEvent. I've implemented something like this and the one problem I have is that the arrival of the signal will not kick the client out of XtNextEvent so your signal handler will not get executed until some other event comes along. Usually, this is no problem, but, if the signal you're catching is SIGQUIT, there probably will not be any more events coming from the user. The real root of this problem, at least on Unix systems, is that the select in the Xlib tries to recover from being interrupted by a signal by checking errno for EINTR (which is the value returned when a system call is interrupted by a signal). If it finds EINTR, it just dives back into the select call. On the surface, it looks as though you could hack an Xlib to respond to signals by changing this behaviour so that XtNextEvent would return with a null event (or something) if it was interrupted and your special XtMainLoop could examine your signal flag. I envision a signal handler like: SignalHandler { sigFlag = TRUE; } and an XtMainLoop like: MyMainLoop() { XEvent event; for (;;) { XtNextEvent( &event ); if (event.type != NULL_EVENT) /* or something like this. */ XtDispatchEvent( &event ); if (sigFlag) { process signal. Inhibit signals. sigFlag = FALSE; Enable signals. } } }
PARCEL@INTELLICORP.COM (Scott Parcel) (03/07/90)
>This wouldn't solve the original problem I had that started all this. I wanted a >way for my process to wake up periodically and flush out the event queue to >keep it from overflowing. For instance, what if I had a model solver that was >going to take 7 hours to run a solve on a model. The user clicks a SOLVE widget >and its out of the event loop for 7 hours. During that time all kinds of events >could be received into the queue and not serviced causing it to eventually >overflow. I wanted to use setitimer and signal to periodically check the queue, >but the problems I had are what started this discussion. Perhaps I'm repeat prior info, but, to process events during the 7 hour loop I'd: 1. Setup to get SIGIO signals when X event data arrives on the event queue. 2. Mask signals or use some other protection technique to only allow processing the signals and the event queue when you know its safe. (Safe to me means your not in the middle of any nonreentrant functions which might be called during the signal handler event processing.) If your only concerned with using the signal handler to process events during a 7 hour mathmatical computation this might be easy. I'm doing this kind of thing and it works fairly well. There are some more refinements which can be needed in some situations. -- scott parcel@intellicorp.com -------
argv%turnpike@Sun.COM (Dan Heller) (03/07/90)
BTW, the recent discussion of XtCleanup() or XtExit() makes this discussion even more important. Trapping signals reliably will aid in the programmer being able to call XtExit() as needed. In article <23695@masscomp.ccur.com> mitch@westford.ccur.com (Mitchel Kuninsky) writes: > argv wrote the following: > >Now, you could implement this yourself via "work procs" > >(see XtAddWorkProc()), but the granularity isn't fine enough. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (Note #1) > >That is, work procs are only called when there are no events > >pending. Implemented properly, the internals to Xt would > >check in between event delivery to event handlers. ^^^^^^^^^^^^^^^^^^^^^^^^^ (note #2) > Are you suggesting that you do an XtAddWorkProc from the signal > handler? Not exactly. There are two ways to address this: one where Xt is modified and the other for when Xt is not modified (e.g. you have write the necessary functions). I claim that the best solution is a modification to Xt. However, I suggested a "workaround" for the timebeing. This is the use of "work procs". From the top: the first call to AddSignalHandler(sig, proc) does: AddSignalHandler(sig, handler) int sig; SIGRET (*handler)(); { SIGRET old_hanlder = signal(sig, _private_func); /* see below */ /* add to a linked list (data struct, whatever) the fact that "handler" should be called when "sig" is delivered. */ return old_handler; } The _private_func is static to the .c file that is implementing this stuff. It would have code which does: static long signal_received = 0L; /* bitmask indicating delivered sigs */ static _private_func(sig, ...) int sig; ... { /* save signal context, resources, etc... in a *queue* because the same signal may have been delivered more than once before processing. */ if (!signal_received) /* no signals registered so far, add work proc */ XtAddWorkProc(_check_sigs, NULL); /* see below */ signal_received |= (1<<sig); /* flag this signal as received */ } static _check_sigs(unused) XtPointer unused; { int i; if (!signal_received) return; /* save lots of time */ for (i == 1; i < NSIG; i++) if (signal_received & (1<<i)) { /* this signal has been received ... look up in linked list which function to call -- also retrieve saved contex. */ while (saved_context) handler(i, save_context, saved_resources, etc...) signal_received &= ~(1<<i); } } > Just about > the ONLY thing you can do safely from a signal handler is set a flag. which is exactly what I'm doing. > One solution to this problem, as you mention in your message, is to set > a flag and use a modified XtMainLoop that checks the flag upon return > from XtNextEvent before calling XtDispatchEvent. I've implemented ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ > something like this and the one problem I have is that the arrival of > the signal will not kick the client out of XtNextEvent so your signal > handler will not get executed until some other event comes along. That's not the way to do it. You *must* do this from _within_ XtNextEvent(). You should not wait till afterwards. As my "notes" (#1 and #2 in the beginning of my message) point out, one way of getting out of XtNextEvent() quickly is by a work proc, but the graunliary isn't fine enough -- you have to wait for all queued events to be delivered before getting notified of the signal. Thus, to really modify XtNextEvent correctly, you have to add a test for the "signal_received" bitmask (!= 0) at the this location within the Xt code: void XtAppNextEvent(app, event) XtAppContext app; XEvent *event; { int i, d; for (;;) { add -> if (app->signal_received != 0) add -> /* call the equivalent to the work proc above */ if (app->count == 0) DoOtherSources(app); else { for (i = 1; i <= app->count; i++) { . . . Note: "signal_received" does not necessarily have to be atteched to an application context, but let's not get into that right now. > Usually, this is no problem, but, if the signal you're catching is > SIGQUIT, there probably will not be any more events coming from the > user. Oh yeah? If you've trapped it, you will certainly get a bunch of events from the user. Because he sees that the application is not quitting, he's going to do it again, click on the "quit" button and ask "why is this application not quitting?" while he moves his mouse around, pushes keys and presses buttons. > The real root of this problem, at least on Unix systems, is that the > select in the Xlib tries to recover from being interrupted by a signal > by checking errno for EINTR (which is the value returned when a system > call is interrupted by a signal). If it finds EINTR, it just dives This is only a problem on sys-v for one. But, Xt already does this so it's not terribly important to continue to address this problem. dan ----------------------------------------------------------- O'Reilly && Associates argv@sun.com / argv@ora.com 632 Petaluma Ave, Sebastopol, CA 95472 800-338-NUTS, in CA: 800-533-NUTS, FAX 707-829-0104 Opinions expressed reflect those of the author only.
argv%turnpike@Sun.COM (Dan Heller) (03/07/90)
In article <1174@sdrc.UUCPevgabb@sdrc.UUCP (Rob Gabbard) writes:
This wouldn't solve the original problem I had that started all this. I
wanted a way for my process to wake up periodically and flush out the
event queue to keep it from overflowing. For instance, what if I had a
model solver that was going to take 7 hours to run a solve on a model.
The user clicks a SOLVE widget and its out of the event loop for 7
hours. During that time all kinds of events could be received into the
queue and not serviced causing it to eventually overflow. I wanted to
use setitimer and signal to periodically check the queue, but the
problems I had are what started this discussion.
There are two ways to address this problem. First and foremost,
you need to redesign this user interface. You should never have
a function that takes that much time an run it in a callback
routine. That type of processing should either be done in a
separate process, or you need to read and dispatch events within
that cpu-intensive routine.
Secondly, given that you *have* to run this 7-hour routine, you
should not decide to use the timer signal to test for user events.
If you do, you're perpetuating the same problem that started this.
That is, the signal handler may still be interfering with any Xlib
calls you may be executing since you would be using Xlib to test
for and deal with events.
Let me be more explicit. If you want to write a long time-consuming
or CPU intensive routine, then the problem of reading/waiting for
events should be handled manually. Edit the cpu-intensive routine
and insert locations in which you can call XPending(), XReadEvent()
or XDispatchEvent() as needed. Do not use a itimer to do this for you.
If you can't edit that routine, then you should spawn a new process
and execute it. I doubt this is the case, however. If you are using
Xview, the Notifier is really handy for stuff like this and there is
a chapter that addresses this type of activity in the XView Programmer's
Manual (Volume 7 of the O'Reilly series on X programming).
dan
-----------------------------------------------------------
O'Reilly && Associates
argv@sun.com / argv@ora.com
632 Petaluma Ave, Sebastopol, CA 95472
800-338-NUTS, in CA: 800-533-NUTS, FAX 707-829-0104
Opinions expressed reflect those of the author only.
hvr@kimba.Sun.COM (Heather Rose) (03/08/90)
In article <1174@sdrc.UUCP> evgabb@sdrc.UUCP (Rob Gabbard) writes: >In article <4429@quanta.eng.ohio-state.edu>, JONESD@kcgl1.eng.ohio-state.edu (David Jones) writes: >> Instead of hacking up tookits to allow your application to add signal handlers, >> I'd rather see them hacked up to convert signals into client events. The >> application would deal with with the signal as another event to deal and >> not as something to be dealt with by a signal handler. > >This wouldn't solve the original problem I had that started all this. I wanted a >way for my process to wake up periodically and flush out the event queue to >keep it from overflowing. For instance, what if I had a model solver that was >going to take 7 hours to run a solve on a model. The user clicks a SOLVE widget >and its out of the event loop for 7 hours. During that time all kinds of events >could be received into the queue and not serviced causing it to eventually >overflow. I wanted to use setitimer and signal to periodically check the queue, >but the problems I had are what started this discussion. In this example, you should use two processes. One does the 7 hour calculation, the other handles the window interface. If you were to use XView for this, you would not even need signal handling since you can set up an input function to read the output of the program when it's available. A two process model is much easier to implement and more reliable than what you've proposed. As an added benefit, you could set the "nice" value of your calculating process so it does not kill your user interaction time while processing. Regards, Heather
jeff@samna.UUCP (jeff) (03/08/90)
In article <23695@masscomp.ccur.com> mitch@westford.ccur.com (Mitchel Kuninsky) writes:
:I envision a signal handler like:
:
: SignalHandler
: {
: sigFlag = TRUE;
: }
:
:and an XtMainLoop like:
:
: MyMainLoop()
: {
: XEvent event;
:
: for (;;)
: {
:(1) XtNextEvent( &event );
: if (event.type != NULL_EVENT) /* or something like this. */
: XtDispatchEvent( &event );
: if (sigFlag)
: {
: process signal.
: Inhibit signals.
: sigFlag = FALSE;
:(2) Enable signals.
: }
: }
: }
This may be kind of nit-picking, but ... You have a nasty race here.
What if a signal arrives between the re-enabling of signals at (2) and
the next call to XtNextEvent at (1).
I believe this points out the need to have the signal-handling more
tightly integrated with the Intrinsics code.
---
Jeff
evgabb@sdrc.UUCP (Rob Gabbard) (03/08/90)
In article <132645@sun.Eng.Sun.COM>, hvr@kimba.Sun.COM (Heather Rose) writes: > In this example, you should use two processes. One does the 7 hour calculation, > the other handles the window interface. We are using a similar architecture to this model you are descibing. What if your window interface was doing a ray trace into a pixmap that took a longer time to do than your timer interval ? That is where the real danger is. > If you were to use XView for this, you would not even need signal handling Sorry, we're DECWindows/Motif based. -- ________ _________ _______ ________ / _______| | ____ \ | ___ \ / _______| Rob Gabbard (uunet!sdrc!evgabb) | |______ | | \ \ | | \ | | / Technical Development Engineer \_______ \ | | | | | |___/ / | | Structural Dynamics Research Corp. ______| | | |____/ / | ____ \ | \_______ #include <std/disclaimer.h> |________/ |________/ |_| |_| \________|
nick@bischeops.UUCP (Nick Bender) (03/10/90)
In article <203@samna.UUCP>, jeff@samna.UUCP (jeff) writes: > In article <23695@masscomp.ccur.com> mitch@westford.ccur.com (Mitchel Kuninsky) writes: > :I envision a signal handler like: > : > : SignalHandler > : { > : sigFlag = TRUE; > : } > : > :and an XtMainLoop like: > : > : MyMainLoop() > : { > : XEvent event; > : > : for (;;) > : { > :(1) XtNextEvent( &event ); > : if (event.type != NULL_EVENT) /* or something like this. */ > : XtDispatchEvent( &event ); > : if (sigFlag) > : { > : process signal. > : Inhibit signals. > : sigFlag = FALSE; > :(2) Enable signals. > : } > : } > : } > > This may be kind of nit-picking, but ... You have a nasty race here. > What if a signal arrives between the re-enabling of signals at (2) and > the next call to XtNextEvent at (1). > > I believe this points out the need to have the signal-handling more > tightly integrated with the Intrinsics code. > > --- > Jeff I've been thinking a little about this problem 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 be cause 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) ? Any thoughts ? PS. I'm assuming the BSD style sigvector signal mechanisms (you know, reliable delivery and all that...). path nick%bischeops@uunet.uu.net
mouse@LARRY.MCRCIM.MCGILL.EDU (der Mouse) (03/11/90)
> 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
thinman@cup.portal.com (Lance C Norskog) (03/18/90)
You're all going about this the wrong way. The original poster with the 7-hour operation can easily do what I did: I wanted to get into X programming, and I wanted to look at some PostScript stuff, so I brought up the Crispin Goswell postscripter X driver. It doesn't handle X input well, but Berkeley sockets and AT&T Streams both have a facility to deliver a signal on receipt of data on a network connection. Under SYSV it's SIGPOLL, under BSD I think it's SIGASYNC. I don't use XtMainLoop at all. The init routine does this: for (fd=3; fd<100; fd++) if fd is a network socket make fd send the input-available signal This is, admittedly, grody, but Xt won't find the fd's for me. The signal handler for this sig sets a flag and exits. Periodically you check that flag and run this routine: XtInputMask mask; while(mask = XtAppPending(applicationcontext)) XtAppProcessEvent(applicationcontext, mask) Under SYSV, this pair stops sigs and then handles them: sighold(SIGPOLL); /* single-thread this routine */ sigrelse(SIGPOLL); /* take more signals now */ Using polling when interrupts are available is extremely goony. If you follow the other suggestions in this thread, your 7-hour calculation will become 8 or 9 or 10 hours, because of all the polling involved. The only problem with this scheme under SYSV is that signals always make system calls return with EINTR, so I had to guard all file I/O with sighold/sigrelse pairs and play games with the command line I/O handler. Also, there are sighold/sigrelse pairs around all X driver routines. Lance