#include <darwintest.h>
#include <darwintest_multiprocess.h>
#include <pthread.h>
#include <launch.h>
#include <mach/mach.h>
#include <mach/message.h>
#include <mach/mach_voucher.h>
#include <pthread/workqueue_private.h>
#include <voucher/ipc_pthread_priority_types.h>
#include <servers/bootstrap.h>
#include <stdlib.h>
#include <sys/event.h>
#include <unistd.h>
#include <crt_externs.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <libkern/OSAtomic.h>
#include <sys/wait.h>
#include <spawn.h>
#include <spawn_private.h>
#include <mach/mach_eventlink.h>
T_GLOBAL_META(T_META_NAMESPACE("xnu.mach_eventlink"),
T_META_RUN_CONCURRENTLY(true));
static kern_return_t
test_eventlink_create(mach_port_t *port_pair)
{
kern_return_t kr;
kr = mach_eventlink_create(mach_task_self(), MELC_OPTION_NO_COPYIN, port_pair);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_create");
return kr;
}
static pthread_t
thread_create_for_test(void * (*function)(void *), void *arg)
{
pthread_t pthread;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_create(&pthread, &attr, function, arg);
T_LOG("pthread created\n");
return pthread;
}
static void *
while1loop(void *arg)
{
arg = NULL;
while (1) {
;
}
return NULL;
}
static void *
test_eventlink_wait_with_timeout(void *arg)
{
kern_return_t kr;
mach_port_t eventlink_port = (mach_port_t) (uintptr_t)arg;
mach_port_t self = mach_thread_self();
uint64_t ticks = mach_absolute_time();
uint64_t count = 1;
kr = mach_eventlink_associate(eventlink_port, self, 0, 0, 0, 0, MELA_OPTION_NONE);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate");
kr = mach_eventlink_wait_until(eventlink_port, &count, MELSW_OPTION_NONE,
KERN_CLOCK_MACH_ABSOLUTE_TIME, ticks + 5000);
T_EXPECT_MACH_ERROR(kr, KERN_OPERATION_TIMED_OUT, "mach_eventlink_wait_until returned expected error");
T_EXPECT_EQ(count, (uint64_t)0, "mach_eventlink_wait_until returned correct count value");
return NULL;
}
static void *
test_eventlink_wait_no_wait(void *arg)
{
kern_return_t kr;
mach_port_t eventlink_port = (mach_port_t) (uintptr_t)arg;
mach_port_t self = mach_thread_self();
uint64_t count = 1;
kr = mach_eventlink_associate(eventlink_port, self, 0, 0, 0, 0, MELA_OPTION_NONE);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate");
kr = mach_eventlink_wait_until(eventlink_port, &count, MELSW_OPTION_NO_WAIT,
KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
T_EXPECT_MACH_ERROR(kr, KERN_OPERATION_TIMED_OUT, "mach_eventlink_wait_until returned expected error");
T_EXPECT_EQ(count, (uint64_t)0, "mach_eventlink_wait_until returned correct count value");
return NULL;
}
static void *
test_eventlink_wait_destroy(void *arg)
{
kern_return_t kr;
mach_port_t eventlink_port = (mach_port_t) (uintptr_t)arg;
mach_port_t self = mach_thread_self();
uint64_t count = 1;
kr = mach_eventlink_associate(eventlink_port, self, 0, 0, 0, 0, MELA_OPTION_NONE);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate");
kr = mach_eventlink_wait_until(eventlink_port, &count, MELSW_OPTION_NONE,
KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
T_EXPECT_MACH_ERROR(kr, KERN_TERMINATED, "mach_eventlink_wait_until returned expected error");
return NULL;
}
static void *
test_eventlink_wait_for_signal(void *arg)
{
kern_return_t kr;
mach_port_t eventlink_port = (mach_port_t) (uintptr_t)arg;
mach_port_t self = mach_thread_self();
uint64_t count = 0;
kr = mach_eventlink_associate(eventlink_port, self, 0, 0, 0, 0, MELA_OPTION_NONE);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate");
kr = mach_eventlink_wait_until(eventlink_port, &count, MELSW_OPTION_NONE,
KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_wait_until");
T_EXPECT_EQ(count, (uint64_t)1, "mach_eventlink_wait_until returned correct count value");
return NULL;
}
static void *
test_eventlink_wait_then_signal(void *arg)
{
kern_return_t kr;
mach_port_t eventlink_port = (mach_port_t) (uintptr_t)arg;
mach_port_t self = mach_thread_self();
uint64_t count = 0;
kr = mach_eventlink_associate(eventlink_port, self, 0, 0, 0, 0, MELA_OPTION_NONE);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate");
kr = mach_eventlink_wait_until(eventlink_port, &count, MELSW_OPTION_NONE,
KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_wait_until");
T_EXPECT_EQ(count, (uint64_t)1, "mach_eventlink_wait_until returned correct count value");
kr = mach_eventlink_signal(eventlink_port, 0);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_signal");
return NULL;
}
static void *
test_eventlink_wait_then_wait_signal_with_no_wait(void *arg)
{
kern_return_t kr;
mach_port_t eventlink_port = (mach_port_t) (uintptr_t)arg;
mach_port_t self = mach_thread_self();
uint64_t count = 0;
kr = mach_eventlink_associate(eventlink_port, self, 0, 0, 0, 0, MELA_OPTION_NONE);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate");
kr = mach_eventlink_wait_until(eventlink_port, &count, MELSW_OPTION_NONE,
KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_wait_until");
T_EXPECT_EQ(count, (uint64_t)1, "mach_eventlink_wait_until returned correct count value");
kr = mach_eventlink_signal_wait_until(eventlink_port, &count, 0, MELSW_OPTION_NO_WAIT,
KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
T_EXPECT_MACH_ERROR(kr, KERN_OPERATION_TIMED_OUT, "mach_eventlink_wait_until returned expected error");
T_EXPECT_EQ(count, (uint64_t)1, "mach_eventlink_wait_until returned correct count value");
return NULL;
}
static void *
test_eventlink_wait_then_wait_signal_with_prepost(void *arg)
{
kern_return_t kr;
mach_port_t eventlink_port = (mach_port_t) (uintptr_t)arg;
mach_port_t self = mach_thread_self();
uint64_t count = 0;
kr = mach_eventlink_associate(eventlink_port, self, 0, 0, 0, 0, MELA_OPTION_NONE);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate");
kr = mach_eventlink_wait_until(eventlink_port, &count, MELSW_OPTION_NONE,
KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_wait_until");
T_EXPECT_EQ(count, (uint64_t)1, "mach_eventlink_wait_until returned correct count value");
count = 0;
kr = mach_eventlink_signal_wait_until(eventlink_port, &count, 0, MELSW_OPTION_NONE,
KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_signal_wait_until");
T_EXPECT_EQ(count, (uint64_t)1, "mach_eventlink_wait_until returned correct count value");
return NULL;
}
static void *
test_eventlink_wait_then_signal_loop(void *arg)
{
kern_return_t kr;
mach_port_t eventlink_port = (mach_port_t) (uintptr_t)arg;
mach_port_t self = mach_thread_self();
uint64_t count = 0;
int i;
kr = mach_eventlink_associate(eventlink_port, self, 0, 0, 0, 0, MELA_OPTION_NONE);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate");
kr = mach_eventlink_wait_until(eventlink_port, &count, MELSW_OPTION_NONE,
KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_wait_until");
T_EXPECT_EQ(count, (uint64_t)1, "mach_eventlink_wait_until returned correct count value");
for (i = 1; i < 100; i++) {
kr = mach_eventlink_signal_wait_until(eventlink_port, &count, 0, MELSW_OPTION_NONE,
KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_signal_wait_until");
T_EXPECT_EQ(count, (uint64_t)(i + 1), "mach_eventlink_wait_until returned correct count value");
}
kr = mach_eventlink_signal(eventlink_port, 0);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_signal");
return NULL;
}
T_DECL(test_eventlink_create, "eventlink create test", T_META_ASROOT(YES))
{
kern_return_t kr;
mach_port_t port_pair[2];
kr = test_eventlink_create(port_pair);
if (kr != KERN_SUCCESS) {
return;
}
mach_port_deallocate(mach_task_self(), port_pair[0]);
mach_port_deallocate(mach_task_self(), port_pair[1]);
}
T_DECL(test_eventlink_destroy, "eventlink destroy test", T_META_ASROOT(YES))
{
kern_return_t kr;
mach_port_t port_pair[2];
kr = test_eventlink_create(port_pair);
if (kr != KERN_SUCCESS) {
return;
}
kr = mach_eventlink_destroy(port_pair[0]);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_destroy");
kr = mach_eventlink_destroy(port_pair[1]);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_destroy");
}
T_DECL(test_eventlink_associate, "eventlink associate test", T_META_ASROOT(YES))
{
kern_return_t kr;
mach_port_t port_pair[2];
mach_port_t self = mach_thread_self();
mach_port_t other_thread = MACH_PORT_NULL;
pthread_t pthread;
kr = mach_eventlink_associate(MACH_PORT_NULL, self, 0, 0, 0, 0, MELA_OPTION_NONE);
T_EXPECT_MACH_ERROR(kr, MACH_SEND_INVALID_DEST, "mach_eventlink_associate with null eventlink returned expected error");
kr = mach_eventlink_disassociate(MACH_PORT_NULL, MELD_OPTION_NONE);
T_EXPECT_MACH_ERROR(kr, MACH_SEND_INVALID_DEST, "mach_eventlink_disassociate with null eventlink returned expected error");
kr = test_eventlink_create(port_pair);
if (kr != KERN_SUCCESS) {
return;
}
pthread = thread_create_for_test(while1loop, NULL);
other_thread = pthread_mach_thread_np(pthread);
for (int i = 0; i < 3; i++) {
kr = mach_eventlink_associate(port_pair[0], self, 0, 0, 0, 0, MELA_OPTION_NONE);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate for object 1");
kr = mach_eventlink_associate(port_pair[1], other_thread, 0, 0, 0, 0, MELA_OPTION_NONE);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate for object 2");
kr = mach_eventlink_associate(port_pair[0], other_thread, 0, 0, 0, 0, MELA_OPTION_NONE);
T_EXPECT_MACH_ERROR(kr, KERN_NAME_EXISTS, "mach_eventlink_associate for associated "
"objects returned expected error");
kr = mach_eventlink_associate(port_pair[1], self, 0, 0, 0, 0, MELA_OPTION_NONE);
T_EXPECT_MACH_ERROR(kr, KERN_NAME_EXISTS, "mach_eventlink_associate for associated "
"objects return expected error");
kr = mach_eventlink_disassociate(port_pair[0], MELD_OPTION_NONE);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_disassociate for object 1");
kr = mach_eventlink_disassociate(port_pair[1], MELD_OPTION_NONE);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_disassociate for object 2");
kr = mach_eventlink_disassociate(port_pair[0], MELD_OPTION_NONE);
T_EXPECT_MACH_ERROR(kr, KERN_INVALID_ARGUMENT, "mach_eventlink_disassociate for "
"disassociated objects returned expected error");
kr = mach_eventlink_disassociate(port_pair[1], MELD_OPTION_NONE);
T_EXPECT_MACH_ERROR(kr, KERN_INVALID_ARGUMENT, "mach_eventlink_disassociate for "
"disassociated objects returned expected error");
}
kr = mach_eventlink_destroy(port_pair[0]);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_destroy");
kr = mach_eventlink_disassociate(port_pair[1], MELD_OPTION_NONE);
T_EXPECT_MACH_ERROR(kr, KERN_TERMINATED, "mach_eventlink_disassociate for "
"terminated object returned expected error");
kr = mach_eventlink_destroy(port_pair[1]);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_destroy");
}
T_DECL(test_eventlink_wait_timeout, "eventlink wait timeout test", T_META_ASROOT(YES))
{
kern_return_t kr;
mach_port_t port_pair[2];
pthread_t pthread;
kr = test_eventlink_create(port_pair);
if (kr != KERN_SUCCESS) {
return;
}
pthread = thread_create_for_test(test_eventlink_wait_with_timeout, (void *)(uintptr_t)port_pair[0]);
sleep(10);
mach_port_deallocate(mach_task_self(), port_pair[0]);
mach_port_deallocate(mach_task_self(), port_pair[1]);
pthread_join(pthread, NULL);
}
T_DECL(test_eventlink_wait_no_wait, "eventlink wait no wait test", T_META_ASROOT(YES))
{
kern_return_t kr;
mach_port_t port_pair[2];
pthread_t pthread;
kr = test_eventlink_create(port_pair);
if (kr != KERN_SUCCESS) {
return;
}
pthread = thread_create_for_test(test_eventlink_wait_no_wait, (void *)(uintptr_t)port_pair[0]);
pthread_join(pthread, NULL);
mach_port_deallocate(mach_task_self(), port_pair[0]);
mach_port_deallocate(mach_task_self(), port_pair[1]);
}
T_DECL(test_eventlink_wait_and_destroy, "eventlink wait and destroy", T_META_ASROOT(YES))
{
kern_return_t kr;
mach_port_t port_pair[2];
pthread_t pthread;
kr = test_eventlink_create(port_pair);
if (kr != KERN_SUCCESS) {
return;
}
pthread = thread_create_for_test(test_eventlink_wait_destroy, (void *)(uintptr_t)port_pair[0]);
sleep(5);
kr = mach_port_mod_refs(mach_task_self(), port_pair[0], MACH_PORT_RIGHT_SEND, 2);
T_ASSERT_MACH_SUCCESS(kr, "mach_port_mod_refs");
kr = mach_eventlink_destroy(port_pair[0]);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_destroy");
pthread_join(pthread, NULL);
mach_port_deallocate(mach_task_self(), port_pair[1]);
}
T_DECL(test_eventlink_wait_and_destroy_remote, "eventlink wait and remote destroy", T_META_ASROOT(YES))
{
kern_return_t kr;
mach_port_t port_pair[2];
pthread_t pthread;
kr = test_eventlink_create(port_pair);
if (kr != KERN_SUCCESS) {
return;
}
pthread = thread_create_for_test(test_eventlink_wait_destroy, (void *)(uintptr_t)port_pair[0]);
sleep(5);
kr = mach_port_mod_refs(mach_task_self(), port_pair[1], MACH_PORT_RIGHT_SEND, 2);
T_ASSERT_MACH_SUCCESS(kr, "mach_port_mod_refs");
kr = mach_eventlink_destroy(port_pair[1]);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_destroy");
pthread_join(pthread, NULL);
mach_port_deallocate(mach_task_self(), port_pair[0]);
}
T_DECL(test_eventlink_wait_and_deallocate, "eventlink wait and deallocate", T_META_ASROOT(YES))
{
kern_return_t kr;
mach_port_t port_pair[2];
pthread_t pthread;
kr = test_eventlink_create(port_pair);
if (kr != KERN_SUCCESS) {
return;
}
pthread = thread_create_for_test(test_eventlink_wait_destroy, (void *)(uintptr_t)port_pair[0]);
sleep(5);
mach_port_deallocate(mach_task_self(), port_pair[0]);
pthread_join(pthread, NULL);
mach_port_deallocate(mach_task_self(), port_pair[1]);
}
T_DECL(test_eventlink_wait_and_disassociate, "eventlink wait and disassociate", T_META_ASROOT(YES))
{
kern_return_t kr;
mach_port_t port_pair[2];
pthread_t pthread;
kr = test_eventlink_create(port_pair);
if (kr != KERN_SUCCESS) {
return;
}
pthread = thread_create_for_test(test_eventlink_wait_destroy, (void *)(uintptr_t)port_pair[0]);
sleep(5);
kr = mach_eventlink_disassociate(port_pair[0], MELD_OPTION_NONE);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_disassociate");
pthread_join(pthread, NULL);
mach_port_deallocate(mach_task_self(), port_pair[1]);
mach_port_deallocate(mach_task_self(), port_pair[0]);
}
T_DECL(test_eventlink_wait_and_signal, "eventlink wait and signal", T_META_ASROOT(YES))
{
kern_return_t kr;
mach_port_t port_pair[2];
pthread_t pthread;
mach_port_t self = mach_thread_self();
kr = test_eventlink_create(port_pair);
if (kr != KERN_SUCCESS) {
return;
}
pthread = thread_create_for_test(test_eventlink_wait_for_signal, (void *)(uintptr_t)port_pair[0]);
sleep(5);
kr = mach_eventlink_associate(port_pair[1], self, 0, 0, 0, 0, MELA_OPTION_NONE);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate for object 2");
kr = mach_eventlink_signal(port_pair[1], 0);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_signal for object 2");
pthread_join(pthread, NULL);
mach_port_deallocate(mach_task_self(), port_pair[0]);
mach_port_deallocate(mach_task_self(), port_pair[1]);
}
T_DECL(test_eventlink_wait_signal, "eventlink wait_signal", T_META_ASROOT(YES))
{
kern_return_t kr;
mach_port_t port_pair[2];
pthread_t pthread;
mach_port_t self = mach_thread_self();
uint64_t count = 0;
kr = test_eventlink_create(port_pair);
if (kr != KERN_SUCCESS) {
return;
}
pthread = thread_create_for_test(test_eventlink_wait_then_signal, (void *)(uintptr_t)port_pair[0]);
sleep(5);
kr = mach_eventlink_associate(port_pair[1], self, 0, 0, 0, 0, MELA_OPTION_NONE);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate for object 2");
kr = mach_eventlink_signal_wait_until(port_pair[1], &count, 0, MELSW_OPTION_NONE,
KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_signal_wait_until");
T_EXPECT_EQ(count, (uint64_t)1, "mach_eventlink_signal_wait_until returned correct count value");
pthread_join(pthread, NULL);
mach_port_deallocate(mach_task_self(), port_pair[0]);
mach_port_deallocate(mach_task_self(), port_pair[1]);
}
T_DECL(test_eventlink_wait_signal_no_wait, "eventlink wait_signal with no wait", T_META_ASROOT(YES))
{
kern_return_t kr;
mach_port_t port_pair[2];
pthread_t pthread;
mach_port_t self = mach_thread_self();
uint64_t count = 0;
kr = test_eventlink_create(port_pair);
if (kr != KERN_SUCCESS) {
return;
}
pthread = thread_create_for_test(test_eventlink_wait_then_wait_signal_with_no_wait, (void *)(uintptr_t)port_pair[0]);
sleep(5);
kr = mach_eventlink_associate(port_pair[1], self, 0, 0, 0, 0, MELA_OPTION_NONE);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate for object 2");
kr = mach_eventlink_signal_wait_until(port_pair[1], &count, 0, MELSW_OPTION_NONE,
KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_signal_wait_until");
T_EXPECT_EQ(count, (uint64_t)1, "mach_eventlink_signal_wait_until returned correct count value");
pthread_join(pthread, NULL);
mach_port_deallocate(mach_task_self(), port_pair[0]);
mach_port_deallocate(mach_task_self(), port_pair[1]);
}
T_DECL(test_eventlink_wait_signal_prepost, "eventlink wait_signal with prepost", T_META_ASROOT(YES))
{
kern_return_t kr;
mach_port_t port_pair[2];
pthread_t pthread;
mach_port_t self = mach_thread_self();
uint64_t count = 0;
kr = test_eventlink_create(port_pair);
if (kr != KERN_SUCCESS) {
return;
}
pthread = thread_create_for_test(test_eventlink_wait_then_wait_signal_with_prepost, (void *)(uintptr_t)port_pair[0]);
sleep(5);
kr = mach_eventlink_associate(port_pair[1], self, 0, 0, 0, 0, MELA_OPTION_NONE);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate for object 2");
kr = mach_eventlink_signal_wait_until(port_pair[1], &count, 0, MELSW_OPTION_NONE,
KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_signal_wait_until");
T_EXPECT_EQ(count, (uint64_t)1, "mach_eventlink_signal_wait_until returned correct count value");
pthread_join(pthread, NULL);
mach_port_deallocate(mach_task_self(), port_pair[0]);
mach_port_deallocate(mach_task_self(), port_pair[1]);
}
T_DECL(test_eventlink_wait_signal_associate_on_wait, "eventlink wait_signal associate on wait", T_META_ASROOT(YES))
{
kern_return_t kr;
mach_port_t port_pair[2];
pthread_t pthread;
uint64_t count = 0;
kr = test_eventlink_create(port_pair);
if (kr != KERN_SUCCESS) {
return;
}
pthread = thread_create_for_test(test_eventlink_wait_then_signal, (void *)(uintptr_t)port_pair[0]);
sleep(5);
kr = mach_eventlink_associate(port_pair[1], MACH_PORT_NULL, 0, 0, 0, 0, MELA_OPTION_ASSOCIATE_ON_WAIT);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate with associate on wait for object 2");
kr = mach_eventlink_signal_wait_until(port_pair[1], &count, 0, MELSW_OPTION_NONE,
KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_signal_wait_until");
T_EXPECT_EQ(count, (uint64_t)1, "mach_eventlink_signal_wait_until returned correct count value");
kr = mach_eventlink_disassociate(port_pair[1], MELD_OPTION_NONE);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_disassociate");
kr = mach_eventlink_signal_wait_until(port_pair[1], &count, 0, MELSW_OPTION_NONE,
KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
T_EXPECT_MACH_ERROR(kr, KERN_INVALID_ARGUMENT, "mach_eventlink_wait_until returned expected error");
pthread_join(pthread, NULL);
mach_port_deallocate(mach_task_self(), port_pair[0]);
mach_port_deallocate(mach_task_self(), port_pair[1]);
}
T_DECL(test_eventlink_wait_signal_loop, "eventlink wait_signal in loop", T_META_ASROOT(YES))
{
kern_return_t kr;
mach_port_t port_pair[2];
pthread_t pthread;
mach_port_t self = mach_thread_self();
uint64_t count = 0;
int i;
kr = test_eventlink_create(port_pair);
if (kr != KERN_SUCCESS) {
return;
}
pthread = thread_create_for_test(test_eventlink_wait_then_signal_loop, (void *)(uintptr_t)port_pair[0]);
kr = mach_eventlink_associate(port_pair[1], self, 0, 0, 0, 0, MELA_OPTION_NONE);
T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate for object 2");
for (i = 0; i < 100; i++) {
kr = mach_eventlink_signal_wait_until(port_pair[1], &count, 0, MELSW_OPTION_NONE,
KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
T_ASSERT_MACH_SUCCESS(kr, "main thread: mach_eventlink_signal_wait_until");
T_EXPECT_EQ(count, (uint64_t)(i + 1), "main thread: mach_eventlink_signal_wait_until returned correct count value");
}
pthread_join(pthread, NULL);
mach_port_deallocate(mach_task_self(), port_pair[0]);
mach_port_deallocate(mach_task_self(), port_pair[1]);
}