[prev in list] [next in list] [prev in thread] [next in thread] 

List:       sbcl-devel
Subject:    [Sbcl-devel] Signal safe SBCL in the works
From:       Nikodemus Siivola <nikodemus () random-state ! net>
Date:       2007-03-30 13:27:11
Message-ID: 460D102F.1080302 () random-state ! net
[Download RAW message or body]

Ok, I think I know how to make SBCL signal safe for the most part.
Tenative documentation and very sketchy imp notes follows.

Does this look acceptable? I think except for the POSIX SIGNALS part
this jives pretty well with what Windows will require at any rate, but
I've very little idea yet of how this works with the Mach kernel
thread thingamajik (but if it can deal with our current approach, it
should certainly be able to deal with this!)

I went thought two different approaches yesterday / last night, and
discovered that they either needed signal unsafe functions in handlers,
or were prohibitively expensive. This should be free from those malaises,
but the actual implementation is vaporvare rigth now, so who knowns for
sure?

The way I see it, the biggest difference is that we (by default) we
lose the lovely asynch timers Xach gave us on unithreaded builds.
Mostly due to that this more or less needs to tie in with the safe
timeout system I mentioned earlier.

Cheers,

  -- Nikodemus

INTERRUPTS

Interrupts are unexpected events that happen due to things beoynd the
program's control: user sending a keyboard interrupt, for example.
There are major classes of interrupts: synchronous and asynchronous.

Synchronous interrupts are deferred till the next call to
RECEIVE-INTERRUPTS that happens outside a WITHOUT-INTERRUPTS section.
Synchronous interrupts are always safe, and it is safe to unwind from
a synchronous interrupt.

There are many sources of synchronous interrupts in the system: On
single-threaded builds timer events are syncronous by default, but can
be made asyncronous on POSIX systems using the function
TIMER-INTERRUPTS. (On multithreaded builds timer events are handled in
a separate thread.)

Most POSIX signals are by default handled as synchrous interrupts, but
this can be altered using SIGNAL-ACTION.

   function RECEIVE-INTERRUPTS

     Does nothing if called during the execution of a
     WITHOUT-INTERRUPTS, unless there is an intervening
     WITH-INTERRUPTS.

     Otherwise, if there are any deferred interrupt, handles at most
     one of each kind and then returns, unless a handler performed a
     non-local exit.

     Since interrupt handlers may execute arbitrary code,
     RECEIVE-INTERRUPTS may signal any kind of condition, execute a
     non-local exit, or even terminate the process.

     SBCL never calls RECEIVE-INTERRUPTS due to a call to another
     function, and does not automatically insert calls to it to user
     code. The only places where SBCL automatically calls
     RECEIVE-INTERRUPTS is between iterations of various interactive
     evaluation loops.

     User functions that call RECEIVE-INTERRUPTS should advertise
     this in their documentation, so that their callers know to
     expect the unexptected.

   function TIMER-INTERRUPTS &optional style

     STYLE must be either NIL, :ASYNCHRONOUS, :SYNCHRONOUS, or :THREAD.

     If no STYLE is given or it is NIL, the current timer interrupt
     style is returned. Otherwise any future timer event are handled in
     using the specified type of interrupt.

     :ASYNCHRONOUS style is supported only on POSIX systems, and only
     for backwards compatibility. Using it is never fully safe, and
     may lead to undefined consequences. Using it allows timers to
     fire using asynchronous interrupts.

     :SYNCHRONOUS style is the default on single-threaded builds, using
     it is safe and limits timers to firing when RECEIVE-INTERRUPTS is
     called.

     :THREAD style is the default on multithreaded build, using it is
     safe, and limits timers to firing within a specific timer thread.

   macro WITHOUT-INTERRUPTS &body forms

     Executes FORMS with all interrupts disabled, unless a nested
     WITH-INTERRUPTS occurs.

     Does not interfere with garbage collection, and does not prevent
     scheduling of other threads on multithreaded builds.

   macro WITH-INTERRUPTS &body forms

     Executes FORMS with all interrupts enabled. Since interrupts are
     normally enabled, this does not have any effect unless an outer
     WITHOUT-INTERRUPTS exists.

Asynchronous interrupts are handled as soon as possible: they are
deferred while inside a WITHOUT-INTERRUPTS section, but are handled as
soon as it is left, or if a WITH-INTERRUPTS section is entered. Most
of the time they are handled essentially immediately.

IMPORTANT: Asyncronous interrupts are never quite safe, and unwinding
from them is especially risky: they may arrive eg. in the middle of a
non-reentrant system call, or between a function call and assigning
its result to a variable.

Asynchronous interrupts can still be useful for debugging, as they are
able to eg. interrupt endless loops that contain no RECEIVE-INTERRUPTS
calls. They should, however, generally be avoided in production
systems, unless hard to diagnose crashes or hangs are acceptable.

By default the following are the only sources of asyncronous
interrupts in SBCL:

* INTERRUPT-THREAD and TERMINATE-THREAD are always asynchronous. Their
   synchronous equivalents are called CALL-IN-THREAD and UNWIND-THREAD.

* The system interactive interrupt (SIGINT on POSIX systems) is by
   default asynchronous, but can be made synchronous by using
   INTERACTIVE-INTERRUPT-ACTION.

* The statistical profiler works currently by using asyncronous
   interrupts, and can therefore cause occasional erratic behaviour.

   function INTERACTIVE-INTERRUPTS &optional style

     STYLE must be either NIL, :ASYNCHRONOUS, or :SYNCHRONOUS.

     If no STYLE is given or it is NIL, the current interactive
     interrupt style is returned. Otherwise any future interactive
     interrupts are handled in using the specified type of interrupt.

     :ASYNCHRONOUS is the default, but is recommended only for
     development and debugging, as it is never quite safe, and
     unwinding from such an interactive interrupt is especially risky.
     It is the default style for both backwards compatibility and to
     allow interruption of eg. endless loops.

     :SYNCHRONOUS style recommended for production environments, and
     defers interactive interrupts till the next call to
     RECEIVE-INTERRUPTS.

POSIX SIGNALS

There are two major classes of signals from the SBCL perspective:
system signals, and user signals. System signals have a predefined
behaviour can cannot be altered by user code without breaking the
system. User signals can have a range of behaviours settable via
SIGNAL-ACTION.

   function SIGNAL-ACTION signal &optional action argument

     Allows defining an action to be taken for handling a user signal.

     Signal must be one of the following keywords (matching the
     corresponding POSIX signal): ...list of "user signals" here...

     Returns as multiple values the previous ACTION and ARGUMENT.

     Possible actions and their arguments are:

      NIL           no argument     Retains current behaviour.
      :ignore       no argument     Ignores the signal.
      :terminate    message         Terminates the lisp process.
      :stop         message         Stops the lisp process.
      :synchronous  handler         Defers the handler to next safe point.
      :asynchronous handler         Handler is called immediately.
      :thread       handler         Handler is called in separate thread.

   function DEFAULT-SIGNAL-ACTION signal

     Causes the system to take the default action for the specified
     SIGNAL number. Calling this function is the correct way to
     terminate or stop the process in response to a signal whose
     default action is to terminate or stop the process after a handler
     has first run: it ensures that the controlling shell is informed
     about the signal that caused process termination.

     Note that if the default POSIX action is to ignore the signal,
     then this function does nothing.

IMPLEMENTATION NOTES

When deferring handling of a signal, we set a global flag, use a
semaphore to lock the pending signal array, mark the specific signal
as pending in the array, and up the semaphore. Multiple pending
signals are lost and we don't care: two SIGINTs is the same as one for
us.

RECEIVE-INTERRUPTS checks the global flag, locks the signal array,
finds the first pending signal from it, zeroes it, releases the
lock, and calls the deferred handler. It repeats this for all for all
pending signals, but at most once for any given signal. This process
is guaranteed to terminate, and can safely be unwound from.

SIGCHLD needs to be thought about some more. We may eg. want to
save the si_code.

SIGPROF, SIGVTALARM: handle immediately for now (unsafe, but we want
these for profiling). someday maybe save context and a snapshot of
stack for analysis at a safe point before next GC. These will still
need to respect WITHOUT-INTERRUPTS, though, to give some measure of
safety. (But maybe we could actually make them bypass that, and have
a separate WITHOUT-INTERNAL-INTERRUPTS that defers them too?)

SIGPIPE, SIGIO/SIGPOLL: ?

SIGBUS, SIGFPE, SIGILL, SIGSEGV, and SIGTRAP are deal with pretty
much as now: they are either something we arranged to happen, or
something potentially bad enough that all bets are off at any rate.

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Sbcl-devel mailing list
Sbcl-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/sbcl-devel
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic