Project

General

Profile

Bug #11265 ยป test-solaris-fork-deadlock.c

ngoto (Naohisa Goto), 06/25/2015 07:45 AM

 
/*
Solaris: (Oracle SolarisStudio 12.x)
% cc -mt -g -m64 -o test-solaris-fork-deadlock test-solaris-fork-deadlock.c \
-ldl -lpthread

Linux: (-D_GNU_SOURCE is needed for RTLD_DEFAULT)
% gcc -g -D_GNU_SOURCE -o test-solaris-fork-deadlock.linux \
test-solaris-fork-deadlock.c -ldl -pthread
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dlfcn.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/wait.h>

/* workaround for Linux */
#if !defined(RTLD_PROBE)
#define RTLD_PROBE RTLD_DEFAULT
#endif

struct data_for_loop_dlsym {
const char *name;
volatile int stop;
void *ptr;
};

static void*
loop_dlsym(void *data)
{
struct data_for_loop_dlsym *s = data;
void *ptr = NULL;

while (!(s->stop)) {
ptr = s->ptr = dlsym(RTLD_PROBE, s->name);
}

return ptr;
}

void do_fork_or_vfork(int flag_v)
{
pid_t pid;
extern char **environ;

if (flag_v) {
fprintf(stderr, "calling vfork()\n");
pid = vfork();
} else {
fprintf(stderr, "calling fork()\n");
pid = fork();
}
if (pid < 0) {
fprintf(stderr, "Error: v?fork returns %ld\n", (long)pid);
exit(3);
} else if (pid == 0) {
/* child process */
execle("/bin/echo", "echo", "child echo output",
NULL, environ);
/* error of execle */
_exit(4);
} else {
/* this process */
pid_t ret;
int stat;

fprintf(stderr, "waiting for child pid %ld\n", (long)pid);
ret = waitpid(pid, &stat, 0);
fprintf(stderr, "waitpid returns %ld with status %d\n", (long)ret, stat);
}
return;
}

void usage(const char *argv0)
{
printf("Usage: %s SYMBOL [fork|vfork]\n", argv0);
printf("Example: %s printf\n", argv0);
printf("Example: %s malloc fork\n", argv0);
printf("Example: %s _ex_unwind vfork\n", argv0);
return;
}

int main(int argc, char *argv[])
{
pthread_t tid;
int ret;
struct data_for_loop_dlsym d;
void *pth_status;
int flag_v = 0;

if (argc <= 1 || argc > 3) {
usage(argv[0]);
exit(0);
}

d.stop = 0;
d.name = argv[1];
d.ptr = (void *)main;

if (argv[2] != NULL) {
if (strcmp(argv[2], "fork") == 0) {
flag_v = 0;
} else if (strcmp(argv[2], "vfork") == 0) {
flag_v = 1;
} else {
fprintf(stderr, "Error: 3rd arg must be fork or vfork (default fork)\n");
usage(argv[0]);
exit(1);
}
}

fprintf(stderr, "this process: getpid() => %ld\n", (long)getpid());

ret = pthread_create(&tid, NULL, loop_dlsym, &d);
if (ret != 0) {
fprintf(stderr, "Error: pthread_create returns %d\n", ret);
exit(2);
}

while (d.ptr == (void *)main) {
fprintf(stderr, "sleep(1)\n");
sleep(1);
fprintf(stderr, "wake up\n");
}
fprintf(stderr, "dlsym returns %p\n", d.ptr);

do_fork_or_vfork(flag_v);

d.stop = 1;

ret = pthread_join(tid, &pth_status);
fprintf(stderr, "pthread_join returns %d with status %p\n", ret, pth_status);

fprintf(stderr, "end normally\n");
return 0;
}
    (1-1/1)