Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : testing of the events subsystem
5 :
6 : Copyright (C) Stefan Metzmacher 2006-2009
7 : Copyright (C) Jeremy Allison 2013
8 :
9 : ** NOTE! The following LGPL license applies to the tevent
10 : ** library. This does NOT imply that all of Samba is released
11 : ** under the LGPL
12 :
13 : This library is free software; you can redistribute it and/or
14 : modify it under the terms of the GNU Lesser General Public
15 : License as published by the Free Software Foundation; either
16 : version 3 of the License, or (at your option) any later version.
17 :
18 : This library is distributed in the hope that it will be useful,
19 : but WITHOUT ANY WARRANTY; without even the implied warranty of
20 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 : Lesser General Public License for more details.
22 :
23 : You should have received a copy of the GNU Lesser General Public
24 : License along with this library; if not, see <http://www.gnu.org/licenses/>.
25 : */
26 :
27 : #include "includes.h"
28 : #define TEVENT_DEPRECATED 1
29 : #include "tevent.h"
30 : #include "system/filesys.h"
31 : #include "system/select.h"
32 : #include "system/network.h"
33 : #include "torture/torture.h"
34 : #include "torture/local/proto.h"
35 : #ifdef HAVE_PTHREAD
36 : #include "system/threads.h"
37 : #include <assert.h>
38 : #endif
39 :
40 : static struct tevent_context *
41 0 : test_tevent_context_init(TALLOC_CTX *mem_ctx)
42 : {
43 0 : struct tevent_context *ev = NULL;
44 :
45 0 : ev = tevent_context_init(mem_ctx);
46 0 : if (ev != NULL) {
47 0 : samba_tevent_set_debug(ev, "<default>");
48 : }
49 :
50 0 : return ev;
51 : }
52 :
53 : static struct tevent_context *
54 0 : test_tevent_context_init_byname(TALLOC_CTX *mem_ctx, const char *name)
55 : {
56 0 : struct tevent_context *ev = NULL;
57 :
58 0 : ev = tevent_context_init_byname(mem_ctx, name);
59 0 : if (ev != NULL) {
60 0 : samba_tevent_set_debug(ev, name);
61 : }
62 :
63 0 : return ev;
64 : }
65 :
66 : static int fde_count;
67 :
68 0 : static void do_read(int fd, void *buf, size_t count)
69 : {
70 : ssize_t ret;
71 :
72 : do {
73 0 : ret = read(fd, buf, count);
74 0 : } while (ret == -1 && errno == EINTR);
75 0 : }
76 :
77 0 : static void fde_handler_read(struct tevent_context *ev_ctx, struct tevent_fd *f,
78 : uint16_t flags, void *private_data)
79 : {
80 0 : int *fd = (int *)private_data;
81 : char c;
82 : #ifdef SA_SIGINFO
83 0 : kill(getpid(), SIGUSR1);
84 : #endif
85 0 : kill(getpid(), SIGALRM);
86 :
87 0 : do_read(fd[0], &c, 1);
88 0 : fde_count++;
89 0 : }
90 :
91 0 : static void do_write(int fd, void *buf, size_t count)
92 : {
93 : ssize_t ret;
94 :
95 : do {
96 0 : ret = write(fd, buf, count);
97 0 : } while (ret == -1 && errno == EINTR);
98 0 : }
99 :
100 0 : static void fde_handler_write(struct tevent_context *ev_ctx, struct tevent_fd *f,
101 : uint16_t flags, void *private_data)
102 : {
103 0 : int *fd = (int *)private_data;
104 0 : char c = 0;
105 :
106 0 : do_write(fd[1], &c, 1);
107 0 : }
108 :
109 :
110 : /* This will only fire if the fd's returned from pipe() are bi-directional. */
111 0 : static void fde_handler_read_1(struct tevent_context *ev_ctx, struct tevent_fd *f,
112 : uint16_t flags, void *private_data)
113 : {
114 0 : int *fd = (int *)private_data;
115 : char c;
116 : #ifdef SA_SIGINFO
117 0 : kill(getpid(), SIGUSR1);
118 : #endif
119 0 : kill(getpid(), SIGALRM);
120 :
121 0 : do_read(fd[1], &c, 1);
122 0 : fde_count++;
123 0 : }
124 :
125 : /* This will only fire if the fd's returned from pipe() are bi-directional. */
126 0 : static void fde_handler_write_1(struct tevent_context *ev_ctx, struct tevent_fd *f,
127 : uint16_t flags, void *private_data)
128 : {
129 0 : int *fd = (int *)private_data;
130 0 : char c = 0;
131 0 : do_write(fd[0], &c, 1);
132 0 : }
133 :
134 0 : static void finished_handler(struct tevent_context *ev_ctx, struct tevent_timer *te,
135 : struct timeval tval, void *private_data)
136 : {
137 0 : int *finished = (int *)private_data;
138 0 : (*finished) = 1;
139 0 : }
140 :
141 0 : static void count_handler(struct tevent_context *ev_ctx, struct tevent_signal *te,
142 : int signum, int count, void *info, void *private_data)
143 : {
144 0 : int *countp = (int *)private_data;
145 0 : (*countp) += count;
146 0 : }
147 :
148 0 : static bool test_event_context(struct torture_context *test,
149 : const void *test_data)
150 : {
151 : struct tevent_context *ev_ctx;
152 0 : int fd[2] = { -1, -1 };
153 0 : const char *backend = (const char *)test_data;
154 0 : int alarm_count=0, info_count=0;
155 : struct tevent_fd *fde_read;
156 : struct tevent_fd *fde_read_1;
157 : struct tevent_fd *fde_write;
158 : struct tevent_fd *fde_write_1;
159 : #ifdef SA_RESTART
160 0 : struct tevent_signal *se1 = NULL;
161 : #endif
162 : #ifdef SA_RESETHAND
163 0 : struct tevent_signal *se2 = NULL;
164 : #endif
165 : #ifdef SA_SIGINFO
166 0 : struct tevent_signal *se3 = NULL;
167 : #endif
168 0 : int finished=0;
169 : struct timeval t;
170 : int ret;
171 :
172 0 : ev_ctx = test_tevent_context_init_byname(test, backend);
173 0 : if (ev_ctx == NULL) {
174 0 : torture_comment(test, "event backend '%s' not supported\n", backend);
175 0 : return true;
176 : }
177 :
178 0 : torture_comment(test, "backend '%s' - %s\n",
179 : backend, __FUNCTION__);
180 :
181 : /* reset globals */
182 0 : fde_count = 0;
183 :
184 : /* create a pipe */
185 0 : ret = pipe(fd);
186 0 : torture_assert_int_equal(test, ret, 0, "pipe failed");
187 :
188 0 : fde_read = tevent_add_fd(ev_ctx, ev_ctx, fd[0], TEVENT_FD_READ,
189 : fde_handler_read, fd);
190 0 : fde_write_1 = tevent_add_fd(ev_ctx, ev_ctx, fd[0], TEVENT_FD_WRITE,
191 : fde_handler_write_1, fd);
192 :
193 0 : fde_write = tevent_add_fd(ev_ctx, ev_ctx, fd[1], TEVENT_FD_WRITE,
194 : fde_handler_write, fd);
195 0 : fde_read_1 = tevent_add_fd(ev_ctx, ev_ctx, fd[1], TEVENT_FD_READ,
196 : fde_handler_read_1, fd);
197 :
198 0 : tevent_fd_set_auto_close(fde_read);
199 0 : tevent_fd_set_auto_close(fde_write);
200 :
201 0 : tevent_add_timer(ev_ctx, ev_ctx, timeval_current_ofs(2,0),
202 : finished_handler, &finished);
203 :
204 : #ifdef SA_RESTART
205 0 : se1 = tevent_add_signal(ev_ctx, ev_ctx, SIGALRM, SA_RESTART, count_handler, &alarm_count);
206 0 : torture_assert(test, se1 != NULL, "failed to setup se1");
207 : #endif
208 : #ifdef SA_RESETHAND
209 0 : se2 = tevent_add_signal(ev_ctx, ev_ctx, SIGALRM, SA_RESETHAND, count_handler, &alarm_count);
210 0 : torture_assert(test, se2 != NULL, "failed to setup se2");
211 : #endif
212 : #ifdef SA_SIGINFO
213 0 : se3 = tevent_add_signal(ev_ctx, ev_ctx, SIGUSR1, SA_SIGINFO, count_handler, &info_count);
214 0 : torture_assert(test, se3 != NULL, "failed to setup se3");
215 : #endif
216 :
217 0 : t = timeval_current();
218 0 : while (!finished) {
219 0 : errno = 0;
220 0 : if (tevent_loop_once(ev_ctx) == -1) {
221 0 : TALLOC_FREE(ev_ctx);
222 0 : torture_fail(test, talloc_asprintf(test, "Failed event loop %s\n", strerror(errno)));
223 : return false;
224 : }
225 : }
226 :
227 0 : talloc_free(fde_read_1);
228 0 : talloc_free(fde_write_1);
229 0 : talloc_free(fde_read);
230 0 : talloc_free(fde_write);
231 :
232 0 : while (alarm_count < fde_count+1) {
233 0 : if (tevent_loop_once(ev_ctx) == -1) {
234 0 : break;
235 : }
236 : }
237 :
238 0 : torture_comment(test, "Got %.2f pipe events/sec\n", fde_count/timeval_elapsed(&t));
239 :
240 : #ifdef SA_RESTART
241 0 : talloc_free(se1);
242 : #endif
243 :
244 0 : torture_assert_int_equal(test, alarm_count, 1+fde_count, "alarm count mismatch");
245 :
246 : #ifdef SA_RESETHAND
247 : /*
248 : * we do not call talloc_free(se2)
249 : * because it is already gone,
250 : * after triggering the event handler.
251 : */
252 : #endif
253 :
254 : #ifdef SA_SIGINFO
255 0 : talloc_free(se3);
256 0 : torture_assert_int_equal(test, info_count, fde_count, "info count mismatch");
257 : #endif
258 :
259 0 : talloc_free(ev_ctx);
260 :
261 0 : return true;
262 : }
263 :
264 : struct test_event_fd1_state {
265 : struct torture_context *tctx;
266 : const char *backend;
267 : struct tevent_context *ev;
268 : int sock[2];
269 : struct tevent_timer *te;
270 : struct tevent_fd *fde0;
271 : struct tevent_fd *fde1;
272 : bool got_write;
273 : bool got_read;
274 : bool drain;
275 : bool drain_done;
276 : unsigned loop_count;
277 : bool finished;
278 : const char *error;
279 : };
280 :
281 0 : static void test_event_fd1_fde_handler(struct tevent_context *ev_ctx,
282 : struct tevent_fd *fde,
283 : uint16_t flags,
284 : void *private_data)
285 : {
286 0 : struct test_event_fd1_state *state =
287 : (struct test_event_fd1_state *)private_data;
288 :
289 0 : if (state->drain_done) {
290 0 : state->finished = true;
291 0 : state->error = __location__;
292 0 : return;
293 : }
294 :
295 0 : if (state->drain) {
296 : ssize_t ret;
297 0 : uint8_t c = 0;
298 :
299 0 : if (!(flags & TEVENT_FD_READ)) {
300 0 : state->finished = true;
301 0 : state->error = __location__;
302 0 : return;
303 : }
304 :
305 0 : ret = read(state->sock[0], &c, 1);
306 0 : if (ret == 1) {
307 0 : return;
308 : }
309 :
310 : /*
311 : * end of test...
312 : */
313 0 : tevent_fd_set_flags(fde, 0);
314 0 : state->drain_done = true;
315 0 : return;
316 : }
317 :
318 0 : if (!state->got_write) {
319 0 : uint8_t c = 0;
320 :
321 0 : if (flags != TEVENT_FD_WRITE) {
322 0 : state->finished = true;
323 0 : state->error = __location__;
324 0 : return;
325 : }
326 0 : state->got_write = true;
327 :
328 : /*
329 : * we write to the other socket...
330 : */
331 0 : do_write(state->sock[1], &c, 1);
332 0 : TEVENT_FD_NOT_WRITEABLE(fde);
333 0 : TEVENT_FD_READABLE(fde);
334 0 : return;
335 : }
336 :
337 0 : if (!state->got_read) {
338 0 : if (flags != TEVENT_FD_READ) {
339 0 : state->finished = true;
340 0 : state->error = __location__;
341 0 : return;
342 : }
343 0 : state->got_read = true;
344 :
345 0 : TEVENT_FD_NOT_READABLE(fde);
346 0 : return;
347 : }
348 :
349 0 : state->finished = true;
350 0 : state->error = __location__;
351 0 : return;
352 : }
353 :
354 0 : static void test_event_fd1_finished(struct tevent_context *ev_ctx,
355 : struct tevent_timer *te,
356 : struct timeval tval,
357 : void *private_data)
358 : {
359 0 : struct test_event_fd1_state *state =
360 : (struct test_event_fd1_state *)private_data;
361 :
362 0 : if (state->drain_done) {
363 0 : state->finished = true;
364 0 : return;
365 : }
366 :
367 0 : if (!state->got_write) {
368 0 : state->finished = true;
369 0 : state->error = __location__;
370 0 : return;
371 : }
372 :
373 0 : if (!state->got_read) {
374 0 : state->finished = true;
375 0 : state->error = __location__;
376 0 : return;
377 : }
378 :
379 0 : state->loop_count++;
380 0 : if (state->loop_count > 3) {
381 0 : state->finished = true;
382 0 : state->error = __location__;
383 0 : return;
384 : }
385 :
386 0 : state->got_write = false;
387 0 : state->got_read = false;
388 :
389 0 : tevent_fd_set_flags(state->fde0, TEVENT_FD_WRITE);
390 :
391 0 : if (state->loop_count > 2) {
392 0 : state->drain = true;
393 0 : TALLOC_FREE(state->fde1);
394 0 : TEVENT_FD_READABLE(state->fde0);
395 : }
396 :
397 0 : state->te = tevent_add_timer(state->ev, state->ev,
398 : timeval_current_ofs(0,2000),
399 : test_event_fd1_finished, state);
400 : }
401 :
402 0 : static bool test_event_fd1(struct torture_context *tctx,
403 : const void *test_data)
404 : {
405 : struct test_event_fd1_state state;
406 : int ret;
407 :
408 0 : ZERO_STRUCT(state);
409 0 : state.tctx = tctx;
410 0 : state.backend = (const char *)test_data;
411 :
412 0 : state.ev = test_tevent_context_init_byname(tctx, state.backend);
413 0 : if (state.ev == NULL) {
414 0 : torture_skip(tctx, talloc_asprintf(tctx,
415 : "event backend '%s' not supported\n",
416 : state.backend));
417 : return true;
418 : }
419 :
420 0 : torture_comment(tctx, "backend '%s' - %s\n",
421 : state.backend, __FUNCTION__);
422 :
423 : /*
424 : * This tests the following:
425 : *
426 : * It monitors the state of state.sock[0]
427 : * with tevent_fd, but we never read/write on state.sock[0]
428 : * while state.sock[1] * is only used to write a few bytes.
429 : *
430 : * We have a loop:
431 : * - we wait only for TEVENT_FD_WRITE on state.sock[0]
432 : * - we write 1 byte to state.sock[1]
433 : * - we wait only for TEVENT_FD_READ on state.sock[0]
434 : * - we disable events on state.sock[0]
435 : * - the timer event restarts the loop
436 : * Then we close state.sock[1]
437 : * We have a loop:
438 : * - we wait for TEVENT_FD_READ/WRITE on state.sock[0]
439 : * - we try to read 1 byte
440 : * - if the read gets an error of returns 0
441 : * we disable the event handler
442 : * - the timer finishes the test
443 : */
444 0 : state.sock[0] = -1;
445 0 : state.sock[1] = -1;
446 :
447 0 : ret = socketpair(AF_UNIX, SOCK_STREAM, 0, state.sock);
448 0 : torture_assert(tctx, ret == 0, "socketpair() failed");
449 :
450 0 : state.te = tevent_add_timer(state.ev, state.ev,
451 : timeval_current_ofs(0,10000),
452 : test_event_fd1_finished, &state);
453 0 : state.fde0 = tevent_add_fd(state.ev, state.ev,
454 : state.sock[0], TEVENT_FD_WRITE,
455 : test_event_fd1_fde_handler, &state);
456 : /* state.fde1 is only used to auto close */
457 0 : state.fde1 = tevent_add_fd(state.ev, state.ev,
458 : state.sock[1], 0,
459 : test_event_fd1_fde_handler, &state);
460 :
461 0 : tevent_fd_set_auto_close(state.fde0);
462 0 : tevent_fd_set_auto_close(state.fde1);
463 :
464 0 : while (!state.finished) {
465 0 : errno = 0;
466 0 : if (tevent_loop_once(state.ev) == -1) {
467 0 : talloc_free(state.ev);
468 0 : torture_fail(tctx, talloc_asprintf(tctx,
469 : "Failed event loop %s\n",
470 : strerror(errno)));
471 : }
472 : }
473 :
474 0 : talloc_free(state.ev);
475 :
476 0 : torture_assert(tctx, state.error == NULL, talloc_asprintf(tctx,
477 : "%s", state.error));
478 :
479 0 : return true;
480 : }
481 :
482 : struct test_event_fd2_state {
483 : struct torture_context *tctx;
484 : const char *backend;
485 : struct tevent_context *ev;
486 : struct tevent_timer *te;
487 : struct test_event_fd2_sock {
488 : struct test_event_fd2_state *state;
489 : int fd;
490 : struct tevent_fd *fde;
491 : size_t num_written;
492 : size_t num_read;
493 : bool got_full;
494 : } sock0, sock1;
495 : bool finished;
496 : const char *error;
497 : };
498 :
499 0 : static void test_event_fd2_sock_handler(struct tevent_context *ev_ctx,
500 : struct tevent_fd *fde,
501 : uint16_t flags,
502 : void *private_data)
503 : {
504 0 : struct test_event_fd2_sock *cur_sock =
505 : (struct test_event_fd2_sock *)private_data;
506 0 : struct test_event_fd2_state *state = cur_sock->state;
507 0 : struct test_event_fd2_sock *oth_sock = NULL;
508 0 : uint8_t v = 0, c;
509 : ssize_t ret;
510 :
511 0 : if (cur_sock == &state->sock0) {
512 0 : oth_sock = &state->sock1;
513 : } else {
514 0 : oth_sock = &state->sock0;
515 : }
516 :
517 0 : if (oth_sock->num_written == 1) {
518 0 : if (flags != (TEVENT_FD_READ | TEVENT_FD_WRITE)) {
519 0 : state->finished = true;
520 0 : state->error = __location__;
521 0 : return;
522 : }
523 : }
524 :
525 0 : if (cur_sock->num_read == oth_sock->num_written) {
526 0 : state->finished = true;
527 0 : state->error = __location__;
528 0 : return;
529 : }
530 :
531 0 : if (!(flags & TEVENT_FD_READ)) {
532 0 : state->finished = true;
533 0 : state->error = __location__;
534 0 : return;
535 : }
536 :
537 0 : if (oth_sock->num_read >= PIPE_BUF) {
538 : /*
539 : * On Linux we become writable once we've read
540 : * one byte. On Solaris we only become writable
541 : * again once we've read 4096 bytes. PIPE_BUF
542 : * is probably a safe bet to test against.
543 : *
544 : * There should be room to write a byte again
545 : */
546 0 : if (!(flags & TEVENT_FD_WRITE)) {
547 0 : state->finished = true;
548 0 : state->error = __location__;
549 0 : return;
550 : }
551 : }
552 :
553 0 : if ((flags & TEVENT_FD_WRITE) && !cur_sock->got_full) {
554 0 : v = (uint8_t)cur_sock->num_written;
555 0 : ret = write(cur_sock->fd, &v, 1);
556 0 : if (ret != 1) {
557 0 : state->finished = true;
558 0 : state->error = __location__;
559 0 : return;
560 : }
561 0 : cur_sock->num_written++;
562 0 : if (cur_sock->num_written > 0x80000000) {
563 0 : state->finished = true;
564 0 : state->error = __location__;
565 0 : return;
566 : }
567 0 : return;
568 : }
569 :
570 0 : if (!cur_sock->got_full) {
571 0 : cur_sock->got_full = true;
572 :
573 0 : if (!oth_sock->got_full) {
574 : /*
575 : * cur_sock is full,
576 : * lets wait for oth_sock
577 : * to be filled
578 : */
579 0 : tevent_fd_set_flags(cur_sock->fde, 0);
580 0 : return;
581 : }
582 :
583 : /*
584 : * oth_sock waited for cur_sock,
585 : * lets restart it
586 : */
587 0 : tevent_fd_set_flags(oth_sock->fde,
588 : TEVENT_FD_READ|TEVENT_FD_WRITE);
589 : }
590 :
591 0 : ret = read(cur_sock->fd, &v, 1);
592 0 : if (ret != 1) {
593 0 : state->finished = true;
594 0 : state->error = __location__;
595 0 : return;
596 : }
597 0 : c = (uint8_t)cur_sock->num_read;
598 0 : if (c != v) {
599 0 : state->finished = true;
600 0 : state->error = __location__;
601 0 : return;
602 : }
603 0 : cur_sock->num_read++;
604 :
605 0 : if (cur_sock->num_read < oth_sock->num_written) {
606 : /* there is more to read */
607 0 : return;
608 : }
609 : /*
610 : * we read everything, we need to remove TEVENT_FD_WRITE
611 : * to avoid spinning
612 : */
613 0 : TEVENT_FD_NOT_WRITEABLE(cur_sock->fde);
614 :
615 0 : if (oth_sock->num_read == cur_sock->num_written) {
616 : /*
617 : * both directions are finished
618 : */
619 0 : state->finished = true;
620 : }
621 :
622 0 : return;
623 : }
624 :
625 0 : static void test_event_fd2_finished(struct tevent_context *ev_ctx,
626 : struct tevent_timer *te,
627 : struct timeval tval,
628 : void *private_data)
629 : {
630 0 : struct test_event_fd2_state *state =
631 : (struct test_event_fd2_state *)private_data;
632 :
633 : /*
634 : * this should never be triggered
635 : */
636 0 : state->finished = true;
637 0 : state->error = __location__;
638 0 : }
639 :
640 0 : static bool test_event_fd2(struct torture_context *tctx,
641 : const void *test_data)
642 : {
643 : struct test_event_fd2_state state;
644 : int sock[2];
645 0 : uint8_t c = 0;
646 :
647 0 : ZERO_STRUCT(state);
648 0 : state.tctx = tctx;
649 0 : state.backend = (const char *)test_data;
650 :
651 0 : state.ev = test_tevent_context_init_byname(tctx, state.backend);
652 0 : if (state.ev == NULL) {
653 0 : torture_skip(tctx, talloc_asprintf(tctx,
654 : "event backend '%s' not supported\n",
655 : state.backend));
656 : return true;
657 : }
658 :
659 0 : torture_comment(tctx, "backend '%s' - %s\n",
660 : state.backend, __FUNCTION__);
661 :
662 : /*
663 : * This tests the following
664 : *
665 : * - We write 1 byte to each socket
666 : * - We wait for TEVENT_FD_READ/WRITE on both sockets
667 : * - When we get TEVENT_FD_WRITE we write 1 byte
668 : * until both socket buffers are full, which
669 : * means both sockets only get TEVENT_FD_READ.
670 : * - Then we read 1 byte until we have consumed
671 : * all bytes the other end has written.
672 : */
673 0 : sock[0] = -1;
674 0 : sock[1] = -1;
675 0 : socketpair(AF_UNIX, SOCK_STREAM, 0, sock);
676 :
677 : /*
678 : * the timer should never expire
679 : */
680 0 : state.te = tevent_add_timer(state.ev, state.ev,
681 : timeval_current_ofs(600, 0),
682 : test_event_fd2_finished, &state);
683 0 : state.sock0.state = &state;
684 0 : state.sock0.fd = sock[0];
685 0 : state.sock0.fde = tevent_add_fd(state.ev, state.ev,
686 : state.sock0.fd,
687 : TEVENT_FD_READ | TEVENT_FD_WRITE,
688 : test_event_fd2_sock_handler,
689 : &state.sock0);
690 0 : state.sock1.state = &state;
691 0 : state.sock1.fd = sock[1];
692 0 : state.sock1.fde = tevent_add_fd(state.ev, state.ev,
693 : state.sock1.fd,
694 : TEVENT_FD_READ | TEVENT_FD_WRITE,
695 : test_event_fd2_sock_handler,
696 : &state.sock1);
697 :
698 0 : tevent_fd_set_auto_close(state.sock0.fde);
699 0 : tevent_fd_set_auto_close(state.sock1.fde);
700 :
701 0 : do_write(state.sock0.fd, &c, 1);
702 0 : state.sock0.num_written++;
703 0 : do_write(state.sock1.fd, &c, 1);
704 0 : state.sock1.num_written++;
705 :
706 0 : while (!state.finished) {
707 0 : errno = 0;
708 0 : if (tevent_loop_once(state.ev) == -1) {
709 0 : talloc_free(state.ev);
710 0 : torture_fail(tctx, talloc_asprintf(tctx,
711 : "Failed event loop %s\n",
712 : strerror(errno)));
713 : }
714 : }
715 :
716 0 : talloc_free(state.ev);
717 :
718 0 : torture_assert(tctx, state.error == NULL, talloc_asprintf(tctx,
719 : "%s", state.error));
720 :
721 0 : return true;
722 : }
723 :
724 : struct test_wrapper_state {
725 : struct torture_context *tctx;
726 : int num_events;
727 : int num_wrap_handlers;
728 : };
729 :
730 0 : static bool test_wrapper_before_use(struct tevent_context *wrap_ev,
731 : void *private_data,
732 : struct tevent_context *main_ev,
733 : const char *location)
734 : {
735 : struct test_wrapper_state *state =
736 0 : talloc_get_type_abort(private_data,
737 : struct test_wrapper_state);
738 :
739 0 : torture_comment(state->tctx, "%s\n", __func__);
740 0 : state->num_wrap_handlers++;
741 0 : return true;
742 : }
743 :
744 0 : static void test_wrapper_after_use(struct tevent_context *wrap_ev,
745 : void *private_data,
746 : struct tevent_context *main_ev,
747 : const char *location)
748 : {
749 : struct test_wrapper_state *state =
750 0 : talloc_get_type_abort(private_data,
751 : struct test_wrapper_state);
752 :
753 0 : torture_comment(state->tctx, "%s\n", __func__);
754 0 : state->num_wrap_handlers++;
755 0 : }
756 :
757 0 : static void test_wrapper_before_fd_handler(struct tevent_context *wrap_ev,
758 : void *private_data,
759 : struct tevent_context *main_ev,
760 : struct tevent_fd *fde,
761 : uint16_t flags,
762 : const char *handler_name,
763 : const char *location)
764 : {
765 : struct test_wrapper_state *state =
766 0 : talloc_get_type_abort(private_data,
767 : struct test_wrapper_state);
768 :
769 0 : torture_comment(state->tctx, "%s\n", __func__);
770 0 : state->num_wrap_handlers++;
771 0 : }
772 :
773 0 : static void test_wrapper_after_fd_handler(struct tevent_context *wrap_ev,
774 : void *private_data,
775 : struct tevent_context *main_ev,
776 : struct tevent_fd *fde,
777 : uint16_t flags,
778 : const char *handler_name,
779 : const char *location)
780 : {
781 : struct test_wrapper_state *state =
782 0 : talloc_get_type_abort(private_data,
783 : struct test_wrapper_state);
784 :
785 0 : torture_comment(state->tctx, "%s\n", __func__);
786 0 : state->num_wrap_handlers++;
787 0 : }
788 :
789 0 : static void test_wrapper_before_timer_handler(struct tevent_context *wrap_ev,
790 : void *private_data,
791 : struct tevent_context *main_ev,
792 : struct tevent_timer *te,
793 : struct timeval requested_time,
794 : struct timeval trigger_time,
795 : const char *handler_name,
796 : const char *location)
797 : {
798 : struct test_wrapper_state *state =
799 0 : talloc_get_type_abort(private_data,
800 : struct test_wrapper_state);
801 :
802 0 : torture_comment(state->tctx, "%s\n", __func__);
803 0 : state->num_wrap_handlers++;
804 0 : }
805 :
806 0 : static void test_wrapper_after_timer_handler(struct tevent_context *wrap_ev,
807 : void *private_data,
808 : struct tevent_context *main_ev,
809 : struct tevent_timer *te,
810 : struct timeval requested_time,
811 : struct timeval trigger_time,
812 : const char *handler_name,
813 : const char *location)
814 : {
815 : struct test_wrapper_state *state =
816 0 : talloc_get_type_abort(private_data,
817 : struct test_wrapper_state);
818 :
819 0 : torture_comment(state->tctx, "%s\n", __func__);
820 0 : state->num_wrap_handlers++;
821 0 : }
822 :
823 0 : static void test_wrapper_before_immediate_handler(struct tevent_context *wrap_ev,
824 : void *private_data,
825 : struct tevent_context *main_ev,
826 : struct tevent_immediate *im,
827 : const char *handler_name,
828 : const char *location)
829 : {
830 : struct test_wrapper_state *state =
831 0 : talloc_get_type_abort(private_data,
832 : struct test_wrapper_state);
833 :
834 0 : torture_comment(state->tctx, "%s\n", __func__);
835 0 : state->num_wrap_handlers++;
836 0 : }
837 :
838 0 : static void test_wrapper_after_immediate_handler(struct tevent_context *wrap_ev,
839 : void *private_data,
840 : struct tevent_context *main_ev,
841 : struct tevent_immediate *im,
842 : const char *handler_name,
843 : const char *location)
844 : {
845 : struct test_wrapper_state *state =
846 0 : talloc_get_type_abort(private_data,
847 : struct test_wrapper_state);
848 :
849 0 : torture_comment(state->tctx, "%s\n", __func__);
850 0 : state->num_wrap_handlers++;
851 0 : }
852 :
853 0 : static void test_wrapper_before_signal_handler(struct tevent_context *wrap_ev,
854 : void *private_data,
855 : struct tevent_context *main_ev,
856 : struct tevent_signal *se,
857 : int signum,
858 : int count,
859 : void *siginfo,
860 : const char *handler_name,
861 : const char *location)
862 : {
863 : struct test_wrapper_state *state =
864 0 : talloc_get_type_abort(private_data,
865 : struct test_wrapper_state);
866 :
867 0 : torture_comment(state->tctx, "%s\n", __func__);
868 0 : state->num_wrap_handlers++;
869 0 : }
870 :
871 0 : static void test_wrapper_after_signal_handler(struct tevent_context *wrap_ev,
872 : void *private_data,
873 : struct tevent_context *main_ev,
874 : struct tevent_signal *se,
875 : int signum,
876 : int count,
877 : void *siginfo,
878 : const char *handler_name,
879 : const char *location)
880 : {
881 : struct test_wrapper_state *state =
882 0 : talloc_get_type_abort(private_data,
883 : struct test_wrapper_state);
884 :
885 0 : torture_comment(state->tctx, "%s\n", __func__);
886 0 : state->num_wrap_handlers++;
887 0 : }
888 :
889 : static const struct tevent_wrapper_ops test_wrapper_ops = {
890 : .name = "test_wrapper",
891 : .before_use = test_wrapper_before_use,
892 : .after_use = test_wrapper_after_use,
893 : .before_fd_handler = test_wrapper_before_fd_handler,
894 : .after_fd_handler = test_wrapper_after_fd_handler,
895 : .before_timer_handler = test_wrapper_before_timer_handler,
896 : .after_timer_handler = test_wrapper_after_timer_handler,
897 : .before_immediate_handler = test_wrapper_before_immediate_handler,
898 : .after_immediate_handler = test_wrapper_after_immediate_handler,
899 : .before_signal_handler = test_wrapper_before_signal_handler,
900 : .after_signal_handler = test_wrapper_after_signal_handler,
901 : };
902 :
903 0 : static void test_wrapper_timer_handler(struct tevent_context *ev,
904 : struct tevent_timer *te,
905 : struct timeval tv,
906 : void *private_data)
907 : {
908 0 : struct test_wrapper_state *state =
909 : (struct test_wrapper_state *)private_data;
910 :
911 :
912 0 : torture_comment(state->tctx, "timer handler\n");
913 :
914 0 : state->num_events++;
915 0 : talloc_free(te);
916 0 : return;
917 : }
918 :
919 0 : static void test_wrapper_fd_handler(struct tevent_context *ev,
920 : struct tevent_fd *fde,
921 : unsigned short fd_flags,
922 : void *private_data)
923 : {
924 0 : struct test_wrapper_state *state =
925 : (struct test_wrapper_state *)private_data;
926 :
927 0 : torture_comment(state->tctx, "fd handler\n");
928 :
929 0 : state->num_events++;
930 0 : talloc_free(fde);
931 0 : return;
932 : }
933 :
934 0 : static void test_wrapper_immediate_handler(struct tevent_context *ev,
935 : struct tevent_immediate *im,
936 : void *private_data)
937 : {
938 0 : struct test_wrapper_state *state =
939 : (struct test_wrapper_state *)private_data;
940 :
941 0 : state->num_events++;
942 0 : talloc_free(im);
943 :
944 0 : torture_comment(state->tctx, "immediate handler\n");
945 0 : return;
946 : }
947 :
948 0 : static void test_wrapper_signal_handler(struct tevent_context *ev,
949 : struct tevent_signal *se,
950 : int signum,
951 : int count,
952 : void *siginfo,
953 : void *private_data)
954 : {
955 0 : struct test_wrapper_state *state =
956 : (struct test_wrapper_state *)private_data;
957 :
958 0 : torture_comment(state->tctx, "signal handler\n");
959 :
960 0 : state->num_events++;
961 0 : talloc_free(se);
962 0 : return;
963 : }
964 :
965 0 : static bool test_wrapper(struct torture_context *tctx,
966 : const void *test_data)
967 : {
968 0 : struct test_wrapper_state *state = NULL;
969 0 : int sock[2] = { -1, -1};
970 0 : uint8_t c = 0;
971 0 : const int num_events = 4;
972 0 : const char *backend = (const char *)test_data;
973 0 : struct tevent_context *ev = NULL;
974 0 : struct tevent_context *wrap_ev = NULL;
975 0 : struct tevent_fd *fde = NULL;
976 0 : struct tevent_timer *te = NULL;
977 0 : struct tevent_signal *se = NULL;
978 0 : struct tevent_immediate *im = NULL;
979 : int ret;
980 0 : bool ok = false;
981 : bool ret2;
982 :
983 0 : ev = test_tevent_context_init_byname(tctx, backend);
984 0 : if (ev == NULL) {
985 0 : torture_skip(tctx, talloc_asprintf(tctx,
986 : "event backend '%s' not supported\n",
987 : backend));
988 : return true;
989 : }
990 :
991 0 : torture_comment(tctx, "tevent backend '%s'\n", backend);
992 :
993 0 : wrap_ev = tevent_context_wrapper_create(
994 : ev, ev, &test_wrapper_ops, &state, struct test_wrapper_state);
995 0 : torture_assert_not_null_goto(tctx, wrap_ev, ok, done,
996 : "tevent_context_wrapper_create failed\n");
997 0 : *state = (struct test_wrapper_state) {
998 : .tctx = tctx,
999 : };
1000 :
1001 0 : ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sock);
1002 0 : torture_assert_goto(tctx, ret == 0, ok, done, "socketpair failed\n");
1003 :
1004 0 : te = tevent_add_timer(wrap_ev, wrap_ev,
1005 : timeval_current_ofs(0, 0),
1006 : test_wrapper_timer_handler, state);
1007 0 : torture_assert_not_null_goto(tctx, te, ok, done,
1008 : "tevent_add_timer failed\n");
1009 :
1010 0 : fde = tevent_add_fd(wrap_ev, wrap_ev,
1011 : sock[1],
1012 : TEVENT_FD_READ,
1013 : test_wrapper_fd_handler,
1014 : state);
1015 0 : torture_assert_not_null_goto(tctx, fde, ok, done,
1016 : "tevent_add_fd failed\n");
1017 :
1018 0 : im = tevent_create_immediate(wrap_ev);
1019 0 : torture_assert_not_null_goto(tctx, im, ok, done,
1020 : "tevent_create_immediate failed\n");
1021 :
1022 0 : se = tevent_add_signal(wrap_ev, wrap_ev,
1023 : SIGUSR1,
1024 : 0,
1025 : test_wrapper_signal_handler,
1026 : state);
1027 0 : torture_assert_not_null_goto(tctx, se, ok, done,
1028 : "tevent_add_signal failed\n");
1029 :
1030 0 : do_write(sock[0], &c, 1);
1031 0 : kill(getpid(), SIGUSR1);
1032 0 : tevent_schedule_immediate(im,
1033 : wrap_ev,
1034 : test_wrapper_immediate_handler,
1035 : state);
1036 :
1037 0 : ret2 = tevent_context_push_use(wrap_ev);
1038 0 : torture_assert_goto(tctx, ret2, ok, done, "tevent_context_push_use(wrap_ev) failed\n");
1039 0 : ret2 = tevent_context_push_use(ev);
1040 0 : torture_assert_goto(tctx, ret2, ok, pop_use, "tevent_context_push_use(ev) failed\n");
1041 0 : tevent_context_pop_use(ev);
1042 0 : tevent_context_pop_use(wrap_ev);
1043 :
1044 0 : ret = tevent_loop_wait(ev);
1045 0 : torture_assert_int_equal_goto(tctx, ret, 0, ok, done, "tevent_loop_wait failed\n");
1046 :
1047 0 : torture_comment(tctx, "Num events: %d\n", state->num_events);
1048 0 : torture_comment(tctx, "Num wrap handlers: %d\n",
1049 0 : state->num_wrap_handlers);
1050 :
1051 0 : torture_assert_int_equal_goto(tctx, state->num_events, num_events, ok, done,
1052 : "Wrong event count\n");
1053 0 : torture_assert_int_equal_goto(tctx, state->num_wrap_handlers,
1054 : num_events*2+2,
1055 : ok, done, "Wrong wrapper count\n");
1056 :
1057 0 : ok = true;
1058 :
1059 0 : done:
1060 0 : TALLOC_FREE(wrap_ev);
1061 0 : TALLOC_FREE(ev);
1062 :
1063 0 : if (sock[0] != -1) {
1064 0 : close(sock[0]);
1065 : }
1066 0 : if (sock[1] != -1) {
1067 0 : close(sock[1]);
1068 : }
1069 0 : return ok;
1070 0 : pop_use:
1071 0 : tevent_context_pop_use(wrap_ev);
1072 0 : goto done;
1073 : }
1074 :
1075 0 : static void test_free_wrapper_signal_handler(struct tevent_context *ev,
1076 : struct tevent_signal *se,
1077 : int signum,
1078 : int count,
1079 : void *siginfo,
1080 : void *private_data)
1081 : {
1082 : struct torture_context *tctx =
1083 0 : talloc_get_type_abort(private_data,
1084 : struct torture_context);
1085 :
1086 0 : torture_comment(tctx, "signal handler\n");
1087 :
1088 0 : talloc_free(se);
1089 :
1090 : /*
1091 : * signal handlers have highest priority in tevent, so this signal
1092 : * handler will always be started before the other handlers
1093 : * below. Freeing the (wrapper) event context here tests that the
1094 : * wrapper implementation correclty handles the wrapper ev going away
1095 : * with pending events.
1096 : */
1097 0 : talloc_free(ev);
1098 0 : return;
1099 : }
1100 :
1101 0 : static void test_free_wrapper_fd_handler(struct tevent_context *ev,
1102 : struct tevent_fd *fde,
1103 : unsigned short fd_flags,
1104 : void *private_data)
1105 : {
1106 : /*
1107 : * This should never be called as
1108 : * test_free_wrapper_signal_handler()
1109 : * already destroyed the wrapper tevent_context.
1110 : */
1111 0 : abort();
1112 : }
1113 :
1114 0 : static void test_free_wrapper_immediate_handler(struct tevent_context *ev,
1115 : struct tevent_immediate *im,
1116 : void *private_data)
1117 : {
1118 : /*
1119 : * This should never be called as
1120 : * test_free_wrapper_signal_handler()
1121 : * already destroyed the wrapper tevent_context.
1122 : */
1123 0 : abort();
1124 : }
1125 :
1126 0 : static void test_free_wrapper_timer_handler(struct tevent_context *ev,
1127 : struct tevent_timer *te,
1128 : struct timeval tv,
1129 : void *private_data)
1130 : {
1131 : /*
1132 : * This should never be called as
1133 : * test_free_wrapper_signal_handler()
1134 : * already destroyed the wrapper tevent_context.
1135 : */
1136 0 : abort();
1137 : }
1138 :
1139 0 : static bool test_free_wrapper(struct torture_context *tctx,
1140 : const void *test_data)
1141 : {
1142 0 : struct test_wrapper_state *state = NULL;
1143 0 : int sock[2] = { -1, -1};
1144 0 : uint8_t c = 0;
1145 0 : const char *backend = (const char *)test_data;
1146 0 : TALLOC_CTX *frame = talloc_stackframe();
1147 0 : struct tevent_context *ev = NULL;
1148 0 : struct tevent_context *wrap_ev = NULL;
1149 0 : struct tevent_fd *fde = NULL;
1150 0 : struct tevent_timer *te = NULL;
1151 0 : struct tevent_signal *se = NULL;
1152 0 : struct tevent_immediate *im = NULL;
1153 : int ret;
1154 0 : bool ok = false;
1155 :
1156 0 : ev = test_tevent_context_init_byname(frame, backend);
1157 0 : if (ev == NULL) {
1158 0 : torture_skip(tctx, talloc_asprintf(tctx,
1159 : "event backend '%s' not supported\n",
1160 : backend));
1161 : return true;
1162 : }
1163 :
1164 0 : torture_comment(tctx, "tevent backend '%s'\n", backend);
1165 :
1166 0 : wrap_ev = tevent_context_wrapper_create(
1167 : ev, ev, &test_wrapper_ops, &state, struct test_wrapper_state);
1168 0 : torture_assert_not_null_goto(tctx, wrap_ev, ok, done,
1169 : "tevent_context_wrapper_create failed\n");
1170 0 : *state = (struct test_wrapper_state) {
1171 : .tctx = tctx,
1172 : };
1173 :
1174 0 : ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sock);
1175 0 : torture_assert_goto(tctx, ret == 0, ok, done, "socketpair failed\n");
1176 :
1177 0 : fde = tevent_add_fd(wrap_ev, frame,
1178 : sock[1],
1179 : TEVENT_FD_READ,
1180 : test_free_wrapper_fd_handler,
1181 : NULL);
1182 0 : torture_assert_not_null_goto(tctx, fde, ok, done,
1183 : "tevent_add_fd failed\n");
1184 :
1185 0 : te = tevent_add_timer(wrap_ev, frame,
1186 : timeval_current_ofs(0, 0),
1187 : test_free_wrapper_timer_handler, NULL);
1188 0 : torture_assert_not_null_goto(tctx, te, ok, done,
1189 : "tevent_add_timer failed\n");
1190 :
1191 0 : im = tevent_create_immediate(frame);
1192 0 : torture_assert_not_null_goto(tctx, im, ok, done,
1193 : "tevent_create_immediate failed\n");
1194 :
1195 0 : se = tevent_add_signal(wrap_ev, frame,
1196 : SIGUSR1,
1197 : 0,
1198 : test_free_wrapper_signal_handler,
1199 : tctx);
1200 0 : torture_assert_not_null_goto(tctx, se, ok, done,
1201 : "tevent_add_signal failed\n");
1202 :
1203 0 : do_write(sock[0], &c, 1);
1204 0 : kill(getpid(), SIGUSR1);
1205 0 : tevent_schedule_immediate(im,
1206 : wrap_ev,
1207 : test_free_wrapper_immediate_handler,
1208 : NULL);
1209 :
1210 0 : ret = tevent_loop_wait(ev);
1211 0 : torture_assert_goto(tctx, ret == 0, ok, done, "tevent_loop_wait failed\n");
1212 :
1213 0 : ok = true;
1214 :
1215 0 : done:
1216 0 : TALLOC_FREE(frame);
1217 :
1218 0 : if (sock[0] != -1) {
1219 0 : close(sock[0]);
1220 : }
1221 0 : if (sock[1] != -1) {
1222 0 : close(sock[1]);
1223 : }
1224 0 : return ok;
1225 : }
1226 :
1227 : #ifdef HAVE_PTHREAD
1228 :
1229 : static pthread_mutex_t threaded_mutex = PTHREAD_MUTEX_INITIALIZER;
1230 : static bool do_shutdown = false;
1231 :
1232 0 : static void test_event_threaded_lock(void)
1233 : {
1234 : int ret;
1235 0 : ret = pthread_mutex_lock(&threaded_mutex);
1236 0 : assert(ret == 0);
1237 0 : }
1238 :
1239 0 : static void test_event_threaded_unlock(void)
1240 : {
1241 : int ret;
1242 0 : ret = pthread_mutex_unlock(&threaded_mutex);
1243 0 : assert(ret == 0);
1244 0 : }
1245 :
1246 0 : static void test_event_threaded_trace(enum tevent_trace_point point,
1247 : void *private_data)
1248 : {
1249 0 : switch (point) {
1250 0 : case TEVENT_TRACE_BEFORE_WAIT:
1251 0 : test_event_threaded_unlock();
1252 0 : break;
1253 0 : case TEVENT_TRACE_AFTER_WAIT:
1254 0 : test_event_threaded_lock();
1255 0 : break;
1256 0 : case TEVENT_TRACE_BEFORE_LOOP_ONCE:
1257 : case TEVENT_TRACE_AFTER_LOOP_ONCE:
1258 0 : break;
1259 : }
1260 0 : }
1261 :
1262 0 : static void test_event_threaded_timer(struct tevent_context *ev,
1263 : struct tevent_timer *te,
1264 : struct timeval current_time,
1265 : void *private_data)
1266 : {
1267 0 : return;
1268 : }
1269 :
1270 0 : static void *test_event_poll_thread(void *private_data)
1271 : {
1272 0 : struct tevent_context *ev = (struct tevent_context *)private_data;
1273 :
1274 0 : test_event_threaded_lock();
1275 :
1276 0 : while (true) {
1277 : int ret;
1278 0 : ret = tevent_loop_once(ev);
1279 0 : assert(ret == 0);
1280 0 : if (do_shutdown) {
1281 0 : test_event_threaded_unlock();
1282 0 : return NULL;
1283 : }
1284 : }
1285 :
1286 : }
1287 :
1288 0 : static void test_event_threaded_read_handler(struct tevent_context *ev,
1289 : struct tevent_fd *fde,
1290 : uint16_t flags,
1291 : void *private_data)
1292 : {
1293 0 : int *pfd = (int *)private_data;
1294 : char c;
1295 : ssize_t nread;
1296 :
1297 0 : if ((flags & TEVENT_FD_READ) == 0) {
1298 0 : return;
1299 : }
1300 :
1301 : do {
1302 0 : nread = read(*pfd, &c, 1);
1303 0 : } while ((nread == -1) && (errno == EINTR));
1304 :
1305 0 : assert(nread == 1);
1306 : }
1307 :
1308 0 : static bool test_event_context_threaded(struct torture_context *test,
1309 : const void *test_data)
1310 : {
1311 : struct tevent_context *ev;
1312 : struct tevent_timer *te;
1313 : struct tevent_fd *fde;
1314 : pthread_t poll_thread;
1315 : int fds[2];
1316 : int ret;
1317 0 : char c = 0;
1318 :
1319 0 : ev = test_tevent_context_init_byname(test, "poll_mt");
1320 0 : torture_assert(test, ev != NULL, "poll_mt not supported");
1321 :
1322 0 : tevent_set_trace_callback(ev, test_event_threaded_trace, NULL);
1323 :
1324 0 : te = tevent_add_timer(ev, ev, timeval_current_ofs(5, 0),
1325 : test_event_threaded_timer, NULL);
1326 0 : torture_assert(test, te != NULL, "Could not add timer");
1327 :
1328 0 : ret = pthread_create(&poll_thread, NULL, test_event_poll_thread, ev);
1329 0 : torture_assert(test, ret == 0, "Could not create poll thread");
1330 :
1331 0 : ret = pipe(fds);
1332 0 : torture_assert(test, ret == 0, "Could not create pipe");
1333 :
1334 0 : poll(NULL, 0, 100);
1335 :
1336 0 : test_event_threaded_lock();
1337 :
1338 0 : fde = tevent_add_fd(ev, ev, fds[0], TEVENT_FD_READ,
1339 : test_event_threaded_read_handler, &fds[0]);
1340 0 : torture_assert(test, fde != NULL, "Could not add fd event");
1341 :
1342 0 : test_event_threaded_unlock();
1343 :
1344 0 : poll(NULL, 0, 100);
1345 :
1346 0 : do_write(fds[1], &c, 1);
1347 :
1348 0 : poll(NULL, 0, 100);
1349 :
1350 0 : test_event_threaded_lock();
1351 0 : do_shutdown = true;
1352 0 : test_event_threaded_unlock();
1353 :
1354 0 : do_write(fds[1], &c, 1);
1355 :
1356 0 : ret = pthread_join(poll_thread, NULL);
1357 0 : torture_assert(test, ret == 0, "pthread_join failed");
1358 :
1359 0 : return true;
1360 : }
1361 :
1362 : #define NUM_TEVENT_THREADS 100
1363 :
1364 : /* Ugly, but needed for torture_comment... */
1365 : static struct torture_context *thread_test_ctx;
1366 : static pthread_t thread_map[NUM_TEVENT_THREADS];
1367 : static unsigned thread_counter;
1368 :
1369 : /* Called in master thread context */
1370 0 : static void callback_nowait(struct tevent_context *ev,
1371 : struct tevent_immediate *im,
1372 : void *private_ptr)
1373 : {
1374 : pthread_t *thread_id_ptr =
1375 0 : talloc_get_type_abort(private_ptr, pthread_t);
1376 : unsigned i;
1377 :
1378 0 : for (i = 0; i < NUM_TEVENT_THREADS; i++) {
1379 0 : if (pthread_equal(*thread_id_ptr,
1380 : thread_map[i])) {
1381 0 : break;
1382 : }
1383 : }
1384 0 : torture_comment(thread_test_ctx,
1385 : "Callback %u from thread %u\n",
1386 : thread_counter,
1387 : i);
1388 0 : thread_counter++;
1389 0 : }
1390 :
1391 : /* Blast the master tevent_context with a callback, no waiting. */
1392 0 : static void *thread_fn_nowait(void *private_ptr)
1393 : {
1394 : struct tevent_thread_proxy *master_tp =
1395 0 : talloc_get_type_abort(private_ptr, struct tevent_thread_proxy);
1396 : struct tevent_immediate *im;
1397 : pthread_t *thread_id_ptr;
1398 :
1399 0 : im = tevent_create_immediate(NULL);
1400 0 : if (im == NULL) {
1401 0 : return NULL;
1402 : }
1403 0 : thread_id_ptr = talloc(NULL, pthread_t);
1404 0 : if (thread_id_ptr == NULL) {
1405 0 : return NULL;
1406 : }
1407 0 : *thread_id_ptr = pthread_self();
1408 :
1409 0 : tevent_thread_proxy_schedule(master_tp,
1410 : &im,
1411 : callback_nowait,
1412 : &thread_id_ptr);
1413 0 : return NULL;
1414 : }
1415 :
1416 0 : static void timeout_fn(struct tevent_context *ev,
1417 : struct tevent_timer *te,
1418 : struct timeval tv, void *p)
1419 : {
1420 0 : thread_counter = NUM_TEVENT_THREADS * 10;
1421 0 : }
1422 :
1423 0 : static bool test_multi_tevent_threaded(struct torture_context *test,
1424 : const void *test_data)
1425 : {
1426 : unsigned i;
1427 : struct tevent_context *master_ev;
1428 : struct tevent_thread_proxy *tp;
1429 :
1430 0 : talloc_disable_null_tracking();
1431 :
1432 : /* Ugly global stuff. */
1433 0 : thread_test_ctx = test;
1434 0 : thread_counter = 0;
1435 :
1436 0 : master_ev = test_tevent_context_init(NULL);
1437 0 : if (master_ev == NULL) {
1438 0 : return false;
1439 : }
1440 :
1441 0 : tp = tevent_thread_proxy_create(master_ev);
1442 0 : if (tp == NULL) {
1443 0 : torture_fail(test,
1444 : talloc_asprintf(test,
1445 : "tevent_thread_proxy_create failed\n"));
1446 : talloc_free(master_ev);
1447 : return false;
1448 : }
1449 :
1450 0 : for (i = 0; i < NUM_TEVENT_THREADS; i++) {
1451 0 : int ret = pthread_create(&thread_map[i],
1452 : NULL,
1453 : thread_fn_nowait,
1454 : tp);
1455 0 : if (ret != 0) {
1456 0 : torture_fail(test,
1457 : talloc_asprintf(test,
1458 : "Failed to create thread %i, %d\n",
1459 : i, ret));
1460 : return false;
1461 : }
1462 : }
1463 :
1464 : /* Ensure we don't wait more than 10 seconds. */
1465 0 : tevent_add_timer(master_ev,
1466 : master_ev,
1467 : timeval_current_ofs(10,0),
1468 : timeout_fn,
1469 : NULL);
1470 :
1471 0 : while (thread_counter < NUM_TEVENT_THREADS) {
1472 0 : int ret = tevent_loop_once(master_ev);
1473 0 : torture_assert(test, ret == 0, "tevent_loop_once failed");
1474 : }
1475 :
1476 0 : torture_assert(test, thread_counter == NUM_TEVENT_THREADS,
1477 : "thread_counter fail\n");
1478 :
1479 0 : talloc_free(master_ev);
1480 0 : return true;
1481 : }
1482 :
1483 : struct reply_state {
1484 : struct tevent_thread_proxy *reply_tp;
1485 : pthread_t thread_id;
1486 : int *p_finished;
1487 : };
1488 :
1489 0 : static void thread_timeout_fn(struct tevent_context *ev,
1490 : struct tevent_timer *te,
1491 : struct timeval tv, void *p)
1492 : {
1493 0 : int *p_finished = (int *)p;
1494 :
1495 0 : *p_finished = 2;
1496 0 : }
1497 :
1498 : /* Called in child-thread context */
1499 0 : static void thread_callback(struct tevent_context *ev,
1500 : struct tevent_immediate *im,
1501 : void *private_ptr)
1502 : {
1503 : struct reply_state *rsp =
1504 0 : talloc_get_type_abort(private_ptr, struct reply_state);
1505 :
1506 0 : talloc_steal(ev, rsp);
1507 0 : *rsp->p_finished = 1;
1508 0 : }
1509 :
1510 : /* Called in master thread context */
1511 0 : static void master_callback(struct tevent_context *ev,
1512 : struct tevent_immediate *im,
1513 : void *private_ptr)
1514 : {
1515 0 : struct reply_state *rsp =
1516 0 : talloc_get_type_abort(private_ptr, struct reply_state);
1517 : unsigned i;
1518 :
1519 0 : talloc_steal(ev, rsp);
1520 :
1521 0 : for (i = 0; i < NUM_TEVENT_THREADS; i++) {
1522 0 : if (pthread_equal(rsp->thread_id,
1523 : thread_map[i])) {
1524 0 : break;
1525 : }
1526 : }
1527 0 : torture_comment(thread_test_ctx,
1528 : "Callback %u from thread %u\n",
1529 : thread_counter,
1530 : i);
1531 : /* Now reply to the thread ! */
1532 0 : tevent_thread_proxy_schedule(rsp->reply_tp,
1533 : &im,
1534 : thread_callback,
1535 : &rsp);
1536 :
1537 0 : thread_counter++;
1538 0 : }
1539 :
1540 0 : static void *thread_fn_1(void *private_ptr)
1541 : {
1542 : struct tevent_thread_proxy *master_tp =
1543 0 : talloc_get_type_abort(private_ptr, struct tevent_thread_proxy);
1544 : struct tevent_thread_proxy *tp;
1545 : struct tevent_immediate *im;
1546 : struct tevent_context *ev;
1547 : struct reply_state *rsp;
1548 0 : int finished = 0;
1549 : int ret;
1550 :
1551 0 : ev = tevent_context_init(NULL);
1552 0 : if (ev == NULL) {
1553 0 : return NULL;
1554 : }
1555 :
1556 0 : tp = tevent_thread_proxy_create(ev);
1557 0 : if (tp == NULL) {
1558 0 : talloc_free(ev);
1559 0 : return NULL;
1560 : }
1561 :
1562 0 : im = tevent_create_immediate(ev);
1563 0 : if (im == NULL) {
1564 0 : talloc_free(ev);
1565 0 : return NULL;
1566 : }
1567 :
1568 0 : rsp = talloc(ev, struct reply_state);
1569 0 : if (rsp == NULL) {
1570 0 : talloc_free(ev);
1571 0 : return NULL;
1572 : }
1573 :
1574 0 : rsp->thread_id = pthread_self();
1575 0 : rsp->reply_tp = tp;
1576 0 : rsp->p_finished = &finished;
1577 :
1578 : /* Introduce a little randomness into the mix.. */
1579 0 : usleep(random() % 7000);
1580 :
1581 0 : tevent_thread_proxy_schedule(master_tp,
1582 : &im,
1583 : master_callback,
1584 : &rsp);
1585 :
1586 : /* Ensure we don't wait more than 10 seconds. */
1587 0 : tevent_add_timer(ev,
1588 : ev,
1589 : timeval_current_ofs(10,0),
1590 : thread_timeout_fn,
1591 : &finished);
1592 :
1593 0 : while (finished == 0) {
1594 0 : ret = tevent_loop_once(ev);
1595 0 : assert(ret == 0);
1596 : }
1597 :
1598 0 : if (finished > 1) {
1599 : /* Timeout ! */
1600 0 : abort();
1601 : }
1602 :
1603 : /*
1604 : * NB. We should talloc_free(ev) here, but if we do
1605 : * we currently get hit by helgrind Fix #323432
1606 : * "When calling pthread_cond_destroy or pthread_mutex_destroy
1607 : * with initializers as argument Helgrind (incorrectly) reports errors."
1608 : *
1609 : * http://valgrind.10908.n7.nabble.com/Helgrind-3-9-0-false-positive-
1610 : * with-pthread-mutex-destroy-td47757.html
1611 : *
1612 : * Helgrind doesn't understand that the request/reply
1613 : * messages provide synchronization between the lock/unlock
1614 : * in tevent_thread_proxy_schedule(), and the pthread_destroy()
1615 : * when the struct tevent_thread_proxy object is talloc_free'd.
1616 : *
1617 : * As a work-around for now return ev for the parent thread to free.
1618 : */
1619 0 : return ev;
1620 : }
1621 :
1622 0 : static bool test_multi_tevent_threaded_1(struct torture_context *test,
1623 : const void *test_data)
1624 : {
1625 : unsigned i;
1626 : struct tevent_context *master_ev;
1627 : struct tevent_thread_proxy *master_tp;
1628 : int ret;
1629 :
1630 0 : talloc_disable_null_tracking();
1631 :
1632 : /* Ugly global stuff. */
1633 0 : thread_test_ctx = test;
1634 0 : thread_counter = 0;
1635 :
1636 0 : master_ev = test_tevent_context_init(NULL);
1637 0 : if (master_ev == NULL) {
1638 0 : return false;
1639 : }
1640 :
1641 0 : master_tp = tevent_thread_proxy_create(master_ev);
1642 0 : if (master_tp == NULL) {
1643 0 : torture_fail(test,
1644 : talloc_asprintf(test,
1645 : "tevent_thread_proxy_create failed\n"));
1646 : talloc_free(master_ev);
1647 : return false;
1648 : }
1649 :
1650 0 : for (i = 0; i < NUM_TEVENT_THREADS; i++) {
1651 0 : ret = pthread_create(&thread_map[i],
1652 : NULL,
1653 : thread_fn_1,
1654 : master_tp);
1655 0 : if (ret != 0) {
1656 0 : torture_fail(test,
1657 : talloc_asprintf(test,
1658 : "Failed to create thread %i, %d\n",
1659 : i, ret));
1660 : return false;
1661 : }
1662 : }
1663 :
1664 0 : while (thread_counter < NUM_TEVENT_THREADS) {
1665 0 : ret = tevent_loop_once(master_ev);
1666 0 : torture_assert(test, ret == 0, "tevent_loop_once failed");
1667 : }
1668 :
1669 : /* Wait for all the threads to finish - join 'em. */
1670 0 : for (i = 0; i < NUM_TEVENT_THREADS; i++) {
1671 : void *retval;
1672 0 : ret = pthread_join(thread_map[i], &retval);
1673 0 : torture_assert(test, ret == 0, "pthread_join failed");
1674 : /* Free the child thread event context. */
1675 0 : talloc_free(retval);
1676 : }
1677 :
1678 0 : talloc_free(master_ev);
1679 0 : return true;
1680 : }
1681 :
1682 : struct threaded_test_2 {
1683 : struct tevent_threaded_context *tctx;
1684 : struct tevent_immediate *im;
1685 : pthread_t thread_id;
1686 : };
1687 :
1688 : static void master_callback_2(struct tevent_context *ev,
1689 : struct tevent_immediate *im,
1690 : void *private_data);
1691 :
1692 0 : static void *thread_fn_2(void *private_data)
1693 : {
1694 0 : struct threaded_test_2 *state = private_data;
1695 :
1696 0 : state->thread_id = pthread_self();
1697 :
1698 0 : usleep(random() % 7000);
1699 :
1700 0 : tevent_threaded_schedule_immediate(
1701 : state->tctx, state->im, master_callback_2, state);
1702 :
1703 0 : return NULL;
1704 : }
1705 :
1706 0 : static void master_callback_2(struct tevent_context *ev,
1707 : struct tevent_immediate *im,
1708 : void *private_data)
1709 : {
1710 0 : struct threaded_test_2 *state = private_data;
1711 : int i;
1712 :
1713 0 : for (i = 0; i < NUM_TEVENT_THREADS; i++) {
1714 0 : if (pthread_equal(state->thread_id, thread_map[i])) {
1715 0 : break;
1716 : }
1717 : }
1718 0 : torture_comment(thread_test_ctx,
1719 : "Callback_2 %u from thread %u\n",
1720 : thread_counter,
1721 : i);
1722 0 : thread_counter++;
1723 0 : }
1724 :
1725 0 : static bool test_multi_tevent_threaded_2(struct torture_context *test,
1726 : const void *test_data)
1727 : {
1728 : unsigned i;
1729 :
1730 : struct tevent_context *ev;
1731 : struct tevent_threaded_context *tctx;
1732 : int ret;
1733 :
1734 0 : thread_test_ctx = test;
1735 0 : thread_counter = 0;
1736 :
1737 0 : ev = test_tevent_context_init(test);
1738 0 : torture_assert(test, ev != NULL, "tevent_context_init failed");
1739 :
1740 : /*
1741 : * tevent_re_initialise used to have a bug where it did not
1742 : * re-initialise the thread support after taking it
1743 : * down. Exercise that code path.
1744 : */
1745 0 : ret = tevent_re_initialise(ev);
1746 0 : torture_assert(test, ret == 0, "tevent_re_initialise failed");
1747 :
1748 0 : tctx = tevent_threaded_context_create(ev, ev);
1749 0 : torture_assert(test, tctx != NULL,
1750 : "tevent_threaded_context_create failed");
1751 :
1752 0 : for (i=0; i<NUM_TEVENT_THREADS; i++) {
1753 : struct threaded_test_2 *state;
1754 :
1755 0 : state = talloc(ev, struct threaded_test_2);
1756 0 : torture_assert(test, state != NULL, "talloc failed");
1757 :
1758 0 : state->tctx = tctx;
1759 0 : state->im = tevent_create_immediate(state);
1760 0 : torture_assert(test, state->im != NULL,
1761 : "tevent_create_immediate failed");
1762 :
1763 0 : ret = pthread_create(&thread_map[i], NULL, thread_fn_2, state);
1764 0 : torture_assert(test, ret == 0, "pthread_create failed");
1765 : }
1766 :
1767 0 : while (thread_counter < NUM_TEVENT_THREADS) {
1768 0 : ret = tevent_loop_once(ev);
1769 0 : torture_assert(test, ret == 0, "tevent_loop_once failed");
1770 : }
1771 :
1772 : /* Wait for all the threads to finish - join 'em. */
1773 0 : for (i = 0; i < NUM_TEVENT_THREADS; i++) {
1774 : void *retval;
1775 0 : ret = pthread_join(thread_map[i], &retval);
1776 0 : torture_assert(test, ret == 0, "pthread_join failed");
1777 : /* Free the child thread event context. */
1778 : }
1779 :
1780 0 : talloc_free(tctx);
1781 0 : talloc_free(ev);
1782 0 : return true;
1783 : }
1784 :
1785 : struct test_cached_pid_thread_state {
1786 : pid_t thread_cached_pid;
1787 : pid_t thread_pid;
1788 : };
1789 :
1790 0 : static void *test_cached_pid_thread(void *private_data)
1791 : {
1792 0 : struct test_cached_pid_thread_state *state =
1793 : (struct test_cached_pid_thread_state *)private_data;
1794 :
1795 0 : state->thread_cached_pid = tevent_cached_getpid();
1796 0 : state->thread_pid = getpid();
1797 :
1798 0 : return NULL;
1799 : }
1800 : #endif
1801 :
1802 0 : static bool test_cached_pid(struct torture_context *test,
1803 : const void *test_data)
1804 : {
1805 0 : pid_t parent_pid = getpid();
1806 : pid_t child_pid;
1807 : pid_t finished_pid;
1808 : int child_status;
1809 :
1810 0 : torture_assert(test, tevent_cached_getpid() == parent_pid, "tevent_cached_getpid()");
1811 :
1812 : #ifdef HAVE_PTHREAD
1813 : {
1814 0 : struct test_cached_pid_thread_state state = { .thread_cached_pid = -1, };
1815 : pthread_t thread;
1816 0 : void *retval = NULL;
1817 : int ret;
1818 :
1819 0 : ret = pthread_create(&thread, NULL, test_cached_pid_thread, &state);
1820 0 : torture_assert(test, ret == 0, "pthread_create failed");
1821 :
1822 0 : ret = pthread_join(thread, &retval);
1823 0 : torture_assert(test, ret == 0, "pthread_join failed");
1824 :
1825 0 : torture_assert(test, state.thread_pid == parent_pid, "getpid() in thread");
1826 0 : torture_assert(test, state.thread_cached_pid == parent_pid, "tevent_cached_getpid() in thread");
1827 : }
1828 : #endif /* HAVE_PTHREAD */
1829 :
1830 0 : child_pid = fork();
1831 0 : if (child_pid == 0) {
1832 : /* child */
1833 0 : pid_t pid = getpid();
1834 0 : pid_t cached_pid = tevent_cached_getpid();
1835 :
1836 0 : if (parent_pid == pid) {
1837 0 : exit(1);
1838 : }
1839 0 : if (pid != cached_pid) {
1840 0 : exit(2);
1841 : }
1842 0 : exit(0);
1843 : }
1844 0 : torture_assert(test, child_pid > 0, "fork failed");
1845 :
1846 0 : finished_pid = waitpid(child_pid, &child_status, 0);
1847 0 : torture_assert(test, finished_pid == child_pid, "wrong child");
1848 0 : torture_assert(test, child_status == 0, "child_status");
1849 :
1850 0 : return true;
1851 : }
1852 :
1853 966 : struct torture_suite *torture_local_event(TALLOC_CTX *mem_ctx)
1854 : {
1855 966 : struct torture_suite *suite = torture_suite_create(mem_ctx, "event");
1856 966 : const char **list = tevent_backend_list(suite);
1857 : int i;
1858 :
1859 4830 : for (i=0;list && list[i];i++) {
1860 : struct torture_suite *backend_suite;
1861 :
1862 3864 : backend_suite = torture_suite_create(mem_ctx, list[i]);
1863 :
1864 3864 : torture_suite_add_simple_tcase_const(backend_suite,
1865 : "context",
1866 : test_event_context,
1867 3864 : (const void *)list[i]);
1868 3864 : torture_suite_add_simple_tcase_const(backend_suite,
1869 : "fd1",
1870 : test_event_fd1,
1871 3864 : (const void *)list[i]);
1872 3864 : torture_suite_add_simple_tcase_const(backend_suite,
1873 : "fd2",
1874 : test_event_fd2,
1875 3864 : (const void *)list[i]);
1876 3864 : torture_suite_add_simple_tcase_const(backend_suite,
1877 : "wrapper",
1878 : test_wrapper,
1879 3864 : (const void *)list[i]);
1880 3864 : torture_suite_add_simple_tcase_const(backend_suite,
1881 : "free_wrapper",
1882 : test_free_wrapper,
1883 3864 : (const void *)list[i]);
1884 :
1885 3864 : torture_suite_add_suite(suite, backend_suite);
1886 : }
1887 :
1888 : #ifdef HAVE_PTHREAD
1889 966 : torture_suite_add_simple_tcase_const(suite, "threaded_poll_mt",
1890 : test_event_context_threaded,
1891 : NULL);
1892 :
1893 966 : torture_suite_add_simple_tcase_const(suite, "multi_tevent_threaded",
1894 : test_multi_tevent_threaded,
1895 : NULL);
1896 :
1897 966 : torture_suite_add_simple_tcase_const(suite, "multi_tevent_threaded_1",
1898 : test_multi_tevent_threaded_1,
1899 : NULL);
1900 :
1901 966 : torture_suite_add_simple_tcase_const(suite, "multi_tevent_threaded_2",
1902 : test_multi_tevent_threaded_2,
1903 : NULL);
1904 :
1905 : #endif
1906 :
1907 966 : torture_suite_add_simple_tcase_const(suite, "tevent_cached_getpid",
1908 : test_cached_pid,
1909 : NULL);
1910 :
1911 966 : return suite;
1912 : }
|