On 'Other UNIXs' (namely AIX 4.2 and HP-UX 11.0) the following program 'works' - that is, it runs to completion without using CTRL-C at the terminal. On linux it hangs. The basic idea is is this: main(): Block SIGCHLD using pthread_sigmask/sigprocmask Initialize a pthread condition and its mutex Start thread_sig_handler thread fork() (See CHLD for child. This is the parent) Wait on the pthread condition Wait on end of thread_sig_handler exit CHLD: execl("/bin/sh", "sh", "-c", "echo HI THERE", NULL); thread_sig_handler: sigwait on SIGCHLD (plus SIGQUIT and SIGINT for safety) post the pthread condition return i.e.: So, basically, one thread is set up as a pseudo signal handler for SIGCHLD while another thread (or the main thread) does a fork/exec, the parent waiting until the signal handler has done its bit (signalled by a pthread condition variable), the child running something that will eventually end, generating a SIGCHLD signal. On Linux the handler thread never gets woken up (until CTRL-C). I tried a modified version too - add a signal handler that does a pthread_kill(handler_thread, SIGCHLD). That wakes it up alright - but the handler thread then attempts a waitpid - and receives ECHILD. So it cannot access the child process. This is the initial problem. I also have others with pthreads - like an execl from a forked child seems to kill the signale handler thread in some circumstances, the nature of which I cannot discover! - Thirdly note that getpid from a thread does NOT return the 'process id' as one would hope in a merely threaded program - it returns a completely different process ID! In general, it seems that pthreads/fork/execl/wait do not work together on Linux - and that pthreads is still a bit buggy! and they are essential to the AIX/HP-UX application that I am porting! Compile this source to test the original problem it: .................... /* * sigwaittest.c - a pthreads facility tester! * * This program tests the ability of a pthreads implementation to handle * SIGCHLD correctly - some don't. e.g. AIX and HP-UX send the SIGCHLD * signal to any thread that waits on SIGCHLD (correct), whereas Linux 2.2 * and Solaris 2.5 send it directly to the forking thread (wrong, I think); * * To compile: * * Linux: cc -o sigwaittest -lpthread sigwaittest.c * HP-UX: cc -o sigwaittest -lpthread sigwaittest.c * AIX: cc_r -o sigwaittest -lpthreads sigwaittest.c * SOLARIS: CC -o sigwaittest -lpthread -DSOLARIS * -D_POSIX_PTHREAD_SEMANTICS sigwaittest.c * * To run: * * Enter * sigwaittest<ENTER> * * You SHOULD get the following if it works: * * Main: entry - pid=<pid> * Main: Blocking SIGCHLD * Main: Initializing condition * Main: Initializing thread attributes: * Main: kicking off thread * FORKER: forking * CHILD: entry - pid=<pid> * THREAD HANDLER: entry - pid=<pid> * FORKER: got child <pid>! * FORKER: Waiting on condition * THREAD HANDLER: Waiting on sig_chld * <A few seconds wait> * SHL: quiting * THREAD HANDLER: Caught signal <signal number> (SIGCHLD) * THREAD HANDLER: Getting child info * THREAD HANDLER: wait pid=<pid>, stat=0 (errno=0/<err msg>) * THREAD HANDLER: Setting condition * THREAD HANDLER: quiting * FORKER: Condition set; quiting * Main: quiting * * or this if it fails: * * Main: entry - pid=<pid> * Main: Blocking SIGCHLD * Main: Initializing condition * Main: Initializing thread attributes: * Main: kicking off thread * FORKER: forking * FORKER: got child <pid>! * CHILD: entry - pid=<pid> * FORKER: Waiting on condition * THREAD HANDLER: entry - pid=<pid> * THREAD HANDLER: Waiting on sig_chld * <A few seconds wait> * SHL: quiting * <An infinite wait. Hit CTRL-C to release it> * THREAD HANDLER: Caught signal <signal number> (NOT SIGCHLD) * THREAD HANDLER: Setting condition * THREAD HANDLER: quiting * FORKER: Condition set; quiting * Main: quiting * * Note that the order of some messages may differ since we are talking * about multpile threads of execution here. */ #include <pthread.h> #include <unistd.h> #include <errno.h> #include <sys/types.h> extern char *sys_errlist[]; #if SOLARIS /* * SOLARIS differences */ #include <signal.h> #include <stdlib.h> #include <stdio.h> #define SHL "/sbin/sh" #else #include <sys/wait.h> #include <sys/signal.h> #if _AIX /* * AIX differences */ #define pthread_sigmask(__A,__B,__C) sigthreadmask(__A,__B,__C) #define PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED #define SHL "/usr/bin/sh" #elif _HPUX_SOURCE /* * HP-UX */ #define SHL "/usr/bin/sh" #else /* * LINUX */ #define SHL "/bin/sh" #endif #endif pthread_mutex_t cond_mutex; pthread_cond_t cond; int done = 0; void *thread_handler_routine(void *should_i); void forker_routine(void); int main() { pthread_t pt1; sigset_t set, old; pthread_attr_t pta; printf("Main: entry - pid=%i\n", getpid()); sigfillset(&set); sigaddset(&set, SIGCHLD); printf("Main: Blocking SIGCHLD\n"); pthread_sigmask(SIG_BLOCK, &set, &old); printf("Main: Initializing condition\n"); pthread_cond_init( &cond, NULL); pthread_mutex_init(&cond_mutex, NULL); printf("Main: Initializing thread attributes:\n"); pthread_attr_init(&pta); pthread_attr_setdetachstate(&pta, PTHREAD_CREATE_JOINABLE); printf("Main: kicking off thread\n"); pthread_create(&pt1, &pta, thread_handler_routine, (void *)0); forker_routine(); pthread_join(pt1, NULL); printf("Main: quiting\n"); return 0; } void forker_routine(void) { pid_t chld; printf("FORKER: forking\n"); if ((chld = fork()) == 0) { printf("CHILD: entry - pid=%i\n", getpid()); execl(SHL, "sh", "-c", "sleep 10; echo SHELL: quiting", NULL); printf("CHILD: quiting\n"); exit(0); } else { printf("FORKER: got child %i!\n", chld); printf("FORKER: Waiting on condition\n"); pthread_mutex_lock(&cond_mutex); if (!done) pthread_cond_wait(&cond, &cond_mutex); pthread_mutex_unlock(&cond_mutex); printf("FORKER: Condition set; quiting\n"); return; } } void *thread_handler_routine(void *parm) { pid_t pid; sigset_t set, old; int sig, status; printf("THREAD HANDLER: entry - pid=%i\n", getpid()); sigemptyset(&set); sigaddset(&set, SIGCHLD); sigaddset(&set, SIGQUIT); /* for safety! */ sigaddset(&set, SIGINT); /* for safety! */ printf("THREAD HANDLER: Waiting on sig_chld\n"); sigwait(&set, &sig); printf("THREAD HANDLER: Caught signal %i (%s)\n", sig, (sig == SIGCHLD) ? "SIGCHLD" : "NOT SIGCHLD"); if (sig == SIGCHLD) { printf("THREAD HANDLER: Getting child info\n"); errno=0; while ((pid = waitpid(-1, &status, WNOHANG)) == -1 && errno == EINTR); printf("THREAD HANDLER: wait: pid=%i, stat=%i (errno=%i/%s)\n", pid, status, errno, sys_errlist[errno]); } printf("THREAD HANDLER: Setting condition\n"); pthread_mutex_lock(&cond_mutex); done = 1; pthread_cond_signal(&cond); pthread_mutex_unlock(&cond_mutex); printf("THREAD HANDLER: quiting\n"); return NULL; } ---------------------------------
GNU PR# 1273: http://www-gnats.gnu.org:8080/cgi-bin/wwwgnats.pl/full/1273 GNU PR# 1305: http://www-gnats.gnu.org:8080/cgi-bin/wwwgnats.pl/full/1305 The short of it is a need to upgrade to 2.1.3 for certain programs. The multithreaded webserver AOLserver also has problems with glibc 2.1.2, whereas it did not have problems with 2.1.1. -- Lamar Owen WGCR Internet Radio
assign to jakub
Bug 7510 seems to have been fixed in newer versions of glibc that came out after 6.1. You SHOULD test this against the 8.0.93 Phoebe beta since it incorporates a new threading model in glibc. It will also have more eyes on fixing it in that release.