mirror of
https://github.com/darlinghq/darling-xnu.git
synced 2024-11-23 12:39:55 +00:00
93 lines
2.0 KiB
C
93 lines
2.0 KiB
C
#include <darwintest.h>
|
|
|
|
#include <stdatomic.h>
|
|
|
|
#include <unistd.h>
|
|
#include <pthread.h>
|
|
#include <sys/ulock.h>
|
|
|
|
#include <os/tsd.h>
|
|
|
|
#ifndef __TSD_MACH_THREAD_SELF
|
|
#define __TSD_MACH_THREAD_SELF 3
|
|
#endif
|
|
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wbad-function-cast"
|
|
__inline static mach_port_name_t
|
|
_os_get_self(void)
|
|
{
|
|
mach_port_name_t self = (mach_port_name_t)_os_tsd_get_direct(__TSD_MACH_THREAD_SELF);
|
|
return self;
|
|
}
|
|
#pragma clang diagnostic pop
|
|
|
|
T_GLOBAL_META(T_META_RUN_CONCURRENTLY(true));
|
|
|
|
#pragma mark ulock_non_owner_wake
|
|
|
|
static _Atomic uint32_t test_ulock;
|
|
|
|
static void *
|
|
test_waiter(void *arg __unused)
|
|
{
|
|
for (;;) {
|
|
uint32_t test_ulock_owner = atomic_load_explicit(&test_ulock,
|
|
memory_order_relaxed);
|
|
int rc = __ulock_wait(UL_UNFAIR_LOCK | ULF_NO_ERRNO, &test_ulock,
|
|
test_ulock_owner, 0);
|
|
if (rc == -EINTR || rc == -EFAULT) {
|
|
continue;
|
|
}
|
|
T_ASSERT_GE(rc, 0, "__ulock_wait");
|
|
break;
|
|
}
|
|
|
|
T_PASS("Waiter woke");
|
|
T_END;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void *
|
|
test_waker(void *arg __unused)
|
|
{
|
|
for (;;) {
|
|
int rc = __ulock_wake(UL_UNFAIR_LOCK | ULF_NO_ERRNO | ULF_WAKE_ALLOW_NON_OWNER,
|
|
&test_ulock, 0);
|
|
if (rc == -EINTR) {
|
|
continue;
|
|
}
|
|
T_ASSERT_EQ(rc, 0, "__ulock_wake");
|
|
break;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
T_DECL(ulock_non_owner_wake, "ulock_wake respects non-owner wakes",
|
|
T_META_CHECK_LEAKS(false))
|
|
{
|
|
pthread_t waiter, waker;
|
|
|
|
atomic_store_explicit(&test_ulock, _os_get_self() & ~0x3u, memory_order_relaxed);
|
|
|
|
T_ASSERT_POSIX_ZERO(pthread_create(&waiter, NULL, test_waiter, NULL), "create waiter");
|
|
|
|
// wait for the waiter to reach the kernel
|
|
for (;;) {
|
|
int kernel_ulocks = __ulock_wake(UL_DEBUG_HASH_DUMP_PID, NULL, 0);
|
|
T_QUIET; T_ASSERT_NE(kernel_ulocks, -1, "UL_DEBUG_HASH_DUMP_PID");
|
|
|
|
if (kernel_ulocks == 1) {
|
|
T_LOG("waiter is now waiting");
|
|
break;
|
|
}
|
|
usleep(100);
|
|
}
|
|
|
|
T_ASSERT_POSIX_ZERO(pthread_create(&waker, NULL, test_waker, NULL), "create waker");
|
|
|
|
// won't ever actually join
|
|
pthread_join(waiter, NULL);
|
|
}
|