Path: blob/master/tools/testing/selftests/drivers/ntsync/ntsync.c
26295 views
// SPDX-License-Identifier: GPL-2.0-or-later1/*2* Various unit tests for the "ntsync" synchronization primitive driver.3*4* Copyright (C) 2021-2022 Elizabeth Figura <[email protected]>5*/67#define _GNU_SOURCE8#include <sys/ioctl.h>9#include <sys/stat.h>10#include <fcntl.h>11#include <time.h>12#include <pthread.h>13#include <linux/ntsync.h>14#include "../../kselftest_harness.h"1516static int read_sem_state(int sem, __u32 *count, __u32 *max)17{18struct ntsync_sem_args args;19int ret;2021memset(&args, 0xcc, sizeof(args));22ret = ioctl(sem, NTSYNC_IOC_SEM_READ, &args);23*count = args.count;24*max = args.max;25return ret;26}2728#define check_sem_state(sem, count, max) \29({ \30__u32 __count, __max; \31int ret = read_sem_state((sem), &__count, &__max); \32EXPECT_EQ(0, ret); \33EXPECT_EQ((count), __count); \34EXPECT_EQ((max), __max); \35})3637static int release_sem(int sem, __u32 *count)38{39return ioctl(sem, NTSYNC_IOC_SEM_RELEASE, count);40}4142static int read_mutex_state(int mutex, __u32 *count, __u32 *owner)43{44struct ntsync_mutex_args args;45int ret;4647memset(&args, 0xcc, sizeof(args));48ret = ioctl(mutex, NTSYNC_IOC_MUTEX_READ, &args);49*count = args.count;50*owner = args.owner;51return ret;52}5354#define check_mutex_state(mutex, count, owner) \55({ \56__u32 __count, __owner; \57int ret = read_mutex_state((mutex), &__count, &__owner); \58EXPECT_EQ(0, ret); \59EXPECT_EQ((count), __count); \60EXPECT_EQ((owner), __owner); \61})6263static int unlock_mutex(int mutex, __u32 owner, __u32 *count)64{65struct ntsync_mutex_args args;66int ret;6768args.owner = owner;69args.count = 0xdeadbeef;70ret = ioctl(mutex, NTSYNC_IOC_MUTEX_UNLOCK, &args);71*count = args.count;72return ret;73}7475static int read_event_state(int event, __u32 *signaled, __u32 *manual)76{77struct ntsync_event_args args;78int ret;7980memset(&args, 0xcc, sizeof(args));81ret = ioctl(event, NTSYNC_IOC_EVENT_READ, &args);82*signaled = args.signaled;83*manual = args.manual;84return ret;85}8687#define check_event_state(event, signaled, manual) \88({ \89__u32 __signaled, __manual; \90int ret = read_event_state((event), &__signaled, &__manual); \91EXPECT_EQ(0, ret); \92EXPECT_EQ((signaled), __signaled); \93EXPECT_EQ((manual), __manual); \94})9596static int wait_objs(int fd, unsigned long request, __u32 count,97const int *objs, __u32 owner, int alert, __u32 *index)98{99struct ntsync_wait_args args = {0};100struct timespec timeout;101int ret;102103clock_gettime(CLOCK_MONOTONIC, &timeout);104105args.timeout = timeout.tv_sec * 1000000000 + timeout.tv_nsec;106args.count = count;107args.objs = (uintptr_t)objs;108args.owner = owner;109args.index = 0xdeadbeef;110args.alert = alert;111ret = ioctl(fd, request, &args);112*index = args.index;113return ret;114}115116static int wait_any(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index)117{118return wait_objs(fd, NTSYNC_IOC_WAIT_ANY, count, objs, owner, 0, index);119}120121static int wait_all(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index)122{123return wait_objs(fd, NTSYNC_IOC_WAIT_ALL, count, objs, owner, 0, index);124}125126static int wait_any_alert(int fd, __u32 count, const int *objs,127__u32 owner, int alert, __u32 *index)128{129return wait_objs(fd, NTSYNC_IOC_WAIT_ANY,130count, objs, owner, alert, index);131}132133static int wait_all_alert(int fd, __u32 count, const int *objs,134__u32 owner, int alert, __u32 *index)135{136return wait_objs(fd, NTSYNC_IOC_WAIT_ALL,137count, objs, owner, alert, index);138}139140TEST(semaphore_state)141{142struct ntsync_sem_args sem_args;143struct timespec timeout;144__u32 count, index;145int fd, ret, sem;146147clock_gettime(CLOCK_MONOTONIC, &timeout);148149fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);150ASSERT_LE(0, fd);151152sem_args.count = 3;153sem_args.max = 2;154sem = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args);155EXPECT_EQ(-1, sem);156EXPECT_EQ(EINVAL, errno);157158sem_args.count = 2;159sem_args.max = 2;160sem = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args);161EXPECT_LE(0, sem);162check_sem_state(sem, 2, 2);163164count = 0;165ret = release_sem(sem, &count);166EXPECT_EQ(0, ret);167EXPECT_EQ(2, count);168check_sem_state(sem, 2, 2);169170count = 1;171ret = release_sem(sem, &count);172EXPECT_EQ(-1, ret);173EXPECT_EQ(EOVERFLOW, errno);174check_sem_state(sem, 2, 2);175176ret = wait_any(fd, 1, &sem, 123, &index);177EXPECT_EQ(0, ret);178EXPECT_EQ(0, index);179check_sem_state(sem, 1, 2);180181ret = wait_any(fd, 1, &sem, 123, &index);182EXPECT_EQ(0, ret);183EXPECT_EQ(0, index);184check_sem_state(sem, 0, 2);185186ret = wait_any(fd, 1, &sem, 123, &index);187EXPECT_EQ(-1, ret);188EXPECT_EQ(ETIMEDOUT, errno);189190count = 3;191ret = release_sem(sem, &count);192EXPECT_EQ(-1, ret);193EXPECT_EQ(EOVERFLOW, errno);194check_sem_state(sem, 0, 2);195196count = 2;197ret = release_sem(sem, &count);198EXPECT_EQ(0, ret);199EXPECT_EQ(0, count);200check_sem_state(sem, 2, 2);201202ret = wait_any(fd, 1, &sem, 123, &index);203EXPECT_EQ(0, ret);204ret = wait_any(fd, 1, &sem, 123, &index);205EXPECT_EQ(0, ret);206207count = 1;208ret = release_sem(sem, &count);209EXPECT_EQ(0, ret);210EXPECT_EQ(0, count);211check_sem_state(sem, 1, 2);212213count = ~0u;214ret = release_sem(sem, &count);215EXPECT_EQ(-1, ret);216EXPECT_EQ(EOVERFLOW, errno);217check_sem_state(sem, 1, 2);218219close(sem);220221close(fd);222}223224TEST(mutex_state)225{226struct ntsync_mutex_args mutex_args;227__u32 owner, count, index;228struct timespec timeout;229int fd, ret, mutex;230231clock_gettime(CLOCK_MONOTONIC, &timeout);232233fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);234ASSERT_LE(0, fd);235236mutex_args.owner = 123;237mutex_args.count = 0;238mutex = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args);239EXPECT_EQ(-1, mutex);240EXPECT_EQ(EINVAL, errno);241242mutex_args.owner = 0;243mutex_args.count = 2;244mutex = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args);245EXPECT_EQ(-1, mutex);246EXPECT_EQ(EINVAL, errno);247248mutex_args.owner = 123;249mutex_args.count = 2;250mutex = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args);251EXPECT_LE(0, mutex);252check_mutex_state(mutex, 2, 123);253254ret = unlock_mutex(mutex, 0, &count);255EXPECT_EQ(-1, ret);256EXPECT_EQ(EINVAL, errno);257258ret = unlock_mutex(mutex, 456, &count);259EXPECT_EQ(-1, ret);260EXPECT_EQ(EPERM, errno);261check_mutex_state(mutex, 2, 123);262263ret = unlock_mutex(mutex, 123, &count);264EXPECT_EQ(0, ret);265EXPECT_EQ(2, count);266check_mutex_state(mutex, 1, 123);267268ret = unlock_mutex(mutex, 123, &count);269EXPECT_EQ(0, ret);270EXPECT_EQ(1, count);271check_mutex_state(mutex, 0, 0);272273ret = unlock_mutex(mutex, 123, &count);274EXPECT_EQ(-1, ret);275EXPECT_EQ(EPERM, errno);276277ret = wait_any(fd, 1, &mutex, 456, &index);278EXPECT_EQ(0, ret);279EXPECT_EQ(0, index);280check_mutex_state(mutex, 1, 456);281282ret = wait_any(fd, 1, &mutex, 456, &index);283EXPECT_EQ(0, ret);284EXPECT_EQ(0, index);285check_mutex_state(mutex, 2, 456);286287ret = unlock_mutex(mutex, 456, &count);288EXPECT_EQ(0, ret);289EXPECT_EQ(2, count);290check_mutex_state(mutex, 1, 456);291292ret = wait_any(fd, 1, &mutex, 123, &index);293EXPECT_EQ(-1, ret);294EXPECT_EQ(ETIMEDOUT, errno);295296owner = 0;297ret = ioctl(mutex, NTSYNC_IOC_MUTEX_KILL, &owner);298EXPECT_EQ(-1, ret);299EXPECT_EQ(EINVAL, errno);300301owner = 123;302ret = ioctl(mutex, NTSYNC_IOC_MUTEX_KILL, &owner);303EXPECT_EQ(-1, ret);304EXPECT_EQ(EPERM, errno);305check_mutex_state(mutex, 1, 456);306307owner = 456;308ret = ioctl(mutex, NTSYNC_IOC_MUTEX_KILL, &owner);309EXPECT_EQ(0, ret);310311memset(&mutex_args, 0xcc, sizeof(mutex_args));312ret = ioctl(mutex, NTSYNC_IOC_MUTEX_READ, &mutex_args);313EXPECT_EQ(-1, ret);314EXPECT_EQ(EOWNERDEAD, errno);315EXPECT_EQ(0, mutex_args.count);316EXPECT_EQ(0, mutex_args.owner);317318memset(&mutex_args, 0xcc, sizeof(mutex_args));319ret = ioctl(mutex, NTSYNC_IOC_MUTEX_READ, &mutex_args);320EXPECT_EQ(-1, ret);321EXPECT_EQ(EOWNERDEAD, errno);322EXPECT_EQ(0, mutex_args.count);323EXPECT_EQ(0, mutex_args.owner);324325ret = wait_any(fd, 1, &mutex, 123, &index);326EXPECT_EQ(-1, ret);327EXPECT_EQ(EOWNERDEAD, errno);328EXPECT_EQ(0, index);329check_mutex_state(mutex, 1, 123);330331owner = 123;332ret = ioctl(mutex, NTSYNC_IOC_MUTEX_KILL, &owner);333EXPECT_EQ(0, ret);334335memset(&mutex_args, 0xcc, sizeof(mutex_args));336ret = ioctl(mutex, NTSYNC_IOC_MUTEX_READ, &mutex_args);337EXPECT_EQ(-1, ret);338EXPECT_EQ(EOWNERDEAD, errno);339EXPECT_EQ(0, mutex_args.count);340EXPECT_EQ(0, mutex_args.owner);341342ret = wait_any(fd, 1, &mutex, 123, &index);343EXPECT_EQ(-1, ret);344EXPECT_EQ(EOWNERDEAD, errno);345EXPECT_EQ(0, index);346check_mutex_state(mutex, 1, 123);347348close(mutex);349350mutex_args.owner = 0;351mutex_args.count = 0;352mutex = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args);353EXPECT_LE(0, mutex);354check_mutex_state(mutex, 0, 0);355356ret = wait_any(fd, 1, &mutex, 123, &index);357EXPECT_EQ(0, ret);358EXPECT_EQ(0, index);359check_mutex_state(mutex, 1, 123);360361close(mutex);362363mutex_args.owner = 123;364mutex_args.count = ~0u;365mutex = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args);366EXPECT_LE(0, mutex);367check_mutex_state(mutex, ~0u, 123);368369ret = wait_any(fd, 1, &mutex, 123, &index);370EXPECT_EQ(-1, ret);371EXPECT_EQ(ETIMEDOUT, errno);372373close(mutex);374375close(fd);376}377378TEST(manual_event_state)379{380struct ntsync_event_args event_args;381__u32 index, signaled;382int fd, event, ret;383384fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);385ASSERT_LE(0, fd);386387event_args.manual = 1;388event_args.signaled = 0;389event = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args);390EXPECT_LE(0, event);391check_event_state(event, 0, 1);392393signaled = 0xdeadbeef;394ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled);395EXPECT_EQ(0, ret);396EXPECT_EQ(0, signaled);397check_event_state(event, 1, 1);398399ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled);400EXPECT_EQ(0, ret);401EXPECT_EQ(1, signaled);402check_event_state(event, 1, 1);403404ret = wait_any(fd, 1, &event, 123, &index);405EXPECT_EQ(0, ret);406EXPECT_EQ(0, index);407check_event_state(event, 1, 1);408409signaled = 0xdeadbeef;410ret = ioctl(event, NTSYNC_IOC_EVENT_RESET, &signaled);411EXPECT_EQ(0, ret);412EXPECT_EQ(1, signaled);413check_event_state(event, 0, 1);414415ret = ioctl(event, NTSYNC_IOC_EVENT_RESET, &signaled);416EXPECT_EQ(0, ret);417EXPECT_EQ(0, signaled);418check_event_state(event, 0, 1);419420ret = wait_any(fd, 1, &event, 123, &index);421EXPECT_EQ(-1, ret);422EXPECT_EQ(ETIMEDOUT, errno);423424ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled);425EXPECT_EQ(0, ret);426EXPECT_EQ(0, signaled);427428ret = ioctl(event, NTSYNC_IOC_EVENT_PULSE, &signaled);429EXPECT_EQ(0, ret);430EXPECT_EQ(1, signaled);431check_event_state(event, 0, 1);432433ret = ioctl(event, NTSYNC_IOC_EVENT_PULSE, &signaled);434EXPECT_EQ(0, ret);435EXPECT_EQ(0, signaled);436check_event_state(event, 0, 1);437438close(event);439440close(fd);441}442443TEST(auto_event_state)444{445struct ntsync_event_args event_args;446__u32 index, signaled;447int fd, event, ret;448449fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);450ASSERT_LE(0, fd);451452event_args.manual = 0;453event_args.signaled = 1;454event = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args);455EXPECT_LE(0, event);456457check_event_state(event, 1, 0);458459signaled = 0xdeadbeef;460ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled);461EXPECT_EQ(0, ret);462EXPECT_EQ(1, signaled);463check_event_state(event, 1, 0);464465ret = wait_any(fd, 1, &event, 123, &index);466EXPECT_EQ(0, ret);467EXPECT_EQ(0, index);468check_event_state(event, 0, 0);469470signaled = 0xdeadbeef;471ret = ioctl(event, NTSYNC_IOC_EVENT_RESET, &signaled);472EXPECT_EQ(0, ret);473EXPECT_EQ(0, signaled);474check_event_state(event, 0, 0);475476ret = wait_any(fd, 1, &event, 123, &index);477EXPECT_EQ(-1, ret);478EXPECT_EQ(ETIMEDOUT, errno);479480ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled);481EXPECT_EQ(0, ret);482EXPECT_EQ(0, signaled);483484ret = ioctl(event, NTSYNC_IOC_EVENT_PULSE, &signaled);485EXPECT_EQ(0, ret);486EXPECT_EQ(1, signaled);487check_event_state(event, 0, 0);488489ret = ioctl(event, NTSYNC_IOC_EVENT_PULSE, &signaled);490EXPECT_EQ(0, ret);491EXPECT_EQ(0, signaled);492check_event_state(event, 0, 0);493494close(event);495496close(fd);497}498499TEST(test_wait_any)500{501int objs[NTSYNC_MAX_WAIT_COUNT + 1], fd, ret;502struct ntsync_mutex_args mutex_args = {0};503struct ntsync_sem_args sem_args = {0};504__u32 owner, index, count, i;505struct timespec timeout;506507clock_gettime(CLOCK_MONOTONIC, &timeout);508509fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);510ASSERT_LE(0, fd);511512sem_args.count = 2;513sem_args.max = 3;514objs[0] = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args);515EXPECT_LE(0, objs[0]);516517mutex_args.owner = 0;518mutex_args.count = 0;519objs[1] = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args);520EXPECT_LE(0, objs[1]);521522ret = wait_any(fd, 2, objs, 123, &index);523EXPECT_EQ(0, ret);524EXPECT_EQ(0, index);525check_sem_state(objs[0], 1, 3);526check_mutex_state(objs[1], 0, 0);527528ret = wait_any(fd, 2, objs, 123, &index);529EXPECT_EQ(0, ret);530EXPECT_EQ(0, index);531check_sem_state(objs[0], 0, 3);532check_mutex_state(objs[1], 0, 0);533534ret = wait_any(fd, 2, objs, 123, &index);535EXPECT_EQ(0, ret);536EXPECT_EQ(1, index);537check_sem_state(objs[0], 0, 3);538check_mutex_state(objs[1], 1, 123);539540count = 1;541ret = release_sem(objs[0], &count);542EXPECT_EQ(0, ret);543EXPECT_EQ(0, count);544545ret = wait_any(fd, 2, objs, 123, &index);546EXPECT_EQ(0, ret);547EXPECT_EQ(0, index);548check_sem_state(objs[0], 0, 3);549check_mutex_state(objs[1], 1, 123);550551ret = wait_any(fd, 2, objs, 123, &index);552EXPECT_EQ(0, ret);553EXPECT_EQ(1, index);554check_sem_state(objs[0], 0, 3);555check_mutex_state(objs[1], 2, 123);556557ret = wait_any(fd, 2, objs, 456, &index);558EXPECT_EQ(-1, ret);559EXPECT_EQ(ETIMEDOUT, errno);560561owner = 123;562ret = ioctl(objs[1], NTSYNC_IOC_MUTEX_KILL, &owner);563EXPECT_EQ(0, ret);564565ret = wait_any(fd, 2, objs, 456, &index);566EXPECT_EQ(-1, ret);567EXPECT_EQ(EOWNERDEAD, errno);568EXPECT_EQ(1, index);569570ret = wait_any(fd, 2, objs, 456, &index);571EXPECT_EQ(0, ret);572EXPECT_EQ(1, index);573574close(objs[1]);575576/* test waiting on the same object twice */577578count = 2;579ret = release_sem(objs[0], &count);580EXPECT_EQ(0, ret);581EXPECT_EQ(0, count);582583objs[1] = objs[0];584ret = wait_any(fd, 2, objs, 456, &index);585EXPECT_EQ(0, ret);586EXPECT_EQ(0, index);587check_sem_state(objs[0], 1, 3);588589ret = wait_any(fd, 0, NULL, 456, &index);590EXPECT_EQ(-1, ret);591EXPECT_EQ(ETIMEDOUT, errno);592593for (i = 1; i < NTSYNC_MAX_WAIT_COUNT + 1; ++i)594objs[i] = objs[0];595596ret = wait_any(fd, NTSYNC_MAX_WAIT_COUNT, objs, 123, &index);597EXPECT_EQ(0, ret);598EXPECT_EQ(0, index);599600ret = wait_any(fd, NTSYNC_MAX_WAIT_COUNT + 1, objs, 123, &index);601EXPECT_EQ(-1, ret);602EXPECT_EQ(EINVAL, errno);603604ret = wait_any(fd, -1, objs, 123, &index);605EXPECT_EQ(-1, ret);606EXPECT_EQ(EINVAL, errno);607608close(objs[0]);609610close(fd);611}612613TEST(test_wait_all)614{615struct ntsync_event_args event_args = {0};616struct ntsync_mutex_args mutex_args = {0};617struct ntsync_sem_args sem_args = {0};618__u32 owner, index, count;619int objs[2], fd, ret;620621fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);622ASSERT_LE(0, fd);623624sem_args.count = 2;625sem_args.max = 3;626objs[0] = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args);627EXPECT_LE(0, objs[0]);628629mutex_args.owner = 0;630mutex_args.count = 0;631objs[1] = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args);632EXPECT_LE(0, objs[1]);633634ret = wait_all(fd, 2, objs, 123, &index);635EXPECT_EQ(0, ret);636EXPECT_EQ(0, index);637check_sem_state(objs[0], 1, 3);638check_mutex_state(objs[1], 1, 123);639640ret = wait_all(fd, 2, objs, 456, &index);641EXPECT_EQ(-1, ret);642EXPECT_EQ(ETIMEDOUT, errno);643check_sem_state(objs[0], 1, 3);644check_mutex_state(objs[1], 1, 123);645646ret = wait_all(fd, 2, objs, 123, &index);647EXPECT_EQ(0, ret);648EXPECT_EQ(0, index);649check_sem_state(objs[0], 0, 3);650check_mutex_state(objs[1], 2, 123);651652ret = wait_all(fd, 2, objs, 123, &index);653EXPECT_EQ(-1, ret);654EXPECT_EQ(ETIMEDOUT, errno);655check_sem_state(objs[0], 0, 3);656check_mutex_state(objs[1], 2, 123);657658count = 3;659ret = release_sem(objs[0], &count);660EXPECT_EQ(0, ret);661EXPECT_EQ(0, count);662663ret = wait_all(fd, 2, objs, 123, &index);664EXPECT_EQ(0, ret);665EXPECT_EQ(0, index);666check_sem_state(objs[0], 2, 3);667check_mutex_state(objs[1], 3, 123);668669owner = 123;670ret = ioctl(objs[1], NTSYNC_IOC_MUTEX_KILL, &owner);671EXPECT_EQ(0, ret);672673ret = wait_all(fd, 2, objs, 123, &index);674EXPECT_EQ(-1, ret);675EXPECT_EQ(EOWNERDEAD, errno);676check_sem_state(objs[0], 1, 3);677check_mutex_state(objs[1], 1, 123);678679close(objs[1]);680681event_args.manual = true;682event_args.signaled = true;683objs[1] = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args);684EXPECT_LE(0, objs[1]);685686ret = wait_all(fd, 2, objs, 123, &index);687EXPECT_EQ(0, ret);688EXPECT_EQ(0, index);689check_sem_state(objs[0], 0, 3);690check_event_state(objs[1], 1, 1);691692close(objs[1]);693694/* test waiting on the same object twice */695objs[1] = objs[0];696ret = wait_all(fd, 2, objs, 123, &index);697EXPECT_EQ(-1, ret);698EXPECT_EQ(EINVAL, errno);699700close(objs[0]);701702close(fd);703}704705struct wake_args {706int fd;707int obj;708};709710struct wait_args {711int fd;712unsigned long request;713struct ntsync_wait_args *args;714int ret;715int err;716};717718static void *wait_thread(void *arg)719{720struct wait_args *args = arg;721722args->ret = ioctl(args->fd, args->request, args->args);723args->err = errno;724return NULL;725}726727static __u64 get_abs_timeout(unsigned int ms)728{729struct timespec timeout;730clock_gettime(CLOCK_MONOTONIC, &timeout);731return (timeout.tv_sec * 1000000000) + timeout.tv_nsec + (ms * 1000000);732}733734static int wait_for_thread(pthread_t thread, unsigned int ms)735{736struct timespec timeout;737738clock_gettime(CLOCK_REALTIME, &timeout);739timeout.tv_nsec += ms * 1000000;740timeout.tv_sec += (timeout.tv_nsec / 1000000000);741timeout.tv_nsec %= 1000000000;742return pthread_timedjoin_np(thread, NULL, &timeout);743}744745TEST(wake_any)746{747struct ntsync_event_args event_args = {0};748struct ntsync_mutex_args mutex_args = {0};749struct ntsync_wait_args wait_args = {0};750struct ntsync_sem_args sem_args = {0};751struct wait_args thread_args;752__u32 count, index, signaled;753int objs[2], fd, ret;754pthread_t thread;755756fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);757ASSERT_LE(0, fd);758759sem_args.count = 0;760sem_args.max = 3;761objs[0] = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args);762EXPECT_LE(0, objs[0]);763764mutex_args.owner = 123;765mutex_args.count = 1;766objs[1] = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args);767EXPECT_LE(0, objs[1]);768769/* test waking the semaphore */770771wait_args.timeout = get_abs_timeout(1000);772wait_args.objs = (uintptr_t)objs;773wait_args.count = 2;774wait_args.owner = 456;775wait_args.index = 0xdeadbeef;776thread_args.fd = fd;777thread_args.args = &wait_args;778thread_args.request = NTSYNC_IOC_WAIT_ANY;779ret = pthread_create(&thread, NULL, wait_thread, &thread_args);780EXPECT_EQ(0, ret);781782ret = wait_for_thread(thread, 100);783EXPECT_EQ(ETIMEDOUT, ret);784785count = 1;786ret = release_sem(objs[0], &count);787EXPECT_EQ(0, ret);788EXPECT_EQ(0, count);789check_sem_state(objs[0], 0, 3);790791ret = wait_for_thread(thread, 100);792EXPECT_EQ(0, ret);793EXPECT_EQ(0, thread_args.ret);794EXPECT_EQ(0, wait_args.index);795796/* test waking the mutex */797798/* first grab it again for owner 123 */799ret = wait_any(fd, 1, &objs[1], 123, &index);800EXPECT_EQ(0, ret);801EXPECT_EQ(0, index);802803wait_args.timeout = get_abs_timeout(1000);804wait_args.owner = 456;805ret = pthread_create(&thread, NULL, wait_thread, &thread_args);806EXPECT_EQ(0, ret);807808ret = wait_for_thread(thread, 100);809EXPECT_EQ(ETIMEDOUT, ret);810811ret = unlock_mutex(objs[1], 123, &count);812EXPECT_EQ(0, ret);813EXPECT_EQ(2, count);814815ret = pthread_tryjoin_np(thread, NULL);816EXPECT_EQ(EBUSY, ret);817818ret = unlock_mutex(objs[1], 123, &count);819EXPECT_EQ(0, ret);820EXPECT_EQ(1, mutex_args.count);821check_mutex_state(objs[1], 1, 456);822823ret = wait_for_thread(thread, 100);824EXPECT_EQ(0, ret);825EXPECT_EQ(0, thread_args.ret);826EXPECT_EQ(1, wait_args.index);827828close(objs[1]);829830/* test waking events */831832event_args.manual = false;833event_args.signaled = false;834objs[1] = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args);835EXPECT_LE(0, objs[1]);836837wait_args.timeout = get_abs_timeout(1000);838ret = pthread_create(&thread, NULL, wait_thread, &thread_args);839EXPECT_EQ(0, ret);840841ret = wait_for_thread(thread, 100);842EXPECT_EQ(ETIMEDOUT, ret);843844ret = ioctl(objs[1], NTSYNC_IOC_EVENT_SET, &signaled);845EXPECT_EQ(0, ret);846EXPECT_EQ(0, signaled);847check_event_state(objs[1], 0, 0);848849ret = wait_for_thread(thread, 100);850EXPECT_EQ(0, ret);851EXPECT_EQ(0, thread_args.ret);852EXPECT_EQ(1, wait_args.index);853854wait_args.timeout = get_abs_timeout(1000);855ret = pthread_create(&thread, NULL, wait_thread, &thread_args);856EXPECT_EQ(0, ret);857858ret = wait_for_thread(thread, 100);859EXPECT_EQ(ETIMEDOUT, ret);860861ret = ioctl(objs[1], NTSYNC_IOC_EVENT_PULSE, &signaled);862EXPECT_EQ(0, ret);863EXPECT_EQ(0, signaled);864check_event_state(objs[1], 0, 0);865866ret = wait_for_thread(thread, 100);867EXPECT_EQ(0, ret);868EXPECT_EQ(0, thread_args.ret);869EXPECT_EQ(1, wait_args.index);870871close(objs[1]);872873event_args.manual = true;874event_args.signaled = false;875objs[1] = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args);876EXPECT_LE(0, objs[1]);877878wait_args.timeout = get_abs_timeout(1000);879ret = pthread_create(&thread, NULL, wait_thread, &thread_args);880EXPECT_EQ(0, ret);881882ret = wait_for_thread(thread, 100);883EXPECT_EQ(ETIMEDOUT, ret);884885ret = ioctl(objs[1], NTSYNC_IOC_EVENT_SET, &signaled);886EXPECT_EQ(0, ret);887EXPECT_EQ(0, signaled);888check_event_state(objs[1], 1, 1);889890ret = wait_for_thread(thread, 100);891EXPECT_EQ(0, ret);892EXPECT_EQ(0, thread_args.ret);893EXPECT_EQ(1, wait_args.index);894895ret = ioctl(objs[1], NTSYNC_IOC_EVENT_RESET, &signaled);896EXPECT_EQ(0, ret);897EXPECT_EQ(1, signaled);898899wait_args.timeout = get_abs_timeout(1000);900ret = pthread_create(&thread, NULL, wait_thread, &thread_args);901EXPECT_EQ(0, ret);902903ret = wait_for_thread(thread, 100);904EXPECT_EQ(ETIMEDOUT, ret);905906ret = ioctl(objs[1], NTSYNC_IOC_EVENT_PULSE, &signaled);907EXPECT_EQ(0, ret);908EXPECT_EQ(0, signaled);909check_event_state(objs[1], 0, 1);910911ret = wait_for_thread(thread, 100);912EXPECT_EQ(0, ret);913EXPECT_EQ(0, thread_args.ret);914EXPECT_EQ(1, wait_args.index);915916/* delete an object while it's being waited on */917918wait_args.timeout = get_abs_timeout(200);919wait_args.owner = 123;920ret = pthread_create(&thread, NULL, wait_thread, &thread_args);921EXPECT_EQ(0, ret);922923ret = wait_for_thread(thread, 100);924EXPECT_EQ(ETIMEDOUT, ret);925926close(objs[0]);927close(objs[1]);928929ret = wait_for_thread(thread, 200);930EXPECT_EQ(0, ret);931EXPECT_EQ(-1, thread_args.ret);932EXPECT_EQ(ETIMEDOUT, thread_args.err);933934close(fd);935}936937TEST(wake_all)938{939struct ntsync_event_args manual_event_args = {0};940struct ntsync_event_args auto_event_args = {0};941struct ntsync_mutex_args mutex_args = {0};942struct ntsync_wait_args wait_args = {0};943struct ntsync_sem_args sem_args = {0};944struct wait_args thread_args;945__u32 count, index, signaled;946int objs[4], fd, ret;947pthread_t thread;948949fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);950ASSERT_LE(0, fd);951952sem_args.count = 0;953sem_args.max = 3;954objs[0] = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args);955EXPECT_LE(0, objs[0]);956957mutex_args.owner = 123;958mutex_args.count = 1;959objs[1] = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args);960EXPECT_LE(0, objs[1]);961962manual_event_args.manual = true;963manual_event_args.signaled = true;964objs[2] = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &manual_event_args);965EXPECT_LE(0, objs[2]);966967auto_event_args.manual = false;968auto_event_args.signaled = true;969objs[3] = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &auto_event_args);970EXPECT_EQ(0, objs[3]);971972wait_args.timeout = get_abs_timeout(1000);973wait_args.objs = (uintptr_t)objs;974wait_args.count = 4;975wait_args.owner = 456;976thread_args.fd = fd;977thread_args.args = &wait_args;978thread_args.request = NTSYNC_IOC_WAIT_ALL;979ret = pthread_create(&thread, NULL, wait_thread, &thread_args);980EXPECT_EQ(0, ret);981982ret = wait_for_thread(thread, 100);983EXPECT_EQ(ETIMEDOUT, ret);984985count = 1;986ret = release_sem(objs[0], &count);987EXPECT_EQ(0, ret);988EXPECT_EQ(0, count);989990ret = pthread_tryjoin_np(thread, NULL);991EXPECT_EQ(EBUSY, ret);992993check_sem_state(objs[0], 1, 3);994995ret = wait_any(fd, 1, &objs[0], 123, &index);996EXPECT_EQ(0, ret);997EXPECT_EQ(0, index);998999ret = unlock_mutex(objs[1], 123, &count);1000EXPECT_EQ(0, ret);1001EXPECT_EQ(1, count);10021003ret = pthread_tryjoin_np(thread, NULL);1004EXPECT_EQ(EBUSY, ret);10051006check_mutex_state(objs[1], 0, 0);10071008ret = ioctl(objs[2], NTSYNC_IOC_EVENT_RESET, &signaled);1009EXPECT_EQ(0, ret);1010EXPECT_EQ(1, signaled);10111012count = 2;1013ret = release_sem(objs[0], &count);1014EXPECT_EQ(0, ret);1015EXPECT_EQ(0, count);1016check_sem_state(objs[0], 2, 3);10171018ret = ioctl(objs[3], NTSYNC_IOC_EVENT_RESET, &signaled);1019EXPECT_EQ(0, ret);1020EXPECT_EQ(1, signaled);10211022ret = ioctl(objs[2], NTSYNC_IOC_EVENT_SET, &signaled);1023EXPECT_EQ(0, ret);1024EXPECT_EQ(0, signaled);10251026ret = ioctl(objs[3], NTSYNC_IOC_EVENT_SET, &signaled);1027EXPECT_EQ(0, ret);1028EXPECT_EQ(0, signaled);10291030check_sem_state(objs[0], 1, 3);1031check_mutex_state(objs[1], 1, 456);1032check_event_state(objs[2], 1, 1);1033check_event_state(objs[3], 0, 0);10341035ret = wait_for_thread(thread, 100);1036EXPECT_EQ(0, ret);1037EXPECT_EQ(0, thread_args.ret);10381039/* delete an object while it's being waited on */10401041wait_args.timeout = get_abs_timeout(200);1042wait_args.owner = 123;1043ret = pthread_create(&thread, NULL, wait_thread, &thread_args);1044EXPECT_EQ(0, ret);10451046ret = wait_for_thread(thread, 100);1047EXPECT_EQ(ETIMEDOUT, ret);10481049close(objs[0]);1050close(objs[1]);1051close(objs[2]);1052close(objs[3]);10531054ret = wait_for_thread(thread, 200);1055EXPECT_EQ(0, ret);1056EXPECT_EQ(-1, thread_args.ret);1057EXPECT_EQ(ETIMEDOUT, thread_args.err);10581059close(fd);1060}10611062TEST(alert_any)1063{1064struct ntsync_event_args event_args = {0};1065struct ntsync_wait_args wait_args = {0};1066struct ntsync_sem_args sem_args = {0};1067__u32 index, count, signaled;1068struct wait_args thread_args;1069int objs[2], event, fd, ret;1070pthread_t thread;10711072fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);1073ASSERT_LE(0, fd);10741075sem_args.count = 0;1076sem_args.max = 2;1077objs[0] = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args);1078EXPECT_LE(0, objs[0]);10791080sem_args.count = 1;1081sem_args.max = 2;1082objs[1] = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args);1083EXPECT_LE(0, objs[1]);10841085event_args.manual = true;1086event_args.signaled = true;1087event = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args);1088EXPECT_LE(0, event);10891090ret = wait_any_alert(fd, 0, NULL, 123, event, &index);1091EXPECT_EQ(0, ret);1092EXPECT_EQ(0, index);10931094ret = ioctl(event, NTSYNC_IOC_EVENT_RESET, &signaled);1095EXPECT_EQ(0, ret);10961097ret = wait_any_alert(fd, 0, NULL, 123, event, &index);1098EXPECT_EQ(-1, ret);1099EXPECT_EQ(ETIMEDOUT, errno);11001101ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled);1102EXPECT_EQ(0, ret);11031104ret = wait_any_alert(fd, 2, objs, 123, event, &index);1105EXPECT_EQ(0, ret);1106EXPECT_EQ(1, index);11071108ret = wait_any_alert(fd, 2, objs, 123, event, &index);1109EXPECT_EQ(0, ret);1110EXPECT_EQ(2, index);11111112/* test wakeup via alert */11131114ret = ioctl(event, NTSYNC_IOC_EVENT_RESET, &signaled);1115EXPECT_EQ(0, ret);11161117wait_args.timeout = get_abs_timeout(1000);1118wait_args.objs = (uintptr_t)objs;1119wait_args.count = 2;1120wait_args.owner = 123;1121wait_args.index = 0xdeadbeef;1122wait_args.alert = event;1123thread_args.fd = fd;1124thread_args.args = &wait_args;1125thread_args.request = NTSYNC_IOC_WAIT_ANY;1126ret = pthread_create(&thread, NULL, wait_thread, &thread_args);1127EXPECT_EQ(0, ret);11281129ret = wait_for_thread(thread, 100);1130EXPECT_EQ(ETIMEDOUT, ret);11311132ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled);1133EXPECT_EQ(0, ret);11341135ret = wait_for_thread(thread, 100);1136EXPECT_EQ(0, ret);1137EXPECT_EQ(0, thread_args.ret);1138EXPECT_EQ(2, wait_args.index);11391140close(event);11411142/* test with an auto-reset event */11431144event_args.manual = false;1145event_args.signaled = true;1146event = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args);1147EXPECT_LE(0, event);11481149count = 1;1150ret = release_sem(objs[0], &count);1151EXPECT_EQ(0, ret);11521153ret = wait_any_alert(fd, 2, objs, 123, event, &index);1154EXPECT_EQ(0, ret);1155EXPECT_EQ(0, index);11561157ret = wait_any_alert(fd, 2, objs, 123, event, &index);1158EXPECT_EQ(0, ret);1159EXPECT_EQ(2, index);11601161ret = wait_any_alert(fd, 2, objs, 123, event, &index);1162EXPECT_EQ(-1, ret);1163EXPECT_EQ(ETIMEDOUT, errno);11641165close(event);11661167close(objs[0]);1168close(objs[1]);11691170close(fd);1171}11721173TEST(alert_all)1174{1175struct ntsync_event_args event_args = {0};1176struct ntsync_wait_args wait_args = {0};1177struct ntsync_sem_args sem_args = {0};1178struct wait_args thread_args;1179__u32 index, count, signaled;1180int objs[2], event, fd, ret;1181pthread_t thread;11821183fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);1184ASSERT_LE(0, fd);11851186sem_args.count = 2;1187sem_args.max = 2;1188objs[0] = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args);1189EXPECT_LE(0, objs[0]);11901191sem_args.count = 1;1192sem_args.max = 2;1193objs[1] = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args);1194EXPECT_LE(0, objs[1]);11951196event_args.manual = true;1197event_args.signaled = true;1198event = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args);1199EXPECT_LE(0, event);12001201ret = wait_all_alert(fd, 2, objs, 123, event, &index);1202EXPECT_EQ(0, ret);1203EXPECT_EQ(0, index);12041205ret = wait_all_alert(fd, 2, objs, 123, event, &index);1206EXPECT_EQ(0, ret);1207EXPECT_EQ(2, index);12081209/* test wakeup via alert */12101211ret = ioctl(event, NTSYNC_IOC_EVENT_RESET, &signaled);1212EXPECT_EQ(0, ret);12131214wait_args.timeout = get_abs_timeout(1000);1215wait_args.objs = (uintptr_t)objs;1216wait_args.count = 2;1217wait_args.owner = 123;1218wait_args.index = 0xdeadbeef;1219wait_args.alert = event;1220thread_args.fd = fd;1221thread_args.args = &wait_args;1222thread_args.request = NTSYNC_IOC_WAIT_ALL;1223ret = pthread_create(&thread, NULL, wait_thread, &thread_args);1224EXPECT_EQ(0, ret);12251226ret = wait_for_thread(thread, 100);1227EXPECT_EQ(ETIMEDOUT, ret);12281229ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled);1230EXPECT_EQ(0, ret);12311232ret = wait_for_thread(thread, 100);1233EXPECT_EQ(0, ret);1234EXPECT_EQ(0, thread_args.ret);1235EXPECT_EQ(2, wait_args.index);12361237close(event);12381239/* test with an auto-reset event */12401241event_args.manual = false;1242event_args.signaled = true;1243event = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args);1244EXPECT_LE(0, event);12451246count = 2;1247ret = release_sem(objs[1], &count);1248EXPECT_EQ(0, ret);12491250ret = wait_all_alert(fd, 2, objs, 123, event, &index);1251EXPECT_EQ(0, ret);1252EXPECT_EQ(0, index);12531254ret = wait_all_alert(fd, 2, objs, 123, event, &index);1255EXPECT_EQ(0, ret);1256EXPECT_EQ(2, index);12571258ret = wait_all_alert(fd, 2, objs, 123, event, &index);1259EXPECT_EQ(-1, ret);1260EXPECT_EQ(ETIMEDOUT, errno);12611262close(event);12631264close(objs[0]);1265close(objs[1]);12661267close(fd);1268}12691270#define STRESS_LOOPS 100001271#define STRESS_THREADS 412721273static unsigned int stress_counter;1274static int stress_device, stress_start_event, stress_mutex;12751276static void *stress_thread(void *arg)1277{1278struct ntsync_wait_args wait_args = {0};1279__u32 index, count, i;1280int ret;12811282wait_args.timeout = UINT64_MAX;1283wait_args.count = 1;1284wait_args.objs = (uintptr_t)&stress_start_event;1285wait_args.owner = gettid();1286wait_args.index = 0xdeadbeef;12871288ioctl(stress_device, NTSYNC_IOC_WAIT_ANY, &wait_args);12891290wait_args.objs = (uintptr_t)&stress_mutex;12911292for (i = 0; i < STRESS_LOOPS; ++i) {1293ioctl(stress_device, NTSYNC_IOC_WAIT_ANY, &wait_args);12941295++stress_counter;12961297unlock_mutex(stress_mutex, wait_args.owner, &count);1298}12991300return NULL;1301}13021303TEST(stress_wait)1304{1305struct ntsync_event_args event_args;1306struct ntsync_mutex_args mutex_args;1307pthread_t threads[STRESS_THREADS];1308__u32 signaled, i;1309int ret;13101311stress_device = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);1312ASSERT_LE(0, stress_device);13131314mutex_args.owner = 0;1315mutex_args.count = 0;1316stress_mutex = ioctl(stress_device, NTSYNC_IOC_CREATE_MUTEX, &mutex_args);1317EXPECT_LE(0, stress_mutex);13181319event_args.manual = 1;1320event_args.signaled = 0;1321stress_start_event = ioctl(stress_device, NTSYNC_IOC_CREATE_EVENT, &event_args);1322EXPECT_LE(0, stress_start_event);13231324for (i = 0; i < STRESS_THREADS; ++i)1325pthread_create(&threads[i], NULL, stress_thread, NULL);13261327ret = ioctl(stress_start_event, NTSYNC_IOC_EVENT_SET, &signaled);1328EXPECT_EQ(0, ret);13291330for (i = 0; i < STRESS_THREADS; ++i) {1331ret = pthread_join(threads[i], NULL);1332EXPECT_EQ(0, ret);1333}13341335EXPECT_EQ(STRESS_LOOPS * STRESS_THREADS, stress_counter);13361337close(stress_start_event);1338close(stress_mutex);1339close(stress_device);1340}13411342TEST_HARNESS_MAIN134313441345