summaryrefslogtreecommitdiff
path: root/lib/pthreadpool/tests.c
diff options
context:
space:
mode:
authorVolker Lendecke <vl@samba.org>2017-08-29 21:57:54 +0200
committerVolker Lendecke <vl@samba.org>2017-08-31 21:34:57 +0200
commit981e674a7472017274c9b169c776d5c5e8bd1469 (patch)
treee348763893e8209a4d3a30435c319406e30f2c30 /lib/pthreadpool/tests.c
parentff98e3fb666b57b56a1427aa1196948ceebdec66 (diff)
downloadsamba-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.c114
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;
}