8#include "pedigree/kernel/LockGuard.h"
9#include "pedigree/kernel/process/ConditionVariable.h"
10#include "pedigree/kernel/process/Mutex.h"
11#include "pedigree/kernel/process/Process.h"
12#include "pedigree/kernel/process/Thread.h"
13#include "pedigree/kernel/processor/Processor.h"
14#include "pedigree/kernel/processor/ProcessorInformation.h"
15#include "pedigree/kernel/syscallError.h"
16#include "pedigree/kernel/time/Time.h"
17#include "pedigree/kernel/utilities/SharedPointer.h"
19#include "PosixSubsystem.h"
20#include "ipc-common.h"
21#include "sysv-semaphore-syscalls.h"
24constexpr size_t MaximumSets = 128;
25constexpr size_t MaximumSemaphores = 256;
26constexpr size_t MaximumOperations = 128;
27constexpr size_t MaximumUndoRecords = 4096;
28constexpr size_t MaximumUndoOwners = 4096;
29constexpr int MaximumValue = 32767;
30constexpr int Create = 01000, Exclusive = 02000, NoWait = 04000, Undo = 0x1000;
31constexpr int Remove = 0, SetMetadata = 1, Stat = 2, Info = 3;
32constexpr int GetPid = 11, GetValue = 12, GetAll = 13, GetNegativeCount = 14;
33constexpr int GetZeroCount = 15, SetValue = 16, SetAll = 17;
34constexpr int SemStat = 18, SemInfo = 19, SemStatAny = 20;
44 int64_t operationTime;
54 int map, identifiers, semaphores, undoStructures, perSet, operations;
55 int undoEntries, undoSize, maximumValue, maximumAdjustment;
58static_assert(
sizeof(Operation) == 6,
"Linux sembuf ABI");
60static_assert(
sizeof(Metadata) == 104,
"Linux amd64 semid_ds ABI");
62struct SemaphoreValue {
63 unsigned short value = 0;
65 unsigned negativeWaiters = 0;
66 unsigned zeroWaiters = 0;
70 uint64_t namespaceId = posix_ipc_namespace_id();
71 Metadata metadata = {};
72 SemaphoreValue semaphores[MaximumSemaphores];
99unsigned sequences[MaximumSets] = {};
100UndoRecord* undoRecords =
nullptr;
101size_t undoRecordCount = 0;
102UndoOwner* undoOwners =
nullptr;
103size_t undoOwnerCount = 0;
109 return set && set->id ==
id && (!enforceNamespace || set->namespaceId == posix_ipc_namespace_id())
114UndoOwner* findOwner(
Thread* thread) {
115 for (UndoOwner* owner = undoOwners; owner; owner = owner->next)
116 if (owner->thread == thread)
121UndoGroup* createUndoGroup(
Thread* thread) {
122 UndoOwner* owner = findOwner(thread);
125 if (undoOwnerCount == MaximumUndoOwners) {
126 SYSCALL_ERROR(OutOfMemory);
129 UndoGroup* group =
new UndoGroup;
131 undoOwners =
new UndoOwner{thread, group, undoOwners};
136UndoRecord* findUndo(UndoGroup* group,
int id,
unsigned number) {
137 for (UndoRecord* record = undoRecords; record; record = record->next)
138 if (record->group == group && record->id ==
id && record->number == number)
143void clearUndo(
int id,
int number = -1) {
144 UndoRecord** link = &undoRecords;
146 UndoRecord* record = *link;
147 if (record->id ==
id && (number < 0 || record->number ==
static_cast<unsigned>(number))) {
148 *link = record->next;
152 link = &record->next;
158int perform(Set& set,
Process* process, UndoGroup* group,
const Operation* operations,
size_t count,
160 unsigned short values[MaximumSemaphores];
161 int adjustments[MaximumSemaphores] = {};
162 bool adjusted[MaximumSemaphores] = {};
163 for (
size_t i = 0; i < set.metadata.count; ++i)
164 values[i] = set.semaphores[i].value;
165 for (
size_t i = 0; i < count; ++i) {
166 const Operation& operation = operations[i];
167 int next = values[operation.number] + operation.value;
168 if ((!operation.value && next) || next < 0) {
172 if (next > MaximumValue) {
173 SYSCALL_ERROR(BadRange);
176 values[operation.number] = next;
177 if ((operation.flags & Undo) && operation.value) {
178 if (!adjusted[operation.number]) {
179 UndoRecord* record = findUndo(group, set.id, operation.number);
180 adjustments[operation.number] = record ? record->adjustment : 0;
181 adjusted[operation.number] =
true;
183 const int adjustment = adjustments[operation.number] - operation.value;
184 if (adjustment < -MaximumValue - 1 || adjustment > MaximumValue) {
185 SYSCALL_ERROR(BadRange);
188 adjustments[operation.number] = adjustment;
192 for (
size_t i = 0; i < set.metadata.count; ++i)
193 if (adjusted[i] && adjustments[i] && !findUndo(group, set.id, i))
195 if (needed > MaximumUndoRecords - undoRecordCount) {
196 SYSCALL_ERROR(OutOfMemory);
199 for (
size_t i = 0; i < set.metadata.count; ++i) {
201 UndoRecord* record = findUndo(group, set.id, i);
203 record->adjustment = adjustments[i];
204 }
else if (adjustments[i]) {
206 new UndoRecord{group, set.id,
static_cast<unsigned>(i), adjustments[i], undoRecords};
210 set.semaphores[i].value = values[i];
212 for (
size_t i = 0; i < count; ++i)
213 set.semaphores[operations[i].number].pid = process->
getUserspaceId();
214 UndoRecord** link = &undoRecords;
216 UndoRecord* record = *link;
217 if (!record->adjustment) {
218 *link = record->next;
222 link = &record->next;
225 set.metadata.operationTime = Time::getTime();
226 set.changed.broadcast();
231int posix_semget(
int key,
int count,
int flags) {
232 if (count < 0 || count >
static_cast<int>(MaximumSemaphores)) {
233 SYSCALL_ERROR(InvalidArgument);
237 size_t freeSlot = MaximumSets;
238 for (
size_t i = 0; i < MaximumSets; ++i) {
240 if (freeSlot == MaximumSets)
244 Set& set = *registry[i];
245 if (!key || set.namespaceId != posix_ipc_namespace_id() || set.metadata.permission.key != key) {
248 if ((flags & (Create | Exclusive)) == (Create | Exclusive)) {
249 SYSCALL_ERROR(FileExists);
252 if (
static_cast<unsigned>(count) > set.metadata.count) {
253 SYSCALL_ERROR(InvalidArgument);
256 const unsigned requested = ((flags >> 6) | (flags >> 3) | flags) & 7;
257 if (!PosixIpc::allowed(set.metadata.permission, requested)) {
258 SYSCALL_ERROR(PermissionDenied);
263 if (key && !(flags & Create)) {
264 SYSCALL_ERROR(DoesNotExist);
268 SYSCALL_ERROR(InvalidArgument);
271 if (freeSlot == MaximumSets) {
272 SYSCALL_ERROR(NoSpaceLeftOnDevice);
276 auto& permission = set->metadata.permission;
277 PosixIpc::initialize(permission, key, flags & 0777, sequences[freeSlot]++ & 0xffff);
278 set->id = permission.sequence * MaximumSets + freeSlot;
279 set->metadata.count = count;
280 set->metadata.changeTime = Time::getTime();
281 registry[freeSlot] = set;
285int posix_semop(
int id,
const void* operations,
size_t count) {
286 return posix_semtimedop(
id, operations, count,
nullptr);
289int posix_semtimedop(
int id,
const void* operations,
size_t count,
const void* timeout) {
290 if (
id < 0 || !count) {
291 SYSCALL_ERROR(InvalidArgument);
294 if (count > MaximumOperations) {
295 SYSCALL_ERROR(TooBig);
298 Operation requested[MaximumOperations];
300 SYSCALL_ERROR(BadAddress);
303 Time::Timestamp remaining = Time::Infinity;
304 Time::Timestamp deadline = Time::Infinity;
307 int64_t seconds, nanoseconds;
310 SYSCALL_ERROR(BadAddress);
313 if (duration.seconds < 0 || duration.nanoseconds < 0 ||
314 duration.nanoseconds >=
static_cast<int64_t
>(Time::Multiplier::Second)) {
315 SYSCALL_ERROR(InvalidArgument);
318 const Time::Timestamp seconds = duration.seconds;
319 remaining = seconds > (Time::Infinity - 1 - duration.nanoseconds) / Time::Multiplier::Second
321 : seconds * Time::Multiplier::Second + duration.nanoseconds;
322 const Time::Timestamp now = Time::getTicks();
323 deadline = remaining >= Time::Infinity - now ? Time::Infinity - 1 : now + remaining;
327 if (!set || set->namespaceId != posix_ipc_namespace_id()) {
328 SYSCALL_ERROR(InvalidArgument);
332 bool needsUndo =
false;
333 for (
size_t i = 0; i < count; ++i) {
334 if (requested[i].number >= set->metadata.count) {
335 SYSCALL_ERROR(FileTooLarge);
338 if (requested[i].value)
340 needsUndo |= (requested[i].flags & Undo) && requested[i].value;
342 Process* process = PosixIpc::process();
343 if (!PosixIpc::allowed(set->metadata.permission, access)) {
344 SYSCALL_ERROR(PermissionDenied);
347 UndoGroup* group =
nullptr;
355 SYSCALL_ERROR(IdentifierRemoved);
359 const int result = perform(*set, process, group, requested, count, blocked);
362 if (deadline != Time::Infinity) {
363 const Time::Timestamp now = Time::getTicks();
364 remaining = now >= deadline ? 0 : deadline - now;
366 if ((requested[blocked].flags & NoWait) || !remaining) {
367 SYSCALL_ERROR(NoMoreProcesses);
370 SemaphoreValue& semaphore = set->semaphores[requested[blocked].number];
372 requested[blocked].value ? semaphore.negativeWaiters : semaphore.zeroWaiters;
374 ConditionVariable::Error error = ConditionVariable::NoError;
375 const bool awakened = set->changed.wait(registryLock, remaining, error);
378 SYSCALL_ERROR(IdentifierRemoved);
382 if (error == ConditionVariable::TimedOut)
383 SYSCALL_ERROR(NoMoreProcesses);
385 SYSCALL_ERROR(Interrupted);
391int posix_semctl(
int id,
int number,
int command, uintptr_t argument) {
392 if (
id < 0 || command < Remove || (command > Info && command < GetPid) || command > SemStatAny) {
393 SYSCALL_ERROR(InvalidArgument);
396 if (command == SetValue &&
397 (
static_cast<int>(argument) < 0 ||
static_cast<int>(argument) > MaximumValue)) {
398 SYSCALL_ERROR(BadRange);
402 if (command == Info || command == SemInfo) {
403 int highest = 0, usedSets = 0, usedSemaphores = 0;
404 for (
size_t i = 0; i < MaximumSets; ++i) {
405 if (registry[i] && registry[i]->namespaceId == posix_ipc_namespace_id()) {
408 usedSemaphores += registry[i]->metadata.count;
411 const Information information = {0,
413 MaximumSets * MaximumSemaphores,
418 command == SemInfo ? usedSets : 20,
420 command == SemInfo ? usedSemaphores : MaximumValue};
422 sizeof(information))) {
423 SYSCALL_ERROR(BadAddress);
428 const bool byIndex = command == SemStat || command == SemStatAny;
429 SharedPointer<Set> set = byIndex &&
id >= 0 && id < static_cast<int>(MaximumSets) ? registry[id]
432 if (!set || set->namespaceId != posix_ipc_namespace_id()) {
433 SYSCALL_ERROR(InvalidArgument);
436 Process* process = PosixIpc::process();
437 auto& permission = set->metadata.permission;
438 if (command == Remove || command == SetMetadata) {
439 if (!PosixIpc::owner(permission)) {
440 SYSCALL_ERROR(NotEnoughPermissions);
443 }
else if (command != SemStatAny &&
444 !PosixIpc::allowed(permission, command == SetValue || command == SetAll ? 2 : 4)) {
445 SYSCALL_ERROR(PermissionDenied);
452 registry[
static_cast<unsigned>(set->id) % MaximumSets].reset();
453 set->changed.broadcast();
458 sizeof(requested))) {
459 SYSCALL_ERROR(BadAddress);
462 if (requested.permission.uid == 0xffffffffU || requested.permission.gid == 0xffffffffU) {
463 SYSCALL_ERROR(InvalidArgument);
466 permission.uid = requested.permission.uid;
467 permission.gid = requested.permission.gid;
468 permission.mode = requested.permission.mode & 0777;
469 set->metadata.changeTime = Time::getTime();
476 sizeof(set->metadata))) {
477 SYSCALL_ERROR(BadAddress);
480 return byIndex ? set->id : 0;
483 unsigned short values[MaximumSemaphores];
484 const size_t bytes = set->metadata.count *
sizeof(values[0]);
485 if (command == GetAll) {
486 for (
size_t i = 0; i < set->metadata.count; ++i)
487 values[i] = set->semaphores[i].value;
489 SYSCALL_ERROR(BadAddress);
494 SYSCALL_ERROR(BadAddress);
497 for (
size_t i = 0; i < set->metadata.count; ++i) {
498 if (values[i] > MaximumValue) {
499 SYSCALL_ERROR(BadRange);
504 for (
size_t i = 0; i < set->metadata.count; ++i) {
505 set->semaphores[i].value = values[i];
508 set->metadata.changeTime = Time::getTime();
509 set->changed.broadcast();
515 case GetNegativeCount:
520 SYSCALL_ERROR(InvalidArgument);
523 if (number < 0 ||
static_cast<unsigned>(number) >= set->metadata.count) {
524 SYSCALL_ERROR(InvalidArgument);
527 SemaphoreValue& semaphore = set->semaphores[number];
530 return semaphore.pid;
532 return semaphore.value;
533 case GetNegativeCount:
534 return semaphore.negativeWaiters;
536 return semaphore.zeroWaiters;
538 const int value =
static_cast<int>(argument);
539 clearUndo(set->id, number);
540 semaphore.value = value;
542 set->metadata.changeTime = Time::getTime();
543 set->changed.broadcast();
548bool posix_sem_clone(
Thread* parent,
Thread* child,
bool shareUndo) {
552 if (findOwner(child))
554 const size_t needed = findOwner(parent) ? 1 : 2;
555 if (needed > MaximumUndoOwners - undoOwnerCount) {
556 SYSCALL_ERROR(OutOfMemory);
559 UndoGroup* group = createUndoGroup(parent);
560 undoOwners =
new UndoOwner{child, group, undoOwners};
566void posix_sem_thread_exit(
Thread* thread) {
568 UndoOwner** ownerLink = &undoOwners;
569 while (*ownerLink && (*ownerLink)->thread != thread)
570 ownerLink = &(*ownerLink)->next;
573 UndoOwner* owner = *ownerLink;
574 UndoGroup* group = owner->group;
575 *ownerLink = owner->next;
580 UndoRecord** link = &undoRecords;
582 UndoRecord* record = *link;
583 if (record->group != group) {
584 link = &record->next;
588 if (set && record->adjustment) {
589 SemaphoreValue& semaphore = set->semaphores[record->number];
590 const int value = semaphore.value + record->adjustment;
592 semaphore.value = value < 0 ? 0 : value > MaximumValue ? MaximumValue : value;
594 set->metadata.operationTime = Time::getTime();
595 set->changed.broadcast();
597 *link = record->next;
604void posix_sem_namespace_exit(uint64_t
identity) {
606 for (
auto& set : registry) {
607 if (set && set->namespaceId ==
identity) {
610 set->changed.broadcast();
static bool copyFromUser(void *destination, const void *source, size_t count, size_t elementSize=1)
static bool copyToUser(void *destination, const void *source, size_t count, size_t elementSize=1)
size_t getUserspaceId() const
static ProcessorInformation & information()
Process * getParent() const