// SPDX-License-Identifier: GPL-2.0-or-later/* * Various unit tests for the "ntsync" synchronization primitive driver. * * Copyright (C) 2021-2022 Elizabeth Figura <zfigura@codeweavers.com> */ #define _GNU_SOURCE#include <sys/ioctl.h>#include <sys/stat.h>#include <sys/wait.h>#include <fcntl.h>#include <sched.h>#include <time.h>#include <pthread.h>#include <linux/ntsync.h>#include "kselftest_harness.h" #ifndef CLONE_NEWTIME#define CLONE_NEWTIME 0x00000080#endif static int read_sem_state(int sem, __u32 *count, __u32 *max){ struct ntsync_sem_args args; int ret; memset(&args, 0xcc, sizeof(args)); ret = ioctl(sem, NTSYNC_IOC_SEM_READ, &args); *count = args.count; *max = args.max; return ret;} #define check_sem_state(sem, count, max) \ ({ \ __u32 __count, __max; \ int ret = read_sem_state((sem), &__count, &__max); \ EXPECT_EQ(0, ret); \ EXPECT_EQ((count), __count); \ EXPECT_EQ((max), __max); \ }) static int release_sem(int sem, __u32 *count){ return ioctl(sem, NTSYNC_IOC_SEM_RELEASE, count);} static int read_mutex_state(int mutex, __u32 *count, __u32 *owner){ struct ntsync_mutex_args args; int ret; memset(&args, 0xcc, sizeof(args)); ret = ioctl(mutex, NTSYNC_IOC_MUTEX_READ, &args); *count = args.count; *owner = args.owner; return ret;} #define check_mutex_state(mutex, count, owner) \ ({ \ __u32 __count, __owner; \ int ret = read_mutex_state((mutex), &__count, &__owner); \ EXPECT_EQ(0, ret); \ EXPECT_EQ((count), __count); \ EXPECT_EQ((owner), __owner); \ }) static int unlock_mutex(int mutex, __u32 owner, __u32 *count){ struct ntsync_mutex_args args; int ret; args.owner = owner; args.count = 0xdeadbeef; ret = ioctl(mutex, NTSYNC_IOC_MUTEX_UNLOCK, &args); *count = args.count; return ret;} static int read_event_state(int event, __u32 *signaled, __u32 *manual){ struct ntsync_event_args args; int ret; memset(&args, 0xcc, sizeof(args)); ret = ioctl(event, NTSYNC_IOC_EVENT_READ, &args); *signaled = args.signaled; *manual = args.manual; return ret;} #define check_event_state(event, signaled, manual) \ ({ \ __u32 __signaled, __manual; \ int ret = read_event_state((event), &__signaled, &__manual); \ EXPECT_EQ(0, ret); \ EXPECT_EQ((signaled), __signaled); \ EXPECT_EQ((manual), __manual); \ }) static int wait_objs(int fd, unsigned long request, __u32 count, const int *objs, __u32 owner, int alert, __u32 *index){ struct ntsync_wait_args args = {0}; struct timespec timeout; int ret; clock_gettime(CLOCK_MONOTONIC, &timeout); args.timeout = timeout.tv_sec * 1000000000 + timeout.tv_nsec; args.count = count; args.objs = (uintptr_t)objs; args.owner = owner; args.index = 0xdeadbeef; args.alert = alert; ret = ioctl(fd, request, &args); *index = args.index; return ret;} static int wait_any(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index){ return wait_objs(fd, NTSYNC_IOC_WAIT_ANY, count, objs, owner, 0, index);} static int wait_all(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index){ return wait_objs(fd, NTSYNC_IOC_WAIT_ALL, count, objs, owner, 0, index);} static int wait_any_alert(int fd, __u32 count, const int *objs, __u32 owner, int alert, __u32 *index){ return wait_objs(fd, NTSYNC_IOC_WAIT_ANY, count, objs, owner, alert, index);} static int wait_all_alert(int fd, __u32 count, const int *objs, __u32 owner, int alert, __u32 *index){ return wait_objs(fd, NTSYNC_IOC_WAIT_ALL, count, objs, owner, alert, index);} TEST(semaphore_state){ struct ntsync_sem_args sem_args; struct timespec timeout; __u32 count, index; int fd, ret, sem; clock_gettime(CLOCK_MONOTONIC, &timeout); fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ASSERT_LE(0, fd); sem_args.count = 3; sem_args.max = 2; sem = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); EXPECT_EQ(-1, sem); EXPECT_EQ(EINVAL, errno); sem_args.count = 2; sem_args.max = 2; sem = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); EXPECT_LE(0, sem); check_sem_state(sem, 2, 2); count = 0; ret = release_sem(sem, &count); EXPECT_EQ(0, ret); EXPECT_EQ(2, count); check_sem_state(sem, 2, 2); count = 1; ret = release_sem(sem, &count); EXPECT_EQ(-1, ret); EXPECT_EQ(EOVERFLOW, errno); check_sem_state(sem, 2, 2); ret = wait_any(fd, 1, &sem, 123, &index); EXPECT_EQ(0, ret); EXPECT_EQ(0, index); check_sem_state(sem, 1, 2); ret = wait_any(fd, 1, &sem, 123, &index); EXPECT_EQ(0, ret); EXPECT_EQ(0, index); check_sem_state(sem, 0, 2); ret = wait_any(fd, 1, &sem, 123, &index); EXPECT_EQ(-1, ret); EXPECT_EQ(ETIMEDOUT, errno); count = 3; ret = release_sem(sem, &count); EXPECT_EQ(-1, ret); EXPECT_EQ(EOVERFLOW, errno); check_sem_state(sem, 0, 2); count = 2; ret = release_sem(sem, &count); EXPECT_EQ(0, ret); EXPECT_EQ(0, count); check_sem_state(sem, 2, 2); ret = wait_any(fd, 1, &sem, 123, &index); EXPECT_EQ(0, ret); ret = wait_any(fd, 1, &sem, 123, &index); EXPECT_EQ(0, ret); count = 1; ret = release_sem(sem, &count); EXPECT_EQ(0, ret); EXPECT_EQ(0, count); check_sem_state(sem, 1, 2); count = ~0u; ret = release_sem(sem, &count); EXPECT_EQ(-1, ret); EXPECT_EQ(EOVERFLOW, errno); check_sem_state(sem, 1, 2); close(sem); close(fd);} TEST(mutex_state){ struct ntsync_mutex_args mutex_args; __u32 owner, count, index; struct timespec timeout; int fd, ret, mutex; clock_gettime(CLOCK_MONOTONIC, &timeout); fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ASSERT_LE(0, fd); mutex_args.owner = 123; mutex_args.count = 0; mutex = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); EXPECT_EQ(-1, mutex); EXPECT_EQ(EINVAL, errno); mutex_args.owner = 0; mutex_args.count = 2; mutex = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); EXPECT_EQ(-1, mutex); EXPECT_EQ(EINVAL, errno); mutex_args.owner = 123; mutex_args.count = 2; mutex = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); EXPECT_LE(0, mutex); check_mutex_state(mutex, 2, 123); ret = unlock_mutex(mutex, 0, &count); EXPECT_EQ(-1, ret); EXPECT_EQ(EINVAL, errno); ret = unlock_mutex(mutex, 456, &count); EXPECT_EQ(-1, ret); EXPECT_EQ(EPERM, errno); check_mutex_state(mutex, 2, 123); ret = unlock_mutex(mutex, 123, &count); EXPECT_EQ(0, ret); EXPECT_EQ(2, count); check_mutex_state(mutex, 1, 123); ret = unlock_mutex(mutex, 123, &count); EXPECT_EQ(0, ret); EXPECT_EQ(1, count); check_mutex_state(mutex, 0, 0); ret = unlock_mutex(mutex, 123, &count); EXPECT_EQ(-1, ret); EXPECT_EQ(EPERM, errno); ret = wait_any(fd, 1, &mutex, 456, &index); EXPECT_EQ(0, ret); EXPECT_EQ(0, index); check_mutex_state(mutex, 1, 456); ret = wait_any(fd, 1, &mutex, 456, &index); EXPECT_EQ(0, ret); EXPECT_EQ(0, index); check_mutex_state(mutex, 2, 456); ret = unlock_mutex(mutex, 456, &count); EXPECT_EQ(0, ret); EXPECT_EQ(2, count); check_mutex_state(mutex, 1, 456); ret = wait_any(fd, 1, &mutex, 123, &index); EXPECT_EQ(-1, ret); EXPECT_EQ(ETIMEDOUT, errno); owner = 0; ret = ioctl(mutex, NTSYNC_IOC_MUTEX_KILL, &owner); EXPECT_EQ(-1, ret); EXPECT_EQ(EINVAL, errno); owner = 123; ret = ioctl(mutex, NTSYNC_IOC_MUTEX_KILL, &owner); EXPECT_EQ(-1, ret); EXPECT_EQ(EPERM, errno); check_mutex_state(mutex, 1, 456); owner = 456; ret = ioctl(mutex, NTSYNC_IOC_MUTEX_KILL, &owner); EXPECT_EQ(0, ret); memset(&mutex_args, 0xcc, sizeof(mutex_args)); ret = ioctl(mutex, NTSYNC_IOC_MUTEX_READ, &mutex_args); EXPECT_EQ(-1, ret); EXPECT_EQ(EOWNERDEAD, errno); EXPECT_EQ(0, mutex_args.count); EXPECT_EQ(0, mutex_args.owner); memset(&mutex_args, 0xcc, sizeof(mutex_args)); ret = ioctl(mutex, NTSYNC_IOC_MUTEX_READ, &mutex_args); EXPECT_EQ(-1, ret); EXPECT_EQ(EOWNERDEAD, errno); EXPECT_EQ(0, mutex_args.count); EXPECT_EQ(0, mutex_args.owner); ret = wait_any(fd, 1, &mutex, 123, &index); EXPECT_EQ(-1, ret); EXPECT_EQ(EOWNERDEAD, errno); EXPECT_EQ(0, index); check_mutex_state(mutex, 1, 123); owner = 123; ret = ioctl(mutex, NTSYNC_IOC_MUTEX_KILL, &owner); EXPECT_EQ(0, ret); memset(&mutex_args, 0xcc, sizeof(mutex_args)); ret = ioctl(mutex, NTSYNC_IOC_MUTEX_READ, &mutex_args); EXPECT_EQ(-1, ret); EXPECT_EQ(EOWNERDEAD, errno); EXPECT_EQ(0, mutex_args.count); EXPECT_EQ(0, mutex_args.owner); ret = wait_any(fd, 1, &mutex, 123, &index); EXPECT_EQ(-1, ret); EXPECT_EQ(EOWNERDEAD, errno); EXPECT_EQ(0, index); check_mutex_state(mutex, 1, 123); close(mutex); mutex_args.owner = 0; mutex_args.count = 0; mutex = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); EXPECT_LE(0, mutex); check_mutex_state(mutex, 0, 0); ret = wait_any(fd, 1, &mutex, 123, &index); EXPECT_EQ(0, ret); EXPECT_EQ(0, index); check_mutex_state(mutex, 1, 123); close(mutex); mutex_args.owner = 123; mutex_args.count = ~0u; mutex = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); EXPECT_LE(0, mutex); check_mutex_state(mutex, ~0u, 123); ret = wait_any(fd, 1, &mutex, 123, &index); EXPECT_EQ(-1, ret); EXPECT_EQ(ETIMEDOUT, errno); close(mutex); close(fd);} TEST(manual_event_state){ struct ntsync_event_args event_args; __u32 index, signaled; int fd, event, ret; fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ASSERT_LE(0, fd); event_args.manual = 1; event_args.signaled = 0; event = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); EXPECT_LE(0, event); check_event_state(event, 0, 1); signaled = 0xdeadbeef; ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled); EXPECT_EQ(0, ret); EXPECT_EQ(0, signaled); check_event_state(event, 1, 1); ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled); EXPECT_EQ(0, ret); EXPECT_EQ(1, signaled); check_event_state(event, 1, 1); ret = wait_any(fd, 1, &event, 123, &index); EXPECT_EQ(0, ret); EXPECT_EQ(0, index); check_event_state(event, 1, 1); signaled = 0xdeadbeef; ret = ioctl(event, NTSYNC_IOC_EVENT_RESET, &signaled); EXPECT_EQ(0, ret); EXPECT_EQ(1, signaled); check_event_state(event, 0, 1); ret = ioctl(event, NTSYNC_IOC_EVENT_RESET, &signaled); EXPECT_EQ(0, ret); EXPECT_EQ(0, signaled); check_event_state(event, 0, 1); ret = wait_any(fd, 1, &event, 123, &index); EXPECT_EQ(-1, ret); EXPECT_EQ(ETIMEDOUT, errno); ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled); EXPECT_EQ(0, ret); EXPECT_EQ(0, signaled); ret = ioctl(event, NTSYNC_IOC_EVENT_PULSE, &signaled); EXPECT_EQ(0, ret); EXPECT_EQ(1, signaled); check_event_state(event, 0, 1); ret = ioctl(event, NTSYNC_IOC_EVENT_PULSE, &signaled); EXPECT_EQ(0, ret); EXPECT_EQ(0, signaled); check_event_state(event, 0, 1); close(event); close(fd);} TEST(auto_event_state){ struct ntsync_event_args event_args; __u32 index, signaled; int fd, event, ret; fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ASSERT_LE(0, fd); event_args.manual = 0; event_args.signaled = 1; event = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); EXPECT_LE(0, event); check_event_state(event, 1, 0); signaled = 0xdeadbeef; ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled); EXPECT_EQ(0, ret); EXPECT_EQ(1, signaled); check_event_state(event, 1, 0); ret = wait_any(fd, 1, &event, 123, &index); EXPECT_EQ(0, ret); EXPECT_EQ(0, index); check_event_state(event, 0, 0); signaled = 0xdeadbeef; ret = ioctl(event, NTSYNC_IOC_EVENT_RESET, &signaled); EXPECT_EQ(0, ret); EXPECT_EQ(0, signaled); check_event_state(event, 0, 0); ret = wait_any(fd, 1, &event, 123, &index); EXPECT_EQ(-1, ret); EXPECT_EQ(ETIMEDOUT, errno); ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled); EXPECT_EQ(0, ret); EXPECT_EQ(0, signaled); ret = ioctl(event, NTSYNC_IOC_EVENT_PULSE, &signaled); EXPECT_EQ(0, ret); EXPECT_EQ(1, signaled); check_event_state(event, 0, 0); ret = ioctl(event, NTSYNC_IOC_EVENT_PULSE, &signaled); EXPECT_EQ(0, ret); EXPECT_EQ(0, signaled); check_event_state(event, 0, 0); Lines 1–500 of 1474. Load more
// SPDX-License-Identifier: GPL-2.0-or-later /* * Various unit tests for the "ntsync" synchronization primitive driver. * * Copyright (C) 2021-2022 Elizabeth Figura <zfigura@codeweavers.com> */ #define _GNU_SOURCE #include <sys/ioctl.h> #include <sys/stat.h> #include <sys/wait.h> #include <fcntl.h> #include <sched.h> #include <time.h> #include <pthread.h> #include <linux/ntsync.h> #include "kselftest_harness.h" #ifndef CLONE_NEWTIME #define CLONE_NEWTIME 0x00000080 #endif static int read_sem_state(int sem, __u32 *count, __u32 *max) { struct ntsync_sem_args args; int ret; memset(&args, 0xcc, sizeof(args)); ret = ioctl(sem, NTSYNC_IOC_SEM_READ, &args); *count = args.count; *max = args.max; return ret; } #define check_sem_state(sem, count, max) \ ({ \ __u32 __count, __max; \ int ret = read_sem_state((sem), &__count, &__max); \ EXPECT_EQ(0, ret); \ EXPECT_EQ((count), __count); \ EXPECT_EQ((max), __max); \ }) static int release_sem(int sem, __u32 *count) { return ioctl(sem, NTSYNC_IOC_SEM_RELEASE, count); } static int read_mutex_state(int mutex, __u32 *count, __u32 *owner) { struct ntsync_mutex_args args; int ret; memset(&args, 0xcc, sizeof(args)); ret = ioctl(mutex, NTSYNC_IOC_MUTEX_READ, &args); *count = args.count; *owner = args.owner; return ret; } #define check_mutex_state(mutex, count, owner) \ ({ \ __u32 __count, __owner; \ int ret = read_mutex_state((mutex), &__count, &__owner); \ EXPECT_EQ(0, ret); \ EXPECT_EQ((count), __count); \ EXPECT_EQ((owner), __owner); \ }) static int unlock_mutex(int mutex, __u32 owner, __u32 *count) { struct ntsync_mutex_args args; int ret; args.owner = owner; args.count = 0xdeadbeef; ret = ioctl(mutex, NTSYNC_IOC_MUTEX_UNLOCK, &args); *count = args.count; return ret; } static int read_event_state(int event, __u32 *signaled, __u32 *manual) { struct ntsync_event_args args; int ret; memset(&args, 0xcc, sizeof(args)); ret = ioctl(event, NTSYNC_IOC_EVENT_READ, &args); *signaled = args.signaled; *manual = args.manual; return ret; } #define check_event_state(event, signaled, manual) \ ({ \ __u32 __signaled, __manual; \ int ret = read_event_state((event), &__signaled, &__manual); \ EXPECT_EQ(0, ret); \ EXPECT_EQ((signaled), __signaled); \ EXPECT_EQ((manual), __manual); \ }) static int wait_objs(int fd, unsigned long request, __u32 count, const int *objs, __u32 owner, int alert, __u32 *index) { struct ntsync_wait_args args = {0}; struct timespec timeout; int ret; clock_gettime(CLOCK_MONOTONIC, &timeout); args.timeout = timeout.tv_sec * 1000000000 + timeout.tv_nsec; args.count = count; args.objs = (uintptr_t)objs; args.owner = owner; args.index = 0xdeadbeef; args.alert = alert; ret = ioctl(fd, request, &args); *index = args.index; return ret; } static int wait_any(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index) { return wait_objs(fd, NTSYNC_IOC_WAIT_ANY, count, objs, owner, 0, index); } static int wait_all(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index) { return wait_objs(fd, NTSYNC_IOC_WAIT_ALL, count, objs, owner, 0, index); } static int wait_any_alert(int fd, __u32 count, const int *objs, __u32 owner, int alert, __u32 *index) { return wait_objs(fd, NTSYNC_IOC_WAIT_ANY, count, objs, owner, alert, index); } static int wait_all_alert(int fd, __u32 count, const int *objs, __u32 owner, int alert, __u32 *index) { return wait_objs(fd, NTSYNC_IOC_WAIT_ALL, count, objs, owner, alert, index); } TEST(semaphore_state) { struct ntsync_sem_args sem_args; struct timespec timeout; __u32 count, index; int fd, ret, sem; clock_gettime(CLOCK_MONOTONIC, &timeout); fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ASSERT_LE(0, fd); sem_args.count = 3; sem_args.max = 2; sem = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); EXPECT_EQ(-1, sem); EXPECT_EQ(EINVAL, errno); sem_args.count = 2; sem_args.max = 2; sem = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args); EXPECT_LE(0, sem); check_sem_state(sem, 2, 2); count = 0; ret = release_sem(sem, &count); EXPECT_EQ(0, ret); EXPECT_EQ(2, count); check_sem_state(sem, 2, 2); count = 1; ret = release_sem(sem, &count); EXPECT_EQ(-1, ret); EXPECT_EQ(EOVERFLOW, errno); check_sem_state(sem, 2, 2); ret = wait_any(fd, 1, &sem, 123, &index); EXPECT_EQ(0, ret); EXPECT_EQ(0, index); check_sem_state(sem, 1, 2); ret = wait_any(fd, 1, &sem, 123, &index); EXPECT_EQ(0, ret); EXPECT_EQ(0, index); check_sem_state(sem, 0, 2); ret = wait_any(fd, 1, &sem, 123, &index); EXPECT_EQ(-1, ret); EXPECT_EQ(ETIMEDOUT, errno); count = 3; ret = release_sem(sem, &count); EXPECT_EQ(-1, ret); EXPECT_EQ(EOVERFLOW, errno); check_sem_state(sem, 0, 2); count = 2; ret = release_sem(sem, &count); EXPECT_EQ(0, ret); EXPECT_EQ(0, count); check_sem_state(sem, 2, 2); ret = wait_any(fd, 1, &sem, 123, &index); EXPECT_EQ(0, ret); ret = wait_any(fd, 1, &sem, 123, &index); EXPECT_EQ(0, ret); count = 1; ret = release_sem(sem, &count); EXPECT_EQ(0, ret); EXPECT_EQ(0, count); check_sem_state(sem, 1, 2); count = ~0u; ret = release_sem(sem, &count); EXPECT_EQ(-1, ret); EXPECT_EQ(EOVERFLOW, errno); check_sem_state(sem, 1, 2); close(sem); close(fd); } TEST(mutex_state) { struct ntsync_mutex_args mutex_args; __u32 owner, count, index; struct timespec timeout; int fd, ret, mutex; clock_gettime(CLOCK_MONOTONIC, &timeout); fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ASSERT_LE(0, fd); mutex_args.owner = 123; mutex_args.count = 0; mutex = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); EXPECT_EQ(-1, mutex); EXPECT_EQ(EINVAL, errno); mutex_args.owner = 0; mutex_args.count = 2; mutex = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); EXPECT_EQ(-1, mutex); EXPECT_EQ(EINVAL, errno); mutex_args.owner = 123; mutex_args.count = 2; mutex = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); EXPECT_LE(0, mutex); check_mutex_state(mutex, 2, 123); ret = unlock_mutex(mutex, 0, &count); EXPECT_EQ(-1, ret); EXPECT_EQ(EINVAL, errno); ret = unlock_mutex(mutex, 456, &count); EXPECT_EQ(-1, ret); EXPECT_EQ(EPERM, errno); check_mutex_state(mutex, 2, 123); ret = unlock_mutex(mutex, 123, &count); EXPECT_EQ(0, ret); EXPECT_EQ(2, count); check_mutex_state(mutex, 1, 123); ret = unlock_mutex(mutex, 123, &count); EXPECT_EQ(0, ret); EXPECT_EQ(1, count); check_mutex_state(mutex, 0, 0); ret = unlock_mutex(mutex, 123, &count); EXPECT_EQ(-1, ret); EXPECT_EQ(EPERM, errno); ret = wait_any(fd, 1, &mutex, 456, &index); EXPECT_EQ(0, ret); EXPECT_EQ(0, index); check_mutex_state(mutex, 1, 456); ret = wait_any(fd, 1, &mutex, 456, &index); EXPECT_EQ(0, ret); EXPECT_EQ(0, index); check_mutex_state(mutex, 2, 456); ret = unlock_mutex(mutex, 456, &count); EXPECT_EQ(0, ret); EXPECT_EQ(2, count); check_mutex_state(mutex, 1, 456); ret = wait_any(fd, 1, &mutex, 123, &index); EXPECT_EQ(-1, ret); EXPECT_EQ(ETIMEDOUT, errno); owner = 0; ret = ioctl(mutex, NTSYNC_IOC_MUTEX_KILL, &owner); EXPECT_EQ(-1, ret); EXPECT_EQ(EINVAL, errno); owner = 123; ret = ioctl(mutex, NTSYNC_IOC_MUTEX_KILL, &owner); EXPECT_EQ(-1, ret); EXPECT_EQ(EPERM, errno); check_mutex_state(mutex, 1, 456); owner = 456; ret = ioctl(mutex, NTSYNC_IOC_MUTEX_KILL, &owner); EXPECT_EQ(0, ret); memset(&mutex_args, 0xcc, sizeof(mutex_args)); ret = ioctl(mutex, NTSYNC_IOC_MUTEX_READ, &mutex_args); EXPECT_EQ(-1, ret); EXPECT_EQ(EOWNERDEAD, errno); EXPECT_EQ(0, mutex_args.count); EXPECT_EQ(0, mutex_args.owner); memset(&mutex_args, 0xcc, sizeof(mutex_args)); ret = ioctl(mutex, NTSYNC_IOC_MUTEX_READ, &mutex_args); EXPECT_EQ(-1, ret); EXPECT_EQ(EOWNERDEAD, errno); EXPECT_EQ(0, mutex_args.count); EXPECT_EQ(0, mutex_args.owner); ret = wait_any(fd, 1, &mutex, 123, &index); EXPECT_EQ(-1, ret); EXPECT_EQ(EOWNERDEAD, errno); EXPECT_EQ(0, index); check_mutex_state(mutex, 1, 123); owner = 123; ret = ioctl(mutex, NTSYNC_IOC_MUTEX_KILL, &owner); EXPECT_EQ(0, ret); memset(&mutex_args, 0xcc, sizeof(mutex_args)); ret = ioctl(mutex, NTSYNC_IOC_MUTEX_READ, &mutex_args); EXPECT_EQ(-1, ret); EXPECT_EQ(EOWNERDEAD, errno); EXPECT_EQ(0, mutex_args.count); EXPECT_EQ(0, mutex_args.owner); ret = wait_any(fd, 1, &mutex, 123, &index); EXPECT_EQ(-1, ret); EXPECT_EQ(EOWNERDEAD, errno); EXPECT_EQ(0, index); check_mutex_state(mutex, 1, 123); close(mutex); mutex_args.owner = 0; mutex_args.count = 0; mutex = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); EXPECT_LE(0, mutex); check_mutex_state(mutex, 0, 0); ret = wait_any(fd, 1, &mutex, 123, &index); EXPECT_EQ(0, ret); EXPECT_EQ(0, index); check_mutex_state(mutex, 1, 123); close(mutex); mutex_args.owner = 123; mutex_args.count = ~0u; mutex = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args); EXPECT_LE(0, mutex); check_mutex_state(mutex, ~0u, 123); ret = wait_any(fd, 1, &mutex, 123, &index); EXPECT_EQ(-1, ret); EXPECT_EQ(ETIMEDOUT, errno); close(mutex); close(fd); } TEST(manual_event_state) { struct ntsync_event_args event_args; __u32 index, signaled; int fd, event, ret; fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ASSERT_LE(0, fd); event_args.manual = 1; event_args.signaled = 0; event = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); EXPECT_LE(0, event); check_event_state(event, 0, 1); signaled = 0xdeadbeef; ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled); EXPECT_EQ(0, ret); EXPECT_EQ(0, signaled); check_event_state(event, 1, 1); ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled); EXPECT_EQ(0, ret); EXPECT_EQ(1, signaled); check_event_state(event, 1, 1); ret = wait_any(fd, 1, &event, 123, &index); EXPECT_EQ(0, ret); EXPECT_EQ(0, index); check_event_state(event, 1, 1); signaled = 0xdeadbeef; ret = ioctl(event, NTSYNC_IOC_EVENT_RESET, &signaled); EXPECT_EQ(0, ret); EXPECT_EQ(1, signaled); check_event_state(event, 0, 1); ret = ioctl(event, NTSYNC_IOC_EVENT_RESET, &signaled); EXPECT_EQ(0, ret); EXPECT_EQ(0, signaled); check_event_state(event, 0, 1); ret = wait_any(fd, 1, &event, 123, &index); EXPECT_EQ(-1, ret); EXPECT_EQ(ETIMEDOUT, errno); ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled); EXPECT_EQ(0, ret); EXPECT_EQ(0, signaled); ret = ioctl(event, NTSYNC_IOC_EVENT_PULSE, &signaled); EXPECT_EQ(0, ret); EXPECT_EQ(1, signaled); check_event_state(event, 0, 1); ret = ioctl(event, NTSYNC_IOC_EVENT_PULSE, &signaled); EXPECT_EQ(0, ret); EXPECT_EQ(0, signaled); check_event_state(event, 0, 1); close(event); close(fd); } TEST(auto_event_state) { struct ntsync_event_args event_args; __u32 index, signaled; int fd, event, ret; fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY); ASSERT_LE(0, fd); event_args.manual = 0; event_args.signaled = 1; event = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args); EXPECT_LE(0, event); check_event_state(event, 1, 0); signaled = 0xdeadbeef; ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled); EXPECT_EQ(0, ret); EXPECT_EQ(1, signaled); check_event_state(event, 1, 0); ret = wait_any(fd, 1, &event, 123, &index); EXPECT_EQ(0, ret); EXPECT_EQ(0, index); check_event_state(event, 0, 0); signaled = 0xdeadbeef; ret = ioctl(event, NTSYNC_IOC_EVENT_RESET, &signaled); EXPECT_EQ(0, ret); EXPECT_EQ(0, signaled); check_event_state(event, 0, 0); ret = wait_any(fd, 1, &event, 123, &index); EXPECT_EQ(-1, ret); EXPECT_EQ(ETIMEDOUT, errno); ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled); EXPECT_EQ(0, ret); EXPECT_EQ(0, signaled); ret = ioctl(event, NTSYNC_IOC_EVENT_PULSE, &signaled); EXPECT_EQ(0, ret); EXPECT_EQ(1, signaled); check_event_state(event, 0, 0); ret = ioctl(event, NTSYNC_IOC_EVENT_PULSE, &signaled); EXPECT_EQ(0, ret); EXPECT_EQ(0, signaled); check_event_state(event, 0, 0);