Bug#233589: waitpid fails to wait for termination of a process started from a different thread
Package:glibc
Version:2.3.2-90
Waitpid fails with errno 10 when called from a thread other than the one
that started the process being waited on. This happens regardless of whether
the threads were created with pthread_create() or clone() (see sample code).
The man pages installed on my system (see uname -a below), indicate that
libpthread/glibc support this behavior. From the LINUX NOTES section of the
man page for waitpid(2):
... since Linux 2.4 a thread can, and by default will, wait on children of
other threads in the same thread group...
my system
>uname -a
Linux amd64 2.4.21-193-smp #1 SMP Thu Jan 22 16:52:24 UTC 2004 x86_64 x86_64
x86_64 GNU/Linux
The sample code below demonstrates this problem.
<snippet>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <pthread.h>
static pthread_t processThreadId= 0;
extern char **environ;
#define STACKSIZE (1024 * 64)
#define USE_CLONE_FOR_THREADS 1
#define CLONE_FLAGS CLONE_PARENT | CLONE_THREAD | CLONE_FS | CLONE_FILES |
CLONE_SIGHAND | CLONE_VM
#if USE_CLONE_FOR_THREADS
int my_pthread_create( pthread_t *pthread, pthread_attr_t * attr, void
*(start_routine)(void *), void *arg)
{
void *stack = (void *)(long)malloc ((size_t)STACKSIZE);
fprintf(stderr, "my_pthread_create::Using clone\n" );
*pthread = (pthread_t)clone( (int(*)(void *))start_routine, (char *)stack
+ STACKSIZE, CLONE_FLAGS, arg );
return (*pthread>0?0:-1);
}
#else
#define my_pthread_create pthread_create
#endif
int my_system (const char *command)
{
int pid, status;
void *stack = malloc( 1024 * 64 );
if (command == 0)
return 1;
fprintf(stderr,"my_system::Using fork\n");
pid = fork();
if (pid == -1)
return -1;
if (pid == 0) {
char *argv[4];
argv[0] = "sh";
argv[1] = "-c";
argv[2] = (char *)command;
argv[3] = 0;
fprintf(stderr,"my_system::Chaining\n");
execve("/bin/sh", argv, environ);
fprintf(stderr,"my_system::Chaining failed!\n");
exit(127);
}
return pid;
}
void *WaitThread(void *arg)
{
int pid = *(int *)arg;
int rpid = 0;
int status = 0;
fprintf(stderr, "WaitThread::Start\n");
while(1)
{
fprintf(stderr,"WaitThread::Waiting on pid: %d\n",pid);
rpid = waitpid(pid, &status, __WCLONE );
if (rpid == -1)
{
fprintf(stderr,"WaitThread::Wait failed errno: %d\n",errno);
if (errno != EINTR)
break;
}
else
{
printf("WaitThread::success child status: %d\n",status);
break;
}
}
fprintf(stderr, "WaitThread::End\n");
return (void *)(long)rpid;
}
void *ProcessThread(void *arg)
{
int pid = 0;
pthread_t waitThreadId;
fprintf(stderr,"ProcessThread::Start\n");
pid = my_system("/bin/sleep 100");
if (pid == -1 )
{
fprintf(stderr, "ProcessThread::my_system failed errno : %d\n",
errno);
exit(pid);
}
else
{
fprintf(stderr, "ProcessThread::Child pid = %d\n", pid);
}
my_pthread_create(&waitThreadId, 0, WaitThread, (void *)&pid);
fprintf(stderr,"ProcessThread::End\n");
return 0;
}
int main()
{
fprintf(stderr,"Main::Start\n");
my_pthread_create(&processThreadId, 0, ProcessThread, 0);
sleep(1);
fprintf(stdout,"<Press return to end>");
fflush(stdout);
getchar();
fprintf(stderr,"Main::End\n");
return 0;
}
</snippet>
Here is the output of this program when using the clone() system call to
create threads, the behavior is the same when using pthread_create():
Main::Start
my_pthread_create::Using clone
ProcessThread::Start
my_system::Using fork
my_system::Chaining
ProcessThread::Child pid = 8678
my_pthread_create::Using clone
WaitThread::Start
WaitThread::Waiting on pid: 8678
WaitThread::Wait failed errno: 10
WaitThread::End
ProcessThread::End
<Press return to end>
Main::End
Thanks in advance for any feedback on this.
Cris.
Reply to: