Subject: Mach exceptions: the return of the sigfilter hook
To: None <tech-kern@netbsd.org>
From: Emmanuel Dreyfus <manu@netbsd.org>
List: tech-kern
Date: 12/22/2003 02:41:24
Hi

After the back-off of the sigfilter emulation hook in kpsignal2 and some
disussions behind the scene, I'm ready to commit it again. I studied various
way to get rid of it, without success. However, I discovered a lot of new
oddities about Mach exceptions and I can propose an alternative to the
sigfilter hook: another emulation hook located somewhere else.


Background: MacOS X is based on Mach. Mach uses Mach exceptions to notify
processes about exceptionnal conditions. A Mach exception is a Mach message
sent to a port that was registered to receive the exception.

When a thread raises an exception, it is suspended. Other threads within the
task (Mach tasks are equivalent to our processes) still run. The thread
receiving the Mach exception (we will call it the exception catcher) must
send a reply (let us call that an acknowledge) to the exception message so
that the suspended thread may resume execution.

Additionnally, MacOS X has a feature called softsignals, where UNIX signals
are notified to the catcher through Mach exceptions. This is where our
problem is: emulating softsignals.


Now, the latest discoveries:

1) Mach exception raised from traps and Mach exceptions raised from UNIX
signals by softsignal are quite different. 

- When a trap raises a Mach exception, it seems that no signal is ever
generated if an exception port was registered for that exception. These
exceptions are raised regardless of the signal mask.
 
- When a UNIX signal raises a Mach exception through the softsignal
feature, the UNIX signal is treated normally after the exception is
acknowledged, except for SIGSTOP: it raises a Mach exception but the process
is not stopped. Mach exceptions are raised for signals ignored or catched,
but not for masked signals: they honour the signal mask. 

2) softsignals can only be enabled in a traced process. You can use
either MacOS X ptrace's PT_SIGEXC after PT_TRACE_ME, or just
PT_ATTACHEXC alone (it does a PT_ATTACH and activates softsignals for
the traced). This is the big discovery, as it narrows the scope of what
I want to do in MI code. At once I proposed a hook at the beginning of
kpsignal2 to intercept any signal, but it seems we only need to
intercept signals when we deal with traced processes.

Once softsignals are enabled in a traced process, the tracer (which
might be different from the catcher) will not get SIGCHLD on each UNIX
signal the traced process will get. And the traced will never be stopped
after getting a signal (the thread that got the exception is suspended
until the exception is acklowledged by the catcher, but the process
still run). remember SIGSTOP being inhibited? It was just a piece from a
bigger picture.

3) we suspect by reading Darwin's header files that Apple has some plans to
convert some signals (SIGPIPE, SIGABRT and SIGSYS) to Mach exceptions,
outside of the softsignals scope. Once you'll have registered an exception
port, you'll be able to get a Mach exception instead of SIGPIPE, even if the
process is not traced. That plans do not have come to reality in MacOS X.3,
I have just been able to check it this evening.

Conclusion: I can avoid the sigfilter hook at the beginning of kpsignal2 if
I install another hook to avoid the SIGCHLD to the parent and process stop
each time a traced process get a signal. There would be three occurences of
the same hook, in kpsignal2 and issignal: 

It would look like this (I'm open to suggestions for the name of the hook) 

                        if ((p->p_emul->e_sigexc != NULL) &&
                            ((*p->p_emul_e_sigexc)(p, ksi) == 0))
                                goto done;

                        if ((p->p_pptr->p_flag & P_NOCLDSTOP) == 0) {
                                /*
                                 * XXXSMP: recursive call; don't lock
                                 * the second time around.
                                 */
                                child_psignal(p, 0);
                        }
                        proc_stop(p, 1);         /* XXXSMP: recurse? */
                        goto done;

Advantages: The emulation layer would be less a hack (for now, to avoid
passing through child_psignal/proc_stop, I remove P_TRACED when softsignals
are enabled, and I reset it back when ptrace(PT_DETACH,...) is called.
That's not nice but it works). 

Disadvantages: the hook is less generic, there are 3 hooks instead of one,
and if Apple starts implementing their project for SIGPIPE/SIGABRT/SIGSYS,
the hook will have to be moved as the beginning of kpsignal2, where
it had been in the first place. 

Any opinion on this mess? Or maybe some ideas to do the job without an
emulation hook? (ideas involving rewritting the signal code are welcome if
you are ready to rewrite it :o) 

-- 
Emmanuel Dreyfus
Il y a 10 sortes de personnes dans le monde: ceux qui comprennent 
le binaire et ceux qui ne le comprennent pas.
manu@netbsd.org