Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/tools/testing/selftests/drivers/ntsync/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 31 kB image not shown  

Quelle  ntsync.c   Sprache: C

 
// 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 <fcntl.h>
#include <time.h>
#include <pthread.h>
#include <linux/ntsync.h>
#include "../../kselftest_harness.h"

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);

 close(event);

 close(fd);
}

TEST(test_wait_any)
{
 int objs[NTSYNC_MAX_WAIT_COUNT + 1], fd, ret;
 struct ntsync_mutex_args mutex_args = {0};
 struct ntsync_sem_args sem_args = {0};
 __u32 owner, index, count, i;
 struct timespec timeout;

 clock_gettime(CLOCK_MONOTONIC, &timeout);

 fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);
 ASSERT_LE(0, fd);

 sem_args.count = 2;
 sem_args.max = 3;
 objs[0] = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args);
 EXPECT_LE(0, objs[0]);

 mutex_args.owner = 0;
 mutex_args.count = 0;
 objs[1] = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args);
 EXPECT_LE(0, objs[1]);

 ret = wait_any(fd, 2, objs, 123, &index);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, index);
 check_sem_state(objs[0], 1, 3);
 check_mutex_state(objs[1], 0, 0);

 ret = wait_any(fd, 2, objs, 123, &index);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, index);
 check_sem_state(objs[0], 0, 3);
 check_mutex_state(objs[1], 0, 0);

 ret = wait_any(fd, 2, objs, 123, &index);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(1, index);
 check_sem_state(objs[0], 0, 3);
 check_mutex_state(objs[1], 1, 123);

 count = 1;
 ret = release_sem(objs[0], &count);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, count);

 ret = wait_any(fd, 2, objs, 123, &index);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, index);
 check_sem_state(objs[0], 0, 3);
 check_mutex_state(objs[1], 1, 123);

 ret = wait_any(fd, 2, objs, 123, &index);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(1, index);
 check_sem_state(objs[0], 0, 3);
 check_mutex_state(objs[1], 2, 123);

 ret = wait_any(fd, 2, objs, 456, &index);
 EXPECT_EQ(-1, ret);
 EXPECT_EQ(ETIMEDOUT, errno);

 owner = 123;
 ret = ioctl(objs[1], NTSYNC_IOC_MUTEX_KILL, &owner);
 EXPECT_EQ(0, ret);

 ret = wait_any(fd, 2, objs, 456, &index);
 EXPECT_EQ(-1, ret);
 EXPECT_EQ(EOWNERDEAD, errno);
 EXPECT_EQ(1, index);

 ret = wait_any(fd, 2, objs, 456, &index);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(1, index);

 close(objs[1]);

 /* test waiting on the same object twice */

 count = 2;
 ret = release_sem(objs[0], &count);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, count);

 objs[1] = objs[0];
 ret = wait_any(fd, 2, objs, 456, &index);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, index);
 check_sem_state(objs[0], 1, 3);

 ret = wait_any(fd, 0, NULL, 456, &index);
 EXPECT_EQ(-1, ret);
 EXPECT_EQ(ETIMEDOUT, errno);

 for (i = 1; i < NTSYNC_MAX_WAIT_COUNT + 1; ++i)
  objs[i] = objs[0];

 ret = wait_any(fd, NTSYNC_MAX_WAIT_COUNT, objs, 123, &index);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, index);

 ret = wait_any(fd, NTSYNC_MAX_WAIT_COUNT + 1, objs, 123, &index);
 EXPECT_EQ(-1, ret);
 EXPECT_EQ(EINVAL, errno);

 ret = wait_any(fd, -1, objs, 123, &index);
 EXPECT_EQ(-1, ret);
 EXPECT_EQ(EINVAL, errno);

 close(objs[0]);

 close(fd);
}

