diff options
author | Volker Lendecke <vl@samba.org> | 2017-08-29 21:57:54 +0200 |
---|---|---|
committer | Volker Lendecke <vl@samba.org> | 2017-08-31 21:34:57 +0200 |
commit | 981e674a7472017274c9b169c776d5c5e8bd1469 (patch) | |
tree | e348763893e8209a4d3a30435c319406e30f2c30 /lib/pthreadpool/tests.c | |
parent | ff98e3fb666b57b56a1427aa1196948ceebdec66 (diff) | |
download | samba-981e674a7472017274c9b169c776d5c5e8bd1469.tar.gz |
pthreadpool: Test fork with an active thread
Bug: https://bugzilla.samba.org/show_bug.cgi?id=13006
Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
Autobuild-User(master): Volker Lendecke <vl@samba.org>
Autobuild-Date(master): Thu Aug 31 21:34:57 CEST 2017 on sn-devel-144
Diffstat (limited to 'lib/pthreadpool/tests.c')
-rw-r--r-- | lib/pthreadpool/tests.c | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/lib/pthreadpool/tests.c b/lib/pthreadpool/tests.c index c4d2e6a1382..999118286eb 100644 --- a/lib/pthreadpool/tests.c +++ b/lib/pthreadpool/tests.c @@ -7,6 +7,7 @@ #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> +#include <signal.h> #include "pthreadpool_pipe.h" #include "pthreadpool_tevent.h" @@ -192,6 +193,113 @@ static int test_fork(void) return 0; } +static void busyfork_job(void *private_data) +{ + return; +} + +static int test_busyfork(void) +{ + struct pthreadpool_pipe *p; + int fds[2]; + struct pollfd pfd; + pid_t child, waitret; + int ret, jobnum, wstatus; + + ret = pipe(fds); + if (ret == -1) { + perror("pipe failed"); + return -1; + } + + ret = pthreadpool_pipe_init(1, &p); + if (ret != 0) { + fprintf(stderr, "pthreadpool_pipe_init failed: %s\n", + strerror(ret)); + return -1; + } + + ret = pthreadpool_pipe_add_job(p, 1, busyfork_job, NULL); + if (ret != 0) { + fprintf(stderr, "pthreadpool_add_job failed: %s\n", + strerror(ret)); + return -1; + } + + ret = pthreadpool_pipe_finished_jobs(p, &jobnum, 1); + if (ret != 1) { + fprintf(stderr, "pthreadpool_pipe_finished_jobs failed\n"); + return -1; + } + + poll(NULL, 0, 200); + + child = fork(); + if (child < 0) { + perror("fork failed"); + return -1; + } + + if (child == 0) { + ret = pthreadpool_pipe_destroy(p); + if (ret != 0) { + fprintf(stderr, "pthreadpool_pipe_destroy failed: " + "%s\n", strerror(ret)); + exit(1); + } + exit(0); + } + + ret = close(fds[1]); + if (ret == -1) { + perror("close failed"); + return -1; + } + + pfd = (struct pollfd) { .fd = fds[0], .events = POLLIN }; + + ret = poll(&pfd, 1, 5000); + if (ret == -1) { + perror("poll failed"); + return -1; + } + if (ret == 0) { + fprintf(stderr, "Child did not exit for 5 seconds\n"); + /* + * The child might hang forever in + * pthread_cond_destroy for example. Be kind to the + * system and kill it. + */ + kill(child, SIGTERM); + return -1; + } + if (ret != 1) { + fprintf(stderr, "poll returned %d -- huh??\n", ret); + return -1; + } + + poll(NULL, 0, 200); + + waitret = waitpid(child, &wstatus, WNOHANG); + if (waitret != child) { + fprintf(stderr, "waitpid returned %d\n", (int)waitret); + return -1; + } + + if (!WIFEXITED(wstatus)) { + fprintf(stderr, "child did not properly exit\n"); + return -1; + } + + ret = WEXITSTATUS(wstatus); + if (ret != 0) { + fprintf(stderr, "child returned %d\n", ret); + return -1; + } + + return 0; +} + static void test_tevent_wait(void *private_data) { int *timeout = private_data; @@ -301,6 +409,12 @@ int main(void) return 1; } + ret = test_busyfork(); + if (ret != 0) { + fprintf(stderr, "test_busyfork failed\n"); + return 1; + } + printf("success\n"); return 0; } |