s4:rpc_server: fix DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN negotiation to match Windows
[Samba.git] / lib / pthreadpool / tests.c
blobd57754603a23e63cbab2fc685d212ccfdf70f7df
1 #include <stdio.h>
2 #include <string.h>
3 #include <poll.h>
4 #include <errno.h>
5 #include <stdlib.h>
6 #include <limits.h>
7 #include <pthread.h>
8 #include <unistd.h>
9 #include <sys/types.h>
10 #include <sys/wait.h>
11 #include <signal.h>
12 #include "pthreadpool_pipe.h"
13 #include "pthreadpool_tevent.h"
15 static int test_init(void)
17 struct pthreadpool_pipe *p;
18 int ret;
20 ret = pthreadpool_pipe_init(1, &p);
21 if (ret != 0) {
22 fprintf(stderr, "pthreadpool_pipe_init failed: %s\n",
23 strerror(ret));
24 return -1;
26 ret = pthreadpool_pipe_destroy(p);
27 if (ret != 0) {
28 fprintf(stderr, "pthreadpool_pipe_destroy failed: %s\n",
29 strerror(ret));
30 return -1;
32 return 0;
35 static void test_sleep(void *ptr)
37 int *ptimeout = (int *)ptr;
38 int ret;
39 ret = poll(NULL, 0, *ptimeout);
40 if (ret != 0) {
41 fprintf(stderr, "poll returned %d (%s)\n",
42 ret, strerror(errno));
46 static int test_jobs(int num_threads, int num_jobs)
48 char *finished;
49 struct pthreadpool_pipe *p;
50 int timeout = 1;
51 int i, ret;
53 finished = (char *)calloc(1, num_jobs);
54 if (finished == NULL) {
55 fprintf(stderr, "calloc failed\n");
56 return -1;
59 ret = pthreadpool_pipe_init(num_threads, &p);
60 if (ret != 0) {
61 fprintf(stderr, "pthreadpool_pipe_init failed: %s\n",
62 strerror(ret));
63 return -1;
66 for (i=0; i<num_jobs; i++) {
67 ret = pthreadpool_pipe_add_job(p, i, test_sleep, &timeout);
68 if (ret != 0) {
69 fprintf(stderr, "pthreadpool_pipe_add_job failed: "
70 "%s\n", strerror(ret));
71 return -1;
75 for (i=0; i<num_jobs; i++) {
76 int jobid = -1;
77 ret = pthreadpool_pipe_finished_jobs(p, &jobid, 1);
78 if (ret < 0) {
79 fprintf(stderr, "pthreadpool_pipe_finished_jobs "
80 "failed: %s\n", strerror(-ret));
81 return -1;
83 if ((ret != 1) || (jobid >= num_jobs)) {
84 fprintf(stderr, "invalid job number %d\n", jobid);
85 return -1;
87 finished[jobid] += 1;
90 for (i=0; i<num_jobs; i++) {
91 if (finished[i] != 1) {
92 fprintf(stderr, "finished[%d] = %d\n",
93 i, finished[i]);
94 return -1;
98 ret = pthreadpool_pipe_destroy(p);
99 if (ret != 0) {
100 fprintf(stderr, "pthreadpool_pipe_destroy failed: %s\n",
101 strerror(ret));
102 return -1;
105 free(finished);
106 return 0;
109 static int test_busydestroy(void)
111 struct pthreadpool_pipe *p;
112 int timeout = 50;
113 struct pollfd pfd;
114 int ret, jobid;
116 ret = pthreadpool_pipe_init(1, &p);
117 if (ret != 0) {
118 fprintf(stderr, "pthreadpool_pipe_init failed: %s\n",
119 strerror(ret));
120 return -1;
122 ret = pthreadpool_pipe_add_job(p, 1, test_sleep, &timeout);
123 if (ret != 0) {
124 fprintf(stderr, "pthreadpool_pipe_add_job failed: %s\n",
125 strerror(ret));
126 return -1;
128 ret = pthreadpool_pipe_destroy(p);
129 if (ret != EBUSY) {
130 fprintf(stderr, "Could destroy a busy pool\n");
131 return -1;
134 pfd.fd = pthreadpool_pipe_signal_fd(p);
135 pfd.events = POLLIN|POLLERR;
137 do {
138 ret = poll(&pfd, 1, -1);
139 } while ((ret == -1) && (errno == EINTR));
141 ret = pthreadpool_pipe_finished_jobs(p, &jobid, 1);
142 if (ret < 0) {
143 fprintf(stderr, "pthreadpool_pipe_finished_jobs failed: %s\n",
144 strerror(-ret));
145 return -1;
148 ret = pthreadpool_pipe_destroy(p);
149 if (ret != 0) {
150 fprintf(stderr, "pthreadpool_pipe_destroy failed: %s\n",
151 strerror(ret));
152 return -1;
154 return 0;
157 static int test_fork(void)
159 struct pthreadpool_pipe *p;
160 pid_t child, waited;
161 int status, ret;
163 ret = pthreadpool_pipe_init(1, &p);
164 if (ret != 0) {
165 fprintf(stderr, "pthreadpool_pipe_init failed: %s\n",
166 strerror(ret));
167 return -1;
169 ret = pthreadpool_pipe_destroy(p);
170 if (ret != 0) {
171 fprintf(stderr, "pthreadpool_pipe_destroy failed: %s\n",
172 strerror(ret));
173 return -1;
176 child = fork();
177 if (child < 0) {
178 perror("fork failed");
179 return -1;
181 if (child == 0) {
182 exit(0);
184 waited = wait(&status);
185 if (waited == -1) {
186 perror("wait failed");
187 return -1;
189 if (waited != child) {
190 fprintf(stderr, "expected child %d, got %d\n",
191 (int)child, (int)waited);
192 return -1;
194 return 0;
197 static void busyfork_job(void *private_data)
199 return;
202 static int test_busyfork(void)
204 struct pthreadpool_pipe *p;
205 int fds[2];
206 struct pollfd pfd;
207 pid_t child, waitret;
208 int ret, jobnum, wstatus;
210 ret = pipe(fds);
211 if (ret == -1) {
212 perror("pipe failed");
213 return -1;
216 ret = pthreadpool_pipe_init(1, &p);
217 if (ret != 0) {
218 fprintf(stderr, "pthreadpool_pipe_init failed: %s\n",
219 strerror(ret));
220 return -1;
223 ret = pthreadpool_pipe_add_job(p, 1, busyfork_job, NULL);
224 if (ret != 0) {
225 fprintf(stderr, "pthreadpool_add_job failed: %s\n",
226 strerror(ret));
227 return -1;
230 ret = pthreadpool_pipe_finished_jobs(p, &jobnum, 1);
231 if (ret != 1) {
232 fprintf(stderr, "pthreadpool_pipe_finished_jobs failed\n");
233 return -1;
236 ret = poll(NULL, 0, 200);
237 if (ret == -1) {
238 perror("poll failed");
239 return -1;
242 child = fork();
243 if (child < 0) {
244 perror("fork failed");
245 return -1;
248 if (child == 0) {
249 ret = pthreadpool_pipe_destroy(p);
250 if (ret != 0) {
251 fprintf(stderr, "pthreadpool_pipe_destroy failed: "
252 "%s\n", strerror(ret));
253 exit(1);
255 exit(0);
258 ret = close(fds[1]);
259 if (ret == -1) {
260 perror("close failed");
261 return -1;
264 pfd = (struct pollfd) { .fd = fds[0], .events = POLLIN };
266 ret = poll(&pfd, 1, 5000);
267 if (ret == -1) {
268 perror("poll failed");
269 return -1;
271 if (ret == 0) {
272 fprintf(stderr, "Child did not exit for 5 seconds\n");
274 * The child might hang forever in
275 * pthread_cond_destroy for example. Be kind to the
276 * system and kill it.
278 kill(child, SIGTERM);
279 return -1;
281 if (ret != 1) {
282 fprintf(stderr, "poll returned %d -- huh??\n", ret);
283 return -1;
286 ret = poll(NULL, 0, 200);
287 if (ret == -1) {
288 perror("poll failed");
289 return -1;
292 waitret = waitpid(child, &wstatus, WNOHANG);
293 if (waitret != child) {
294 fprintf(stderr, "waitpid returned %d\n", (int)waitret);
295 return -1;
298 if (!WIFEXITED(wstatus)) {
299 fprintf(stderr, "child did not properly exit\n");
300 return -1;
303 ret = WEXITSTATUS(wstatus);
304 if (ret != 0) {
305 fprintf(stderr, "child returned %d\n", ret);
306 return -1;
309 return 0;
312 static int test_busyfork2(void)
314 struct pthreadpool_pipe *p;
315 pid_t child;
316 int ret, jobnum;
317 struct pollfd pfd;
319 ret = pthreadpool_pipe_init(1, &p);
320 if (ret != 0) {
321 fprintf(stderr, "pthreadpool_pipe_init failed: %s\n",
322 strerror(ret));
323 return -1;
326 ret = pthreadpool_pipe_add_job(p, 1, busyfork_job, NULL);
327 if (ret != 0) {
328 fprintf(stderr, "pthreadpool_add_job failed: %s\n",
329 strerror(ret));
330 return -1;
333 ret = pthreadpool_pipe_finished_jobs(p, &jobnum, 1);
334 if (ret != 1) {
335 fprintf(stderr, "pthreadpool_pipe_finished_jobs failed\n");
336 return -1;
339 ret = poll(NULL, 0, 10);
340 if (ret == -1) {
341 perror("poll failed");
342 return -1;
345 ret = pthreadpool_pipe_add_job(p, 1, busyfork_job, NULL);
346 if (ret != 0) {
347 fprintf(stderr, "pthreadpool_add_job failed: %s\n",
348 strerror(ret));
349 return -1;
353 * Do the fork right after the add_job. This tests a race
354 * where the atfork prepare handler gets all idle threads off
355 * the condvar. If we are faster doing the fork than the
356 * existing idle thread could get out of idle and take the
357 * job, after the fork we end up with no threads to take care
358 * of the job.
361 child = fork();
362 if (child < 0) {
363 perror("fork failed");
364 return -1;
367 if (child == 0) {
368 exit(0);
371 pfd = (struct pollfd) {
372 .fd = pthreadpool_pipe_signal_fd(p),
373 .events = POLLIN|POLLERR
376 do {
377 ret = poll(&pfd, 1, 5000);
378 } while ((ret == -1) && (errno == EINTR));
380 if (ret == 0) {
381 fprintf(stderr, "job unfinished after 5 seconds\n");
382 return -1;
385 return 0;
388 static void test_tevent_wait(void *private_data)
390 int *timeout = private_data;
391 poll(NULL, 0, *timeout);
394 static int test_tevent_1(void)
396 struct tevent_context *ev;
397 struct pthreadpool_tevent *pool;
398 struct tevent_req *req1, *req2;
399 int timeout10 = 10;
400 int timeout100 = 100;
401 int ret;
402 bool ok;
404 ev = tevent_context_init(NULL);
405 if (ev == NULL) {
406 ret = errno;
407 fprintf(stderr, "tevent_context_init failed: %s\n",
408 strerror(ret));
409 return ret;
411 ret = pthreadpool_tevent_init(ev, UINT_MAX, &pool);
412 if (ret != 0) {
413 fprintf(stderr, "pthreadpool_tevent_init failed: %s\n",
414 strerror(ret));
415 TALLOC_FREE(ev);
416 return ret;
418 req1 = pthreadpool_tevent_job_send(
419 ev, ev, pool, test_tevent_wait, &timeout10);
420 if (req1 == NULL) {
421 fprintf(stderr, "pthreadpool_tevent_job_send failed\n");
422 TALLOC_FREE(ev);
423 return ENOMEM;
425 req2 = pthreadpool_tevent_job_send(
426 ev, ev, pool, test_tevent_wait, &timeout100);
427 if (req2 == NULL) {
428 fprintf(stderr, "pthreadpool_tevent_job_send failed\n");
429 TALLOC_FREE(ev);
430 return ENOMEM;
432 ok = tevent_req_poll(req2, ev);
433 if (!ok) {
434 ret = errno;
435 fprintf(stderr, "tevent_req_poll failed: %s\n",
436 strerror(ret));
437 TALLOC_FREE(ev);
438 return ret;
440 ret = pthreadpool_tevent_job_recv(req1);
441 TALLOC_FREE(req1);
442 if (ret != 0) {
443 fprintf(stderr, "tevent_req_poll failed: %s\n",
444 strerror(ret));
445 TALLOC_FREE(ev);
446 return ret;
449 TALLOC_FREE(req2);
451 ret = tevent_loop_wait(ev);
452 if (ret != 0) {
453 fprintf(stderr, "tevent_loop_wait failed\n");
454 return ret;
457 TALLOC_FREE(pool);
458 TALLOC_FREE(ev);
459 return 0;
462 int main(void)
464 int ret;
466 ret = test_tevent_1();
467 if (ret != 0) {
468 fprintf(stderr, "test_event_1 failed: %s\n",
469 strerror(ret));
470 return 1;
473 ret = test_init();
474 if (ret != 0) {
475 fprintf(stderr, "test_init failed\n");
476 return 1;
479 ret = test_fork();
480 if (ret != 0) {
481 fprintf(stderr, "test_fork failed\n");
482 return 1;
485 ret = test_jobs(10, 10000);
486 if (ret != 0) {
487 fprintf(stderr, "test_jobs failed\n");
488 return 1;
491 ret = test_busydestroy();
492 if (ret != 0) {
493 fprintf(stderr, "test_busydestroy failed\n");
494 return 1;
497 ret = test_busyfork();
498 if (ret != 0) {
499 fprintf(stderr, "test_busyfork failed\n");
500 return 1;
503 ret = test_busyfork2();
504 if (ret != 0) {
505 fprintf(stderr, "test_busyfork2 failed\n");
506 return 1;
509 printf("success\n");
510 return 0;