TEST(test_wait_all)
{
 struct ntsync_event_args event_args = {0};
 struct ntsync_mutex_args mutex_args = {0};
 struct ntsync_sem_args sem_args = {0};
 __u32 owner, index, count;
 int objs[2], fd, ret;

 fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);
 ASSERT_LE(0, fd);

 sem_args.count = 2;
 sem_args.max = 3;
 objs[0] = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args);
 EXPECT_LE(0, objs[0]);

 mutex_args.owner = 0;
 mutex_args.count = 0;
 objs[1] = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args);
 EXPECT_LE(0, objs[1]);

 ret = wait_all(fd, 2, objs, 123, &index);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, index);
 check_sem_state(objs[0], 1, 3);
 check_mutex_state(objs[1], 1, 123);

 ret = wait_all(fd, 2, objs, 456, &index);
 EXPECT_EQ(-1, ret);
 EXPECT_EQ(ETIMEDOUT, errno);
 check_sem_state(objs[0], 1, 3);
 check_mutex_state(objs[1], 1, 123);

 ret = wait_all(fd, 2, objs, 123, &index);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, index);
 check_sem_state(objs[0], 0, 3);
 check_mutex_state(objs[1], 2, 123);

 ret = wait_all(fd, 2, objs, 123, &index);
 EXPECT_EQ(-1, ret);
 EXPECT_EQ(ETIMEDOUT, errno);
 check_sem_state(objs[0], 0, 3);
 check_mutex_state(objs[1], 2, 123);

 count = 3;
 ret = release_sem(objs[0], &count);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, count);

 ret = wait_all(fd, 2, objs, 123, &index);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, index);
 check_sem_state(objs[0], 2, 3);
 check_mutex_state(objs[1], 3, 123);

 owner = 123;
 ret = ioctl(objs[1], NTSYNC_IOC_MUTEX_KILL, &owner);
 EXPECT_EQ(0, ret);

 ret = wait_all(fd, 2, objs, 123, &index);
 EXPECT_EQ(-1, ret);
 EXPECT_EQ(EOWNERDEAD, errno);
 check_sem_state(objs[0], 1, 3);
 check_mutex_state(objs[1], 1, 123);

 close(objs[1]);

 event_args.manual = true;
 event_args.signaled = true;
 objs[1] = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args);
 EXPECT_LE(0, objs[1]);

 ret = wait_all(fd, 2, objs, 123, &index);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, index);
 check_sem_state(objs[0], 0, 3);
 check_event_state(objs[1], 1, 1);

 close(objs[1]);

 /* test waiting on the same object twice */
 objs[1] = objs[0];
 ret = wait_all(fd, 2, objs, 123, &index);
 EXPECT_EQ(-1, ret);
 EXPECT_EQ(EINVAL, errno);

 close(objs[0]);

 close(fd);
}

struct wake_args {
 int fd;
 int obj;
};

struct wait_args {
 int fd;
 unsigned long request;
 struct ntsync_wait_args *args;
 int ret;
 int err;
};

static void *wait_thread(void *arg)
{
 struct wait_args *args = arg;

 args->ret = ioctl(args->fd, args->request, args->args);
 args->err = errno;
 return NULL;
}

static __u64 get_abs_timeout(unsigned int ms)
{
 struct timespec timeout;
 clock_gettime(CLOCK_MONOTONIC, &timeout);
 return (timeout.tv_sec * 1000000000) + timeout.tv_nsec + (ms * 1000000);
}

static int wait_for_thread(pthread_t thread, unsigned int ms)
{
 struct timespec timeout;

 clock_gettime(CLOCK_REALTIME, &timeout);
 timeout.tv_nsec += ms * 1000000;
 timeout.tv_sec += (timeout.tv_nsec / 1000000000);
 timeout.tv_nsec %= 1000000000;
 return pthread_timedjoin_np(thread, NULL, &timeout);
}

