]> git.saurik.com Git - apple/xnu.git/blob - tests/kqueue_close.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / tests / kqueue_close.c
1 #include <unistd.h>
2 #include <pthread.h>
3 #include <errno.h>
4
5 #include <sys/event.h>
6
7 #include <darwintest.h>
8
9 T_GLOBAL_META(T_META_RUN_CONCURRENTLY(true));
10
11 /*
12 * <rdar://problem/30231213> close() of kqueue FD races with kqueue_scan park
13 *
14 * When close concurrent with poll goes wrong, the close hangs
15 * and the kevent never gets any more events.
16 */
17
18 /* Both events should fire at about the same time */
19 static uint32_t timeout_ms = 10;
20
21 static void *
22 poll_kqueue(void *arg)
23 {
24 int fd = (int)arg;
25
26 struct kevent kev = {
27 .filter = EVFILT_TIMER,
28 .flags = EV_ADD,
29 .data = timeout_ms,
30 };
31
32 int rv = kevent(fd, &kev, 1, NULL, 0, NULL);
33
34 if (rv == -1 && errno == EBADF) {
35 /* The close may race with this thread spawning */
36 T_LOG("kqueue already closed?");
37 return NULL;
38 } else {
39 T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "kevent");
40 }
41
42 while ((rv = kevent(fd, NULL, 0, &kev, 1, NULL)) == 1) {
43 T_LOG("poll\n");
44 }
45
46 if (rv != -1 || errno != EBADF) {
47 T_ASSERT_POSIX_SUCCESS(rv, "fd should be closed");
48 }
49
50 return NULL;
51 }
52
53 static void
54 run_test()
55 {
56 int fd = kqueue();
57 T_QUIET; T_ASSERT_POSIX_SUCCESS(fd, "kqueue");
58
59 pthread_t thread;
60 int rv = pthread_create(&thread, NULL, poll_kqueue,
61 (void *)(uintptr_t)fd);
62 T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "pthread_create");
63
64 usleep(timeout_ms * 1000);
65
66 rv = close(fd);
67 T_ASSERT_POSIX_SUCCESS(rv, "close");
68
69 rv = pthread_join(thread, NULL);
70 T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "pthread_join");
71 }
72
73 T_DECL(kqueue_close_race, "Races kqueue close with kqueue process",
74 T_META_LTEPHASE(LTE_POSTINIT), T_META_TIMEOUT(5))
75 {
76 for (uint32_t i = 1; i < 100; i++) {
77 run_test();
78 }
79 }