
On 09 April 2006 16:02, Marcin 'Qrczak' Kowalczyk wrote:
"Simon Marlow"
writes: That sounds hard to program with - surely you want to stop the program in order to clean up? Otherwise the program is going to continue working, generating more exit handlers, and we might never get to exit.
Here is how I've done it in Kogut:
An equivalent of Haskell's exitWith simply throws a predefined exception. When an unhandled exception reaches the toplevel, this exception is treated specially and is not printed with a stack trace. Exceptions caused by system signals are special too.
There is a central list of registered exit handlers. On program exit each handler is run once. Handlers registered during this cleanup are run too. Any exceptions thrown from handlers are caught and ignored. This happens after printing a stack trace from an unhandled exception, just before shutting down the runtime and exiting.
One of exit handlers cancels all other threads (except those which has been garbage collected) and waits until they finish. New threads started during this cleanup are canceled too.
Can a thread be GC'd without being sent an exception first? How does "cancelling" a thread differ from sending it an exception? Cheers, Simon

"Simon Marlow"
How does "cancelling" a thread differ from sending it an exception?
It doesn't. By cancelling I mean just sending a particular async exception.
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 immediately. 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@knm.org.pl ^^ http://qrnik.knm.org.pl/~qrczak/
participants (2)
-
Marcin 'Qrczak' Kowalczyk
-
Simon Marlow