TEST(wake_any)
{
 struct ntsync_event_args event_args = {0};
 struct ntsync_mutex_args mutex_args = {0};
 struct ntsync_wait_args wait_args = {0};
 struct ntsync_sem_args sem_args = {0};
 struct wait_args thread_args;
 __u32 count, index, signaled;
 int objs[2], fd, ret;
 pthread_t thread;

 fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);
 ASSERT_LE(0, fd);

 sem_args.count = 0;
 sem_args.max = 3;
 objs[0] = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args);
 EXPECT_LE(0, objs[0]);

 mutex_args.owner = 123;
 mutex_args.count = 1;
 objs[1] = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args);
 EXPECT_LE(0, objs[1]);

 /* test waking the semaphore */

 wait_args.timeout = get_abs_timeout(1000);
 wait_args.objs = (uintptr_t)objs;
 wait_args.count = 2;
 wait_args.owner = 456;
 wait_args.index = 0xdeadbeef;
 thread_args.fd = fd;
 thread_args.args = &wait_args;
 thread_args.request = NTSYNC_IOC_WAIT_ANY;
 ret = pthread_create(&thread, NULL, wait_thread, &thread_args);
 EXPECT_EQ(0, ret);

 ret = wait_for_thread(thread, 100);
 EXPECT_EQ(ETIMEDOUT, ret);

 count = 1;
 ret = release_sem(objs[0], &count);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, count);
 check_sem_state(objs[0], 0, 3);

 ret = wait_for_thread(thread, 100);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, thread_args.ret);
 EXPECT_EQ(0, wait_args.index);

 /* test waking the mutex */

 /* first grab it again for owner 123 */
 ret = wait_any(fd, 1, &objs[1], 123, &index);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, index);

 wait_args.timeout = get_abs_timeout(1000);
 wait_args.owner = 456;
 ret = pthread_create(&thread, NULL, wait_thread, &thread_args);
 EXPECT_EQ(0, ret);

 ret = wait_for_thread(thread, 100);
 EXPECT_EQ(ETIMEDOUT, ret);

 ret = unlock_mutex(objs[1], 123, &count);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(2, count);

 ret = pthread_tryjoin_np(thread, NULL);
 EXPECT_EQ(EBUSY, ret);

 ret = unlock_mutex(objs[1], 123, &count);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(1, mutex_args.count);
 check_mutex_state(objs[1], 1, 456);

 ret = wait_for_thread(thread, 100);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, thread_args.ret);
 EXPECT_EQ(1, wait_args.index);

 close(objs[1]);

 /* test waking events */

 event_args.manual = false;
 event_args.signaled = false;
 objs[1] = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args);
 EXPECT_LE(0, objs[1]);

 wait_args.timeout = get_abs_timeout(1000);
 ret = pthread_create(&thread, NULL, wait_thread, &thread_args);
 EXPECT_EQ(0, ret);

 ret = wait_for_thread(thread, 100);
 EXPECT_EQ(ETIMEDOUT, ret);

 ret = ioctl(objs[1], NTSYNC_IOC_EVENT_SET, &signaled);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, signaled);
 check_event_state(objs[1], 0, 0);

 ret = wait_for_thread(thread, 100);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, thread_args.ret);
 EXPECT_EQ(1, wait_args.index);

 wait_args.timeout = get_abs_timeout(1000);
 ret = pthread_create(&thread, NULL, wait_thread, &thread_args);
 EXPECT_EQ(0, ret);

 ret = wait_for_thread(thread, 100);
 EXPECT_EQ(ETIMEDOUT, ret);

 ret = ioctl(objs[1], NTSYNC_IOC_EVENT_PULSE, &signaled);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, signaled);
 check_event_state(objs[1], 0, 0);

 ret = wait_for_thread(thread, 100);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, thread_args.ret);
 EXPECT_EQ(1, wait_args.index);

 close(objs[1]);

 event_args.manual = true;
 event_args.signaled = false;
 objs[1] = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args);
 EXPECT_LE(0, objs[1]);

 wait_args.timeout = get_abs_timeout(1000);
 ret = pthread_create(&thread, NULL, wait_thread, &thread_args);
 EXPECT_EQ(0, ret);

 ret = wait_for_thread(thread, 100);
 EXPECT_EQ(ETIMEDOUT, ret);

 ret = ioctl(objs[1], NTSYNC_IOC_EVENT_SET, &signaled);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, signaled);
 check_event_state(objs[1], 1, 1);

 ret = wait_for_thread(thread, 100);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, thread_args.ret);
 EXPECT_EQ(1, wait_args.index);

 ret = ioctl(objs[1], NTSYNC_IOC_EVENT_RESET, &signaled);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(1, signaled);

 wait_args.timeout = get_abs_timeout(1000);
 ret = pthread_create(&thread, NULL, wait_thread, &thread_args);
 EXPECT_EQ(0, ret);

 ret = wait_for_thread(thread, 100);
 EXPECT_EQ(ETIMEDOUT, ret);

 ret = ioctl(objs[1], NTSYNC_IOC_EVENT_PULSE, &signaled);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, signaled);
 check_event_state(objs[1], 0, 1);

 ret = wait_for_thread(thread, 100);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, thread_args.ret);
 EXPECT_EQ(1, wait_args.index);

 /* delete an object while it's being waited on */

 wait_args.timeout = get_abs_timeout(200);
 wait_args.owner = 123;
 ret = pthread_create(&thread, NULL, wait_thread, &thread_args);
 EXPECT_EQ(0, ret);

 ret = wait_for_thread(thread, 100);
 EXPECT_EQ(ETIMEDOUT, ret);

 close(objs[0]);
 close(objs[1]);

 ret = wait_for_thread(thread, 200);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(-1, thread_args.ret);
 EXPECT_EQ(ETIMEDOUT, thread_args.err);

 close(fd);
}

