2#include "mqueue-state.h"
3#include "pedigree/kernel/LockGuard.h"
4#include "pedigree/kernel/process/Scheduler.h"
5#include "pedigree/kernel/processor/Processor.h"
6#include "pedigree/kernel/processor/ProcessorInformation.h"
7#include "pedigree/kernel/syscallError.h"
8#include "pedigree/kernel/utilities/utility.h"
13#include "modules/subsys/posix/PosixSubsystem.h"
14#include "mqueue-netlink.h"
17bool copyDeadline(
const LinuxMqTimespec* user, Time::Timestamp& deadline) {
18 deadline = Time::Infinity;
24 SYSCALL_ERROR(BadAddress);
27 if (value.seconds < 0 || value.nanoseconds < 0 || value.nanoseconds >= 1000000000) {
28 SYSCALL_ERROR(InvalidArgument);
31 const uint64_t seconds =
static_cast<uint64_t
>(value.seconds);
32 const uint64_t nanos =
static_cast<uint64_t
>(value.nanoseconds);
33 deadline = seconds > (Time::Infinity - 1 - nanos) / Time::Multiplier::Second
35 : seconds * Time::Multiplier::Second + nanos;
41 SYSCALL_ERROR(NoMoreProcesses);
44 Time::Timestamp remaining = Time::Infinity;
45 if (deadline != Time::Infinity) {
46 const Time::Timestamp now = Time::getTimeNanoseconds();
47 if (deadline <= now) {
48 SYSCALL_ERROR(TimedOut);
51 remaining = deadline - now;
53 ConditionVariable::Error error = ConditionVariable::NoError;
54 if (condition.
wait(lock, remaining, error) || error == ConditionVariable::TimedOut) {
57 SYSCALL_ERROR(Interrupted);
62MqueueState::MqueueState(
const String& queueName,
size_t maxMessages,
size_t messageSize,
63 int64_t owner, int64_t group,
unsigned permissions)
68 capacity(maxMessages),
77 messages(
UniqueArray<Message>::allocate(maxMessages)),
78 storage(
UniqueArray<uint8_t>::allocate(maxMessages * messageSize)),
81 for (
size_t n = 0; n < capacity; ++n) {
82 messages.get()[n].next = n + 1 == capacity ? -1 :
static_cast<int>(n + 1);
86PosixMessageQueue::PosixMessageQueue(
const String& name,
size_t capacity,
size_t size, int64_t uid,
87 int64_t gid,
unsigned mode)
88 : m_State(new
MqueueState(name, capacity, size, uid, gid, mode)) {}
90PosixMessageQueue::~PosixMessageQueue() {
93 for (
auto it = g_Mqueues.begin(); it != g_Mqueues.end(); ++it) {
100 m_State->notification.complete(
true);
105const String& PosixMessageQueue::name()
const {
106 return m_State->name;
109bool PosixMessageQueue::mayOpen(
Process* process,
int flags)
const {
110 const auto& state = *m_State;
111 const int64_t uid = process->getEffectiveUserId();
115 unsigned mode = state.mode;
116 bool group = state.gid == process->getEffectiveGroupId();
119 process->getSupplementalGroupIds(groups);
120 for (
size_t n = 0; n < groups.
count(); ++n) {
121 group |= groups[n] == state.gid;
124 mode >>= uid == state.uid ? 6 : group ? 3 : 0;
125 const int access = flags & O_ACCMODE;
126 return (access == O_WRONLY || (mode & 4)) && (access == O_RDONLY || (mode & 2));
129bool PosixMessageQueue::mayUnlink(
Process* process)
const {
130 const int64_t uid = process->getEffectiveUserId();
131 return uid == 0 || uid == m_State->uid;
134int PosixMessageQueue::send(
const char* data,
size_t length,
unsigned priority,
bool nonblock,
136 auto& state = *m_State;
137 if (priority >= 32768) {
138 SYSCALL_ERROR(InvalidArgument);
141 if (length > state.size) {
142 syscallError(EMSGSIZE);
145 Time::Timestamp deadline;
146 if (!copyDeadline(timeout, deadline)) {
151 SYSCALL_ERROR(BadAddress);
154 state.lock.acquire();
155 while (state.count == state.capacity) {
156 if (!waitQueue(state.writers, state.lock, deadline, nonblock)) {
157 state.lock.release();
161 const bool wasEmpty = !state.count;
162 const int slot = state.free;
163 auto&
message = state.messages.get()[slot];
167 MemoryCopy(state.storage.get() + slot * state.size, copy.get(), length);
168 int* insertion = &state.head;
169 while (*insertion >= 0 && state.messages.get()[*insertion].priority >= priority) {
170 insertion = &state.messages.get()[*insertion].next;
176 ++state.generations.read;
177 if (!state.receiverCount) {
178 state.notification.complete(
false);
181 state.lock.release();
182 state.readers.broadcast();
187int PosixMessageQueue::receive(
char* data,
size_t length,
unsigned* priority,
bool nonblock,
189 auto& state = *m_State;
190 if (length < state.size) {
191 syscallError(EMSGSIZE);
194 Time::Timestamp deadline;
195 if (!copyDeadline(timeout, deadline)) {
198 state.lock.acquire();
199 while (!state.count) {
200 ++state.receiverCount;
201 const bool resumed = waitQueue(state.readers, state.lock, deadline, nonblock);
202 --state.receiverCount;
204 state.lock.release();
208 const int slot = state.head;
209 auto&
message = state.messages.get()[slot];
210 const size_t received =
message.length;
215 state.lock.release();
216 SYSCALL_ERROR(BadAddress);
222 if (state.count-- == state.capacity) {
223 ++state.generations.write;
225 state.lock.release();
226 state.writers.broadcast();
228 return static_cast<int>(received);
236 SYSCALL_ERROR(BadAddress);
239 if (attr.flags & ~
static_cast<int64_t
>(O_NONBLOCK)) {
240 SYSCALL_ERROR(InvalidArgument);
244 auto& state = *m_State;
247 static_cast<int64_t
>(state.capacity),
248 static_cast<int64_t
>(state.size),
249 static_cast<int64_t
>(state.count),
252 SYSCALL_ERROR(BadAddress);
256 if (attr.flags & O_NONBLOCK) {
265ReadyMask PosixMessageQueue::queryReady() {
267 return (m_State->count ? ReadyRead : ReadyNone) |
268 (m_State->count < m_State->capacity ? ReadyWrite : ReadyNone);
273 return m_State->generations;
276void MqueueNotification::complete(
bool removed) {
282 }
else if (!removed && event.notify == 0) {
289 auto* subsystem =
static_cast<PosixSubsystem*
>(target->getSubsystem());
290 subsystem->
queueSignalDelivery(thread.get(),
event.signal,
nullptr, -3,
true,
event.value);
303 SYSCALL_ERROR(BadAddress);
306 const auto&
event = notification.event;
307 if (event.notify < 0 || event.notify > 2 ||
308 (event.notify == 0 && (event.signal <= 0 ||
static_cast<size_t>(event.signal) >
309 PosixSubsystem::MaximumSupportedSignal))) {
310 SYSCALL_ERROR(InvalidArgument);
313 if (event.notify == 2) {
315 if (!acquireDescriptor(event.signal, socket) || !socket->
networkImpl ||
317 SYSCALL_ERROR(BadFileDescriptor);
321 reinterpret_cast<const void*
>(event.value), 32)) {
322 SYSCALL_ERROR(BadAddress);
327 notification.process = process;
330 auto& state = *m_State;
333 if (state.notification.process == process) {
334 state.notification.complete(
true);
338 if (state.notification.process) {
339 SYSCALL_ERROR(DeviceBusy);
342 if (notification.socket &&
346 state.notification = notification;
350void PosixMessageQueue::cancelNotification(
size_t pid) {
352 if (m_State->notification.process && m_State->notification.pid == pid) {
353 m_State->notification.complete(
true);
357void PosixMessageQueue::clockChanged() {
MUST_USE_RESULT bool wait(Mutex &mutex, Time::Timestamp &timeout, Error &error, WaitQueue::StackDiscardCleanup onStackDiscard=nullptr, void *stackDiscardContext=nullptr)
void removeStatusFlag(int flag)
Helper to remove a single flag from the status flags.
int getStatusFlags() const
Get current status flags.
void addStatusFlag(int newFlag)
Helper to add a single flag to the status flags.
SharedPointer< NetworkSyscalls > networkImpl
Network syscall implementation for this descriptor (if it's a socket).
ReadinessGenerations readinessGenerations() override
static bool copyFromUser(void *destination, const void *source, size_t count, size_t elementSize=1)
SignalDeliveryResult queueSignalDelivery(Thread *target, size_t sig, uint32_t *flags=nullptr, int32_t signalCode=0, bool processDirected=false, uint64_t signalValue=0, const SharedPointer< SignalEventState > &state=SharedPointer< SignalEventState >())
static bool copyToUser(void *destination, const void *source, size_t count, size_t elementSize=1)
size_t getUserspaceId() const
MUST_USE_RESULT bool acquireProcessSignalThread(ThreadLease &lease)
static ProcessorInformation & information()
void notifyReadiness(ReadyMask mask)
void closeReadiness(ReadyMask mask=ReadyInvalid|ReadyHangup)
static Scheduler & instance()
MUST_USE_RESULT bool acquireProcess(ProcessLease &lease, size_t n)
A vector / dynamic array.