Subj : Re: A pity that there is no forkall() which clones threads To : comp.programming.threads From : Marcin 'Qrczak' Kowalczyk Date : Tue Mar 08 2005 12:02 am David Hopwood writes: > On a ForkProcess call in thread T, > > 1. set a global flag that causes all threads except T to suspend > if and when they reach an interruptible point. Doing this with a global flag would be too intrusive, it would require amending the mechanism of delivering signals with additional checking just for the purpose of forking. I send all threads Kogut signals instead (and hook to send it to newly created threads too, and set up an exit monitor which checks for threads that will not handle the signal because they finished). The handler of such signal suspends the thread. When it's resumed after the fork, it either returns or throws the exception of thread cancellation. > 2. wait until all threads have suspended except T, and possibly some > threads that were already running interruptible foreign code at > the time of the ForkProcess call. Yes, the semantics should be like this. It's ugly that the forker has to peek inside thread internals to determine whether it should be counted or not. And it's ugly to add a flag to a thread state only to determine whether it's evaporable at fork. And they will leak resources. For example if the call is getaddrinfo, it will leave open sockets. >> Maybe I should introduce something which says "when you want to >> interrupt me while I'm making this foreign call, send me SIGUSR1". > > Unix signals and threads don't mix very well; you probably want to use > pthread_cancel instead. No, a Kogut signal doesn't necessarily imply cancellation. And even in case it does, it's not immediate - it's propagated as an exception. There is no Kogut API which could be mapped to pthread_cancel. In particular in the case of forking the signal causes suspension and later in one of the processes the computation continues, so interruption can't be made with pthread_cancel. I tried making the change of interruption by Unix signals, but it was getting very ugly. The problem is that it steals a signal which might be used for other purposes by the programmer, and even concurrent foreign calls might want to use the same signal. Signal handlers are global, it's impossible to determine in which thread a signal handler is executing unless I break rules and call functions which are generally unsafe in signal handlers. Signals would have to be blocked in various other places because in order to determine how the signal should be handled (depending on whether it's a real signal or a signal used internally to wake up a foreign call) more data would have to be made accessible to signal handlers than currently is. It would have race conditions, in particular a system signal sent to the process could be lost. Well, currently there are small and probably unavoidable race conditions (when a signal arrives just before epoll/poll/select, it might not be handled promptly; there is pselect but there is no equivalent for epoll). I'm considering giving up on this issue. It's already quite complicated and there are compromises caused by implementability. For example when you change the thread which handles Unix signals, the change is actually postponed if the new or old thread is inside a foreign call, because it's impossible to change its signal mask from the outside. This should rarely be a problem in practice - usually it's the main thread anyway, and if not, it's set up once at the beginning rather than changed repeatedly while the main thread makes foreign calls. Is there any way to interrupt waitpid, other than a Unix signal or pthread_cancel? Can I assume that pthread_getspecific is usable in a signal handler? Currently there is an ugly but working way to interrupt WaitForProcess by some Kogut programs: invoke it in the thread which handles Unix signals, and send a signal to the self process. This is not usable for two waits in parallel. Of course another way is to set up a handler for SigChld and wait for signals instead of using WaitForProcess. It's not easy to provide an interface to pthread_kill because if Unix signals are unblocked in other threads, then the above problems appear, and if they are blocked then pthread_kill obviously won't work. > I was originally thinking that it would indicate both that the thread > agrees to be evaporated on fork, and that it can be interrupted using > pthread_cancel with cancellation type PTHREAD_CANCEL_ASYNCHRONOUS (see > the man page). POSIX cancellation doesn't map well to Kogut threads. The concept of blocking Kogut signals is similar to POSIX cancellability (I have similar three effective states, the difference is that the synchronous mode is not the default), but being similar doesn't mean that one mechanism can use the other. -- __("< Marcin Kowalczyk \__/ qrczak@knm.org.pl ^^ http://qrnik.knm.org.pl/~qrczak/ .