[comp.os.mach] Threads and signals

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