olson@sax.cs.uiuc.edu (Robert Olson) (09/17/90)
I'm trying to take an existing application and create a thread to handle some communication with another application via a port (I'm actually using the NextStep speaker/listener). The problem is that the application is using SIGIO to notify itself of keypresses. When I add another thread for communication, the communication thread is the one that actually gets the signal, some of the time (when I type quickly at the application), hanging the application. Is there any way I can keep the thread from getting the signal? I tried doing a sigblock, but then the application didn't get the signals either. --bob -- Bob Olson University of Illinois at Urbana/Champaign Internet: rolson@uiuc.edu UUCP: {uunet|convex|pur-ee}!uiucdcs!olson NeXT mail: olson@fazer.champaign.il.us "You can't win a game of chess with an action figure!" AMA #522687 DoD #28
bill@cs.columbia.edu (Bill Schilit) (09/17/90)
Robert Olson writes: >I'm trying to take an existing application and create a thread to >handle some communication with another application via a port (I'm >actually using the NextStep speaker/listener). The problem is that the >application is using SIGIO to notify itself of keypresses. When I add >another thread for communication, the communication thread is the one >that actually gets the signal, some of the time (when I type quickly at >the application), hanging the application. Is there any way I can keep >the thread from getting the signal? I tried doing a sigblock, but then >the application didn't get the signals either. Robert, The problem you are having with mach threads and unix signals is because threads and signals don't mix (one is unix and the other isn't). Signals are either synchronous -- caused by the program flow -- or asynchronous. Synchronous signals (like illegal memory reference) are handled by the mach exception handler in the unix emulation code and are correctly sent to the offending thread (the one generating the exception condition). See ux_exception.c and catch_exception_raise(). Asynchronous signals on the other hand (like your SIGIO) are delivered willy nilly to the first thread that happens to go past some code in the kernel. Doing things like sigblock are only going to cause problems because these *unix* system calls effect all threads in the task. So I think your options are: (1) You can structure your code so that the SIGIO handler can run in any thread. (2) you can catch the signal in any thread and wakeup or interrupt your IO thread. If you decide to interrupt you may be able to get some code from Xerox PARC that simulates signals directed at a particular thread, however, this is expensive and should be avoided. - Bill -- Bill Schilit Columbia University Computer Science Department bill@cs.columbia.edu
brenegan@pluto.sybase.com (david brenegan) (09/19/90)
>Robert Olson writes: > >>[..good stuff deleted..] > Bill schilit writes: >The problem you are having with mach threads and unix signals is >because threads and signals don't mix (one is unix and the other >isn't). [..other good stuff deleted...] > This is a very fundamental problem with mach and unix as bill points out. This really is a common problem. The way I am dealing with this problem is I have a thread that does nothing but catch exceptions, in my case I use EXC_SOFTWARE. This exception thread listens to all the threads exception ports ( I actually allocate and set the exception port I listen to using the port_allocate() and task_set_special_port() routines.) This exception thread simply waits, blocked in msg_receive() waiting for an exception to happen. Once we receive on we pass the message to a special 'exception server', on NeXT this is called exc_server(). exc_server() returns us a message which we must then do a msg_send() with, otherwise the the thread permanently blocks and things don't work, this is apparently a mach feature. This is *all* the exception thread does, looping around blocking again in msg_receive(). The routine catch_exception_raise(), does the real work. This guy needs to first stop the thread that will run the signal handler, via thread_suspend(). Interrupt the current system call in progress (if there was one in progress), via thread_abort(), get the processor registers, via thread_get_state(). And then set up the pc, etc. to call the correct signal handler according to information you can pass in to this routine (catch_exception_raise()). Then call thread_resume(). If things are set up correctly, you will execute the signal handler in the thread that it should be executing in, and return to what you were doing before the interrupted system call. In order for this all to work, you also need to have a generic signal handler, that just calls exception_raise(). In this routine you would say the exception is EXC_SOFTWARE, and probably set the type of signal in the subcode variable passed to this routine. (see exception_raise(), as bill says...). There are some bugs/features on NeXT that may prevent you from having this work successfully for you. I have working examples of what I just discussed but I'm running in to some problems that NeXT is trying to get working for me. I hope this little discussion helps you in your endevours. Cheers, _David Brenegan Sybase Inc. brenegan@sybase.com