diff options
author | Volker Lendecke <vl@samba.org> | 2017-11-29 18:55:21 +0100 |
---|---|---|
committer | Karolin Seeger <kseeger@samba.org> | 2017-12-14 12:22:18 +0100 |
commit | dce01acabed7fc8e8ad35369971f0cfd2ddefbc3 (patch) | |
tree | 31f4395a865a324c5a9a432fbabd7d5886690f54 /lib/pthreadpool | |
parent | b418ab369876f6aff08ee564a7f07d9e5dc0bcc0 (diff) | |
download | samba-dce01acabed7fc8e8ad35369971f0cfd2ddefbc3.tar.gz |
pthreadpool: Add a test for the race condition fixed in the last commit
Bug: https://bugzilla.samba.org/show_bug.cgi?id=13179
Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
(cherry picked from commit 53f7bbca0451e4f57cdbe8ab4f67f601fe8d40c1)
Diffstat (limited to 'lib/pthreadpool')
-rw-r--r-- | lib/pthreadpool/tests.c | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/lib/pthreadpool/tests.c b/lib/pthreadpool/tests.c index 999118286eb..0ea285d970e 100644 --- a/lib/pthreadpool/tests.c +++ b/lib/pthreadpool/tests.c @@ -300,6 +300,82 @@ static int test_busyfork(void) return 0; } +static int test_busyfork2(void) +{ + struct pthreadpool_pipe *p; + pid_t child; + int ret, jobnum; + struct pollfd pfd; + + 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; + } + + ret = poll(NULL, 0, 10); + if (ret == -1) { + perror("poll failed"); + 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; + } + + /* + * Do the fork right after the add_job. This tests a race + * where the atfork prepare handler gets all idle threads off + * the condvar. If we are faster doing the fork than the + * existing idle thread could get out of idle and take the + * job, after the fork we end up with no threads to take care + * of the job. + */ + + child = fork(); + if (child < 0) { + perror("fork failed"); + return -1; + } + + if (child == 0) { + exit(0); + } + + pfd = (struct pollfd) { + .fd = pthreadpool_pipe_signal_fd(p), + .events = POLLIN|POLLERR + }; + + do { + ret = poll(&pfd, 1, 5000); + } while ((ret == -1) && (errno == EINTR)); + + if (ret == 0) { + fprintf(stderr, "job unfinished after 5 seconds\n"); + return -1; + } + + return 0; +} + static void test_tevent_wait(void *private_data) { int *timeout = private_data; @@ -415,6 +491,12 @@ int main(void) return 1; } + ret = test_busyfork2(); + if (ret != 0) { + fprintf(stderr, "test_busyfork2 failed\n"); + return 1; + } + printf("success\n"); return 0; } |