New paste Repaste Download
/*
* LegacyClonk
*
* Copyright (c) 2020-2021, The LegacyClonk Team and contributors
*
* Distributed under the terms of the ISC license; see accompanying file
* "COPYING" for details.
*
* "Clonk" is a registered trademark of Matthes Bender, used with permission.
* See accompanying file "TRADEMARK" for details.
*
* To redistribute this file separately, substitute the full license texts
* for the above references.
*/
#include "C4NtSync.h"
#include <fcntl.h>
#include <asm/ioctl.h>
#include <linux/ntsync.h>
#include <sys/ioctl.h>
#include <unistd.h>
class C4NtSync
{
public:
C4NtSync()
{
fd = open("/dev/ntsync", O_CLOEXEC);
if (fd == -1)
{
throw std::runtime_error{"ntsync not available"};
}
}
~C4NtSync()
{
close(fd);
}
C4NtSync(const C4NtSync &) = delete;
C4NtSync &operator=(const C4NtSync &) = delete;
C4NtSync(C4NtSync &&) = delete;
C4NtSync &operator=(C4NtSync &&) = delete;
public:
template<typename... Args>
int IoControl(Args &&...args)
{
return ioctl(fd, std::forward<Args>(args)...);
}
int get() const noexcept { return fd; }
private:
int fd;
};
static C4NtSync NtSync;
static HANDLE FdToHandle(const int fd)
{
return reinterpret_cast<HANDLE>(static_cast<std::uintptr_t>(static_cast<unsigned int>(fd)));
}
static int HandleToFd(const HANDLE handle)
{
return static_cast<int>(static_cast<unsigned int>(reinterpret_cast<std::uintptr_t>(handle)));
}
static int ThrowIfFailed(const int result, const char *const message)
{
if (result == -1)
{
throw std::runtime_error{std::format("{} failed: {}", message, std::strerror(errno))};
}
return result;
}
HANDLE CreateEvent(std::nullptr_t, bool manualReset, bool initialState, std::nullptr_t)
{
const ntsync_event_args args{
.manual = manualReset,
.signaled = initialState
};
return FdToHandle(ThrowIfFailed(NtSync.IoControl(NTSYNC_IOC_CREATE_EVENT, &args), "CreateEvent"));
}
bool SetEvent(const HANDLE handle)
{
const int fd{HandleToFd(handle)};
__u32 previous;
return ioctl(fd, NTSYNC_IOC_EVENT_SET, &previous) == 0;
}
bool ResetEvent(const HANDLE handle)
{
const int fd{HandleToFd(handle)};
__u32 previous;
return ioctl(fd, NTSYNC_IOC_EVENT_RESET, &previous) == 0;
}
bool CloseHandle(const HANDLE handle)
{
return close(HandleToFd(handle)) == 0;
}
std::uint32_t WaitForSingleObject(const HANDLE handle, const std::uint32_t milliseconds)
{
return WaitForMultipleObjects(1, &handle, false, milliseconds);
}
#include <sys/eventfd.h>
std::uint32_t WaitForMultipleObjects(const std::uint32_t count, const HANDLE *const handles, const bool waitAll, const std::uint32_t milliseconds)
{
if (count > NTSYNC_MAX_WAIT_COUNT)
{
errno = EINVAL;
return WAIT_FAILED;
}
std::array<int, NTSYNC_MAX_WAIT_COUNT> objs{};
std::ranges::copy(std::span{handles, count} | std::views::transform(&HandleToFd), objs.begin());
std::uint64_t nanoseconds;
if (milliseconds == std::numeric_limits<std::uint32_t>::max())
{
nanoseconds = std::numeric_limits<__u64>::max();
}
else
{
nanoseconds = static_cast<__u64>(milliseconds) * 1'000'000;
}
int efd = eventfd(1, EFD_CLOEXEC);
ntsync_wait_args args{
.timeout = nanoseconds,
.objs = static_cast<__u64>(reinterpret_cast<std::uintptr_t>(objs.data())),
.count = count,
.owner = static_cast<__u32>(gettid()),
.alert = (__u32) efd
};
for (;;)
{
if (NtSync.IoControl(waitAll ? NTSYNC_IOC_WAIT_ALL : NTSYNC_IOC_WAIT_ANY, &args) == 0)
{
return WAIT_OBJECT_0 + args.index;
}
else
{
switch (errno)
{
case EINTR:
continue;
case ETIMEDOUT:
return WAIT_TIMEOUT;
case EOWNERDEAD:
return WAIT_ABANDONED_0 + args.index;
default:
return WAIT_FAILED;
}
}
}
}
Filename: None. Size: 4kb. View raw, , hex, or download this file.

This paste expires on 2025-04-26 13:36:29.720207. Pasted through web.