Signals + minimal proposal

Marcin 'Qrczak' Kowalczyk qrczak at
Tue Apr 11 08:22:56 EDT 2006

"Simon Marlow" <simonmar at> writes:

> How does "cancelling" a thread differ from sending it an exception?

It doesn't. By cancelling I mean just sending a particular async

> Can a thread be GC'd without being sent an exception first?

Yes, but I'm now changing this.

Unfortunately it doesn't seem possible to guarantee proper stack
unwinding in all cases:

POSIX threads evaporate after fork() in the child process. This means
that foreign code performing callbacks doesn't exist there, except in
the thread doing the fork; the C stacks are inaccessible. So in Kogut
in this case bound threads become unbound, and they only run up to the
end of the nearest callback from foreign code: then they are killed

Another technical limitation: in a build where OS threads are not used,
callbacks returning in a non-LIFO order must wait for the callback
using the top of the OS stack to return. It's impossible to cause such
thread to continue immediately even if it gets an exception.

There are also limitations caused by principles I've adopted myself.
I have scoped mutex locking and scoped unlocking. In particular
waiting for a condition unlocks the mutex and always relocks it before
returning. When a thread is waiting to relock a mutex when exiting a
scope (rather than when entering a scope), it must absolutely lock it
before it can continue, in order to guarantee consistent state of the
mutex in regions of code.

So I'm going to send threads about to be GC'd a signal rather than an
exception; it will be handled only if the thread has signals unblocked.

There is another case similar to GC'ing a thread: when the runtime
discovers that there are no threads to be run, to wait for I/O, to
wait for a timeout, and the thread handling system signals doesn't
seem to be intentionally waiting for signals (it's not blocked on a
Kogut construct similar to POSIX sigwait), the runtime attempts to
wake up the thread handling system signals with a Deadlock signal,
so the program can react to a total deadlock. Of course a deadlock
of only a subset of threads won't be detected if the threads are
not GC'd.

When waiting for the rest of threads at program exit, it might happen
that some threads won't want to return after being cancelled, e.g.
they have signals blocked or they lock up during cleanup. Such case
would normally be a deadlock (the main thread is waiting until they
finish, and they are waiting for something else), but the above
mechanism causes the main thread to be woken up and continue even
though some threads have not finished.

   __("<         Marcin Kowalczyk
   \__/       qrczak at

More information about the Haskell-prime mailing list