TEST(wake_all)
{
 struct ntsync_event_args manual_event_args = {0};
 struct ntsync_event_args auto_event_args = {0};
 struct ntsync_mutex_args mutex_args = {0};
 struct ntsync_wait_args wait_args = {0};
 struct ntsync_sem_args sem_args = {0};
 struct wait_args thread_args;
 __u32 count, index, signaled;
 int objs[4], fd, ret;
 pthread_t thread;

 fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);
 ASSERT_LE(0, fd);

 sem_args.count = 0;
 sem_args.max = 3;
 objs[0] = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args);
 EXPECT_LE(0, objs[0]);

 mutex_args.owner = 123;
 mutex_args.count = 1;
 objs[1] = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args);
 EXPECT_LE(0, objs[1]);

 manual_event_args.manual = true;
 manual_event_args.signaled = true;
 objs[2] = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &manual_event_args);
 EXPECT_LE(0, objs[2]);

 auto_event_args.manual = false;
 auto_event_args.signaled = true;
 objs[3] = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &auto_event_args);
 EXPECT_EQ(0, objs[3]);

 wait_args.timeout = get_abs_timeout(1000);
 wait_args.objs = (uintptr_t)objs;
 wait_args.count = 4;
 wait_args.owner = 456;
 thread_args.fd = fd;
 thread_args.args = &wait_args;
 thread_args.request = NTSYNC_IOC_WAIT_ALL;
 ret = pthread_create(&thread, NULL, wait_thread, &thread_args);
 EXPECT_EQ(0, ret);

 ret = wait_for_thread(thread, 100);
 EXPECT_EQ(ETIMEDOUT, ret);

 count = 1;
 ret = release_sem(objs[0], &count);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, count);

 ret = pthread_tryjoin_np(thread, NULL);
 EXPECT_EQ(EBUSY, ret);

 check_sem_state(objs[0], 1, 3);

 ret = wait_any(fd, 1, &objs[0], 123, &index);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, index);

 ret = unlock_mutex(objs[1], 123, &count);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(1, count);

 ret = pthread_tryjoin_np(thread, NULL);
 EXPECT_EQ(EBUSY, ret);

 check_mutex_state(objs[1], 0, 0);

 ret = ioctl(objs[2], NTSYNC_IOC_EVENT_RESET, &signaled);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(1, signaled);

 count = 2;
 ret = release_sem(objs[0], &count);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, count);
 check_sem_state(objs[0], 2, 3);

 ret = ioctl(objs[3], NTSYNC_IOC_EVENT_RESET, &signaled);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(1, signaled);

 ret = ioctl(objs[2], NTSYNC_IOC_EVENT_SET, &signaled);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, signaled);

 ret = ioctl(objs[3], NTSYNC_IOC_EVENT_SET, &signaled);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, signaled);

 check_sem_state(objs[0], 1, 3);
 check_mutex_state(objs[1], 1, 456);
 check_event_state(objs[2], 1, 1);
 check_event_state(objs[3], 0, 0);

 ret = wait_for_thread(thread, 100);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, thread_args.ret);

 /* delete an object while it's being waited on */

 wait_args.timeout = get_abs_timeout(200);
 wait_args.owner = 123;
 ret = pthread_create(&thread, NULL, wait_thread, &thread_args);
 EXPECT_EQ(0, ret);

 ret = wait_for_thread(thread, 100);
 EXPECT_EQ(ETIMEDOUT, ret);

 close(objs[0]);
 close(objs[1]);
 close(objs[2]);
 close(objs[3]);

 ret = wait_for_thread(thread, 200);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(-1, thread_args.ret);
 EXPECT_EQ(ETIMEDOUT, thread_args.err);

 close(fd);
}

TEST(alert_any)
{
 struct ntsync_event_args event_args = {0};
 struct ntsync_wait_args wait_args = {0};
 struct ntsync_sem_args sem_args = {0};
 __u32 index, count, signaled;
 struct wait_args thread_args;
 int objs[2], event, fd, ret;
 pthread_t thread;

 fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);
 ASSERT_LE(0, fd);

 sem_args.count = 0;
 sem_args.max = 2;
 objs[0] = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args);
 EXPECT_LE(0, objs[0]);

 sem_args.count = 1;
 sem_args.max = 2;
 objs[1] = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args);
 EXPECT_LE(0, objs[1]);

 event_args.manual = true;
 event_args.signaled = true;
 event = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args);
 EXPECT_LE(0, event);

 ret = wait_any_alert(fd, 0, NULL, 123, event, &index);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, index);

 ret = ioctl(event, NTSYNC_IOC_EVENT_RESET, &signaled);
 EXPECT_EQ(0, ret);

 ret = wait_any_alert(fd, 0, NULL, 123, event, &index);
 EXPECT_EQ(-1, ret);
 EXPECT_EQ(ETIMEDOUT, errno);

 ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled);
 EXPECT_EQ(0, ret);

 ret = wait_any_alert(fd, 2, objs, 123, event, &index);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(1, index);

 ret = wait_any_alert(fd, 2, objs, 123, event, &index);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(2, index);

 /* test wakeup via alert */

 ret = ioctl(event, NTSYNC_IOC_EVENT_RESET, &signaled);
 EXPECT_EQ(0, ret);

 wait_args.timeout = get_abs_timeout(1000);
 wait_args.objs = (uintptr_t)objs;
 wait_args.count = 2;
 wait_args.owner = 123;
 wait_args.index = 0xdeadbeef;
 wait_args.alert = event;
 thread_args.fd = fd;
 thread_args.args = &wait_args;
 thread_args.request = NTSYNC_IOC_WAIT_ANY;
 ret = pthread_create(&thread, NULL, wait_thread, &thread_args);
 EXPECT_EQ(0, ret);

 ret = wait_for_thread(thread, 100);
 EXPECT_EQ(ETIMEDOUT, ret);

 ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled);
 EXPECT_EQ(0, ret);

 ret = wait_for_thread(thread, 100);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, thread_args.ret);
 EXPECT_EQ(2, wait_args.index);

 close(event);

 /* test with an auto-reset event */

 event_args.manual = false;
 event_args.signaled = true;
 event = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args);
 EXPECT_LE(0, event);

 count = 1;
 ret = release_sem(objs[0], &count);
 EXPECT_EQ(0, ret);

 ret = wait_any_alert(fd, 2, objs, 123, event, &index);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, index);

 ret = wait_any_alert(fd, 2, objs, 123, event, &index);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(2, index);

 ret = wait_any_alert(fd, 2, objs, 123, event, &index);
 EXPECT_EQ(-1, ret);
 EXPECT_EQ(ETIMEDOUT, errno);

 close(event);

 close(objs[0]);
 close(objs[1]);

 close(fd);
}

TEST(alert_all)
{
 struct ntsync_event_args event_args = {0};
 struct ntsync_wait_args wait_args = {0};
 struct ntsync_sem_args sem_args = {0};
 struct wait_args thread_args;
 __u32 index, count, signaled;
 int objs[2], event, fd, ret;
 pthread_t thread;

 fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);
 ASSERT_LE(0, fd);

 sem_args.count = 2;
 sem_args.max = 2;
 objs[0] = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args);
 EXPECT_LE(0, objs[0]);

 sem_args.count = 1;
 sem_args.max = 2;
 objs[1] = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args);
 EXPECT_LE(0, objs[1]);

 event_args.manual = true;
 event_args.signaled = true;
 event = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args);
 EXPECT_LE(0, event);

 ret = wait_all_alert(fd, 2, objs, 123, event, &index);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, index);

 ret = wait_all_alert(fd, 2, objs, 123, event, &index);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(2, index);

 /* test wakeup via alert */

 ret = ioctl(event, NTSYNC_IOC_EVENT_RESET, &signaled);
 EXPECT_EQ(0, ret);

 wait_args.timeout = get_abs_timeout(1000);
 wait_args.objs = (uintptr_t)objs;
 wait_args.count = 2;
 wait_args.owner = 123;
 wait_args.index = 0xdeadbeef;
 wait_args.alert = event;
 thread_args.fd = fd;
 thread_args.args = &wait_args;
 thread_args.request = NTSYNC_IOC_WAIT_ALL;
 ret = pthread_create(&thread, NULL, wait_thread, &thread_args);
 EXPECT_EQ(0, ret);

 ret = wait_for_thread(thread, 100);
 EXPECT_EQ(ETIMEDOUT, ret);

 ret = ioctl(event, NTSYNC_IOC_EVENT_SET, &signaled);
 EXPECT_EQ(0, ret);

 ret = wait_for_thread(thread, 100);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, thread_args.ret);
 EXPECT_EQ(2, wait_args.index);

 close(event);

 /* test with an auto-reset event */

 event_args.manual = false;
 event_args.signaled = true;
 event = ioctl(fd, NTSYNC_IOC_CREATE_EVENT, &event_args);
 EXPECT_LE(0, event);

 count = 2;
 ret = release_sem(objs[1], &count);
 EXPECT_EQ(0, ret);

 ret = wait_all_alert(fd, 2, objs, 123, event, &index);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(0, index);

 ret = wait_all_alert(fd, 2, objs, 123, event, &index);
 EXPECT_EQ(0, ret);
 EXPECT_EQ(2, index);

 ret = wait_all_alert(fd, 2, objs, 123, event, &index);
 EXPECT_EQ(-1, ret);
 EXPECT_EQ(ETIMEDOUT, errno);

 close(event);

 close(objs[0]);
 close(objs[1]);

 close(fd);
}

#define STRESS_LOOPS 10000
#define STRESS_THREADS 4

static unsigned int stress_counter;
static int stress_device, stress_start_event, stress_mutex;

static void *stress_thread(void *arg)
{
 struct ntsync_wait_args wait_args = {0};
 __u32 index, count, i;
 int ret;

 wait_args.timeout = UINT64_MAX;
 wait_args.count = 1;
 wait_args.objs = (uintptr_t)&stress_start_event;
 wait_args.owner = gettid();
 wait_args.index = 0xdeadbeef;

 ioctl(stress_device, NTSYNC_IOC_WAIT_ANY, &wait_args);

 wait_args.objs = (uintptr_t)&stress_mutex;

 for (i = 0; i < STRESS_LOOPS; ++i) {
  ioctl(stress_device, NTSYNC_IOC_WAIT_ANY, &wait_args);

  ++stress_counter;

  unlock_mutex(stress_mutex, wait_args.owner, &count);
 }

 return NULL;
}

TEST(stress_wait)
{
 struct ntsync_event_args event_args;
 struct ntsync_mutex_args mutex_args;
 pthread_t threads[STRESS_THREADS];
 __u32 signaled, i;
 int ret;

 stress_device = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);
 ASSERT_LE(0, stress_device);

 mutex_args.owner = 0;
 mutex_args.count = 0;
 stress_mutex = ioctl(stress_device, NTSYNC_IOC_CREATE_MUTEX, &mutex_args);
 EXPECT_LE(0, stress_mutex);

 event_args.manual = 1;
 event_args.signaled = 0;
 stress_start_event = ioctl(stress_device, NTSYNC_IOC_CREATE_EVENT, &event_args);
 EXPECT_LE(0, stress_start_event);

 for (i = 0; i < STRESS_THREADS; ++i)
  pthread_create(&threads[i], NULL, stress_thread, NULL);

 ret = ioctl(stress_start_event, NTSYNC_IOC_EVENT_SET, &signaled);
 EXPECT_EQ(0, ret);

 for (i = 0; i < STRESS_THREADS; ++i) {
  ret = pthread_join(threads[i], NULL);
  EXPECT_EQ(0, ret);
 }

 EXPECT_EQ(STRESS_LOOPS * STRESS_THREADS, stress_counter);

 close(stress_start_event);
 close(stress_mutex);
 close(stress_device);
}

TEST_HARNESS_MAIN

Messung V0.5
C=99 H=96 G=97

¤ Dauer der Verarbeitung: 0.21 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.