darling-xnu/tests/kqueue_close.c
2023-05-16 21:41:14 -07:00

80 lines
1.6 KiB
C

#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <sys/event.h>
#include <darwintest.h>
T_GLOBAL_META(T_META_RUN_CONCURRENTLY(true));
/*
* <rdar://problem/30231213> close() of kqueue FD races with kqueue_scan park
*
* When close concurrent with poll goes wrong, the close hangs
* and the kevent never gets any more events.
*/
/* Both events should fire at about the same time */
static uint32_t timeout_ms = 10;
static void *
poll_kqueue(void *arg)
{
int fd = (int)arg;
struct kevent kev = {
.filter = EVFILT_TIMER,
.flags = EV_ADD,
.data = timeout_ms,
};
int rv = kevent(fd, &kev, 1, NULL, 0, NULL);
if (rv == -1 && errno == EBADF) {
/* The close may race with this thread spawning */
T_LOG("kqueue already closed?");
return NULL;
} else {
T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "kevent");
}
while ((rv = kevent(fd, NULL, 0, &kev, 1, NULL)) == 1) {
T_LOG("poll\n");
}
if (rv != -1 || errno != EBADF) {
T_ASSERT_POSIX_SUCCESS(rv, "fd should be closed");
}
return NULL;
}
static void
run_test()
{
int fd = kqueue();
T_QUIET; T_ASSERT_POSIX_SUCCESS(fd, "kqueue");
pthread_t thread;
int rv = pthread_create(&thread, NULL, poll_kqueue,
(void *)(uintptr_t)fd);
T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "pthread_create");
usleep(timeout_ms * 1000);
rv = close(fd);
T_ASSERT_POSIX_SUCCESS(rv, "close");
rv = pthread_join(thread, NULL);
T_QUIET; T_ASSERT_POSIX_SUCCESS(rv, "pthread_join");
}
T_DECL(kqueue_close_race, "Races kqueue close with kqueue process",
T_META_LTEPHASE(LTE_POSTINIT), T_META_TIMEOUT(5))
{
for (uint32_t i = 1; i < 100; i++) {
run_test();
}
}