mirror of
https://github.com/mirkobrombin/raven.git
synced 2026-11-03 21:46:32 +00:00
142 lines
3.4 KiB
C++
142 lines
3.4 KiB
C++
#include "event.h"
|
|
#include "shared_file.h"
|
|
|
|
#include <new>
|
|
#include <stdexcept>
|
|
#include <sys/stat.h>
|
|
|
|
namespace raven {
|
|
|
|
std::optional<uint32_t> event_access(uint32_t requested)
|
|
{
|
|
if (requested & ~0xf21f0003U)
|
|
return std::nullopt;
|
|
uint32_t access = requested & 0x1f0003;
|
|
if (requested & 0x80000000U) access |= 0x120001;
|
|
if (requested & 0x40000000U) access |= 0x120002;
|
|
if (requested & 0x20000000U) access |= 0x120000;
|
|
if (requested & (0x10000000U | 0x02000000U)) access |= 0x1f0003;
|
|
return access;
|
|
}
|
|
|
|
struct EventObject::Shared {
|
|
std::atomic<uint32_t> signaled;
|
|
uint32_t type;
|
|
};
|
|
|
|
static_assert(std::atomic<uint32_t>::is_always_lock_free);
|
|
|
|
EventObject::EventObject(int descriptor) : type(0), local_signaled(false), descriptor(descriptor)
|
|
{
|
|
try {
|
|
struct stat information{};
|
|
if (descriptor < 0 || ::fstat(descriptor, &information) || information.st_size != sizeof(Shared))
|
|
throw std::runtime_error("invalid event storage");
|
|
void *mapped = ::mmap(nullptr, sizeof(Shared), PROT_READ | PROT_WRITE, MAP_SHARED, descriptor, 0);
|
|
if (mapped == MAP_FAILED)
|
|
throw std::runtime_error("cannot map event storage");
|
|
shared = static_cast<Shared *>(mapped);
|
|
if (shared->type > 1)
|
|
throw std::runtime_error("invalid event type");
|
|
type = shared->type;
|
|
listen_shared_changes();
|
|
++shared_object_count;
|
|
} catch (...) {
|
|
if (shared) ::munmap(shared, sizeof(Shared));
|
|
if (descriptor >= 0) ::close(descriptor);
|
|
throw;
|
|
}
|
|
}
|
|
|
|
EventObject::~EventObject()
|
|
{
|
|
if (shared) {
|
|
::munmap(shared, sizeof(Shared));
|
|
--shared_object_count;
|
|
}
|
|
if (descriptor >= 0) ::close(descriptor);
|
|
}
|
|
|
|
bool EventObject::describe(InheritedHandle &record) const
|
|
{
|
|
std::lock_guard lock(mutex);
|
|
if (!shared) {
|
|
const int created = ::memfd_create("raven-event", MFD_CLOEXEC | MFD_ALLOW_SEALING);
|
|
if (created < 0)
|
|
return false;
|
|
if (::ftruncate(created, sizeof(Shared)) ||
|
|
::fcntl(created, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_SEAL)) {
|
|
::close(created);
|
|
return false;
|
|
}
|
|
void *mapped = ::mmap(nullptr, sizeof(Shared), PROT_READ | PROT_WRITE, MAP_SHARED, created, 0);
|
|
if (mapped == MAP_FAILED) {
|
|
::close(created);
|
|
return false;
|
|
}
|
|
shared = new (mapped) Shared{{uint32_t(local_signaled)}, type};
|
|
descriptor = created;
|
|
listen_shared_changes();
|
|
++shared_object_count;
|
|
changed.notify_all();
|
|
}
|
|
record.kind = "event";
|
|
record.descriptor = descriptor;
|
|
return true;
|
|
}
|
|
|
|
bool EventObject::is_set() const
|
|
{
|
|
return shared ? shared->signaled.load() != 0 : local_signaled;
|
|
}
|
|
|
|
bool EventObject::take()
|
|
{
|
|
if (type == 0)
|
|
return is_set();
|
|
if (shared)
|
|
return shared->signaled.exchange(0) != 0;
|
|
const bool previous = local_signaled;
|
|
local_signaled = false;
|
|
return previous;
|
|
}
|
|
|
|
int EventObject::signaled(uint32_t) const
|
|
{
|
|
std::lock_guard lock(mutex);
|
|
return is_set();
|
|
}
|
|
|
|
void EventObject::consume(uint32_t thread)
|
|
{
|
|
try_consume(thread);
|
|
}
|
|
|
|
bool EventObject::try_consume(uint32_t)
|
|
{
|
|
std::lock_guard lock(mutex);
|
|
return take();
|
|
}
|
|
|
|
int EventObject::set_state(bool signaled)
|
|
{
|
|
std::lock_guard lock(mutex);
|
|
const bool previous = shared ? shared->signaled.exchange(uint32_t(signaled)) != 0 : local_signaled;
|
|
local_signaled = signaled;
|
|
if (signaled) {
|
|
if (type == 0) {
|
|
for (const auto &waiter : waiters) waiter->ready = true;
|
|
waiters.clear();
|
|
} else if (!waiters.empty() && take()) {
|
|
waiters.front()->ready = true;
|
|
waiters.pop_front();
|
|
}
|
|
changed.notify_all();
|
|
}
|
|
if (shared)
|
|
announce_shared_change();
|
|
return previous;
|
|
}
|
|
|
|
}
|