20#include "pedigree/kernel/Log.h"
21#include "pedigree/kernel/Metrics.h"
22#include "pedigree/kernel/machine/Machine.h"
23#include "pedigree/kernel/machine/Timer.h"
24#include "pedigree/kernel/process/PerProcessorScheduler.h"
25#include "pedigree/kernel/process/Scheduler.h"
26#include "pedigree/kernel/process/Semaphore.h"
27#include "pedigree/kernel/process/Thread.h"
28#include "pedigree/kernel/process/eventNumbers.h"
29#include "pedigree/kernel/processor/Processor.h"
30#include "pedigree/kernel/processor/ProcessorInformation.h"
31#include "pedigree/kernel/time/Time.h"
32#include "pedigree/kernel/utilities/Iterator.h"
33#include "pedigree/kernel/utilities/assert.h"
34#include "pedigree/kernel/utilities/utility.h"
37constexpr size_t SemaphoreMagic = 0xdeadbaba;
38constexpr size_t MutexStateTag = 1;
39constexpr size_t MutexUnlocked = MutexStateTag;
41size_t loadState(
const size_t* state) {
42 return __atomic_load_n(state, __ATOMIC_ACQUIRE);
45bool isMutexState(
size_t state) {
46 return (state & MutexStateTag) == MutexStateTag;
49size_t currentMutexOwner() {
50#if defined(PEDIGREE_BUILDUTILS)
51 alignas(2)
static thread_local char ownerIdentity;
52 uintptr_t owner =
reinterpret_cast<uintptr_t
>(&ownerIdentity);
55 uintptr_t owner = thread ?
reinterpret_cast<uintptr_t
>(thread)
56 : reinterpret_cast<uintptr_t>(&
Processor::information());
58 assert((owner & MutexStateTag) == 0);
59 return owner | MutexStateTag;
62#if defined(PEDIGREE_BUILDUTILS)
63class SemaphoreInterruptGuard {
65 explicit SemaphoreInterruptGuard(
bool) {}
71void destroyTimeoutEvent(
Thread* thread,
Event* event) {
83 event->waitForDeliveries();
87struct SemaphoreTimeoutDiscard {
92void discardSemaphoreWait(
void* context) {
93 SemaphoreTimeoutDiscard* discard =
reinterpret_cast<SemaphoreTimeoutDiscard*
>(context);
94 Event*
event = discard->event;
95 discard->event =
nullptr;
96 destroyTimeoutEvent(discard->thread, event);
99void finishSemaphoreTimeout(SemaphoreTimeoutDiscard& discard) {
100 Event*
event = discard.event;
101 discard.event =
nullptr;
102 destroyTimeoutEvent(discard.thread, event);
105#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
106Semaphore::BeforeWaitHook g_BeforeWaitHook =
nullptr;
107Semaphore::MutexTransitionHook g_MutexTransitionHook =
nullptr;
111void observeMutexTransition(Semaphore::MutexTransitionWindow window) {
112 Semaphore::MutexTransitionHook hook = __atomic_load_n(&g_MutexTransitionHook, __ATOMIC_ACQUIRE);
120static void interruptSemaphore(uint8_t* pBuffer) {
126Semaphore::SemaphoreEvent::SemaphoreEvent(
size_t nestingLevel)
127 :
Event(reinterpret_cast<uintptr_t>(&interruptSemaphore), false ,
129#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
130 g_SemaphoreTimeoutCreates += 1;
134Semaphore::SemaphoreEvent::~SemaphoreEvent() {
135#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
136 g_SemaphoreTimeoutDestroys += 1;
149 return EventNumbers::Interrupt;
153 : magic(SemaphoreMagic), m_Counter(nInitialValue), m_Waiters(), m_bCanInterrupt(canInterrupt) {
154 assert(magic == SemaphoreMagic);
158 assert(magic == SemaphoreMagic);
162 size_t timeoutUsecs,
bool deferTerminal) {
165 return SemaphoreResult::withError(Interrupted);
169 size_t state = loadState(&magic);
170 assert(state == SemaphoreMagic || isMutexState(state));
171 if (isMutexState(state)) {
173 FATAL(
"Mutex acquisition must request exactly one item");
175 if (state == currentMutexOwner()) {
176 ERROR_NOLOCK(
"Recursive mutex " <<
Hex <<
reinterpret_cast<uintptr_t
>(
this) <<
" caller "
177 <<
reinterpret_cast<uintptr_t
>(__builtin_return_address(0)));
178#if X86_COMMON && !defined(PEDIGREE_BUILDUTILS)
183 size_t stackSize = 0;
184 uintptr_t stackBase =
reinterpret_cast<uintptr_t
>(thread->
getKernelStackBase(&stackSize));
186 for (
size_t depth = 0; stackSize >= 2 *
sizeof(uintptr_t) && depth < 12; ++depth) {
187 if ((frame & (
alignof(uintptr_t) - 1)) || frame < stackBase ||
188 frame - stackBase > stackSize - 2 *
sizeof(uintptr_t)) {
191 const uintptr_t* words =
reinterpret_cast<const uintptr_t*
>(frame);
192 ERROR_NOLOCK(
"Recursive mutex frame " <<
Dec << depth <<
" pc " <<
Hex << words[1]);
193 uintptr_t next = words[0];
201 FATAL(
"Recursive Mutex acquisition");
210 for (
int i = 0; i < 10; i++) {
212 return SemaphoreResult::withValue(
true);
217 return SemaphoreResult::withValue(
true);
219 Metrics::increment(Metrics::SemaphoreContended);
223 return SemaphoreResult::withError(TimedOut);
228 if (retainedSignalInterruption && m_bCanInterrupt) {
229 return SemaphoreResult::withError(Interrupted);
233 const bool completionWait =
238 if (timeoutSecs || timeoutUsecs) {
240 Machine::instance().
getTimer()->
addAlarm(pEvent, timeoutSecs, timeoutUsecs);
242 SemaphoreTimeoutDiscard timeoutDiscard = {pThread, pEvent};
245 SemaphoreResult result = SemaphoreResult::withValue(
true);
248 finishSemaphoreTimeout(timeoutDiscard);
249 return SemaphoreResult::withError(Interrupted);
255 if (pThread->getInterruptionReason() == Thread::InterruptedByTimeout) {
256 finishSemaphoreTimeout(timeoutDiscard);
257 pThread->clearInterruption();
258 return SemaphoreResult::withError(TimedOut);
262 finishSemaphoreTimeout(timeoutDiscard);
267 auto guard = m_Waiters.acquire();
268#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
269 if (
auto hook = __atomic_load_n(&g_BeforeWaitHook, __ATOMIC_ACQUIRE)) {
273 guard.prepareToWait();
279 finishSemaphoreTimeout(timeoutDiscard);
285 if (
static_cast<ssize_t
>(m_Counter) >=
static_cast<ssize_t
>(n)) {
294 finishSemaphoreTimeout(timeoutDiscard);
295 return SemaphoreResult::withError(Interrupted);
298 WaitQueue::WakeReason wakeReason =
301 reinterpret_cast<uintptr_t
>(__builtin_return_address(0)))
303 reinterpret_cast<uintptr_t
>(__builtin_return_address(0)));
307 const Thread::InterruptionReason interruption = pThread->getInterruptionReason();
308 if (wakeReason == WaitQueue::WakeReason::Event && interruption == Thread::NotInterrupted &&
316 if ((wakeReason == WaitQueue::WakeReason::Event ||
317 wakeReason == WaitQueue::WakeReason::Unwinding ||
318 wakeReason == WaitQueue::WakeReason::Terminating ||
319 interruption != Thread::NotInterrupted)) {
320 if (completionWait && (wakeReason == WaitQueue::WakeReason::Unwinding ||
321 wakeReason == WaitQueue::WakeReason::Terminating)) {
325 if (interruption == Thread::InterruptedByTimeout) {
326 result = SemaphoreResult::withError(TimedOut);
327 pThread->clearInterruption();
328 }
else if (!m_bCanInterrupt && (wakeReason == WaitQueue::WakeReason::Event ||
329 interruption == Thread::InterruptedBySignal)) {
338 result = SemaphoreResult::withError(Interrupted);
343 if (interruption != Thread::InterruptedBySignal) {
344 pThread->clearInterruption();
348 finishSemaphoreTimeout(timeoutDiscard);
356 SemaphoreResult result = acquireWithResult(n, timeoutSecs, timeoutUsecs);
357 return result.hasValue() && result.value();
361 SemaphoreError& error) {
362 SemaphoreResult result = acquireWithResult(n, timeoutSecs, timeoutUsecs);
363 if (result.hasError()) {
364 error = result.error();
369 return result.value();
374 return acquire(n, timeoutSecs, timeoutUsecs);
377 if (!timeoutSecs && !timeoutUsecs && n == 1 && loadState(&magic) == MutexUnlocked) {
389 const bool hasTimeout = timeoutSecs || timeoutUsecs;
390 const Time::Timestamp started = hasTimeout ? Time::getTicks() : 0;
392 Time::Timestamp timeout = 0;
394 const Time::Timestamp maximum = Time::Infinity - 1;
395 if (timeoutSecs > (maximum / Time::Multiplier::Second)) {
398 timeout = timeoutSecs * Time::Multiplier::Second;
399 const Time::Timestamp microseconds =
400 timeoutUsecs > (maximum / Time::Multiplier::Microsecond)
402 : timeoutUsecs * Time::Multiplier::Microsecond;
403 timeout = microseconds > (maximum - timeout) ? maximum : timeout + microseconds;
407 Thread::InterruptionReason retainedInterruption =
408 thread ? thread->getInterruptionReason() : Thread::NotInterrupted;
409 if (thread && retainedInterruption != Thread::NotInterrupted) {
410 thread->clearInterruption();
413 size_t remainingSecs = timeoutSecs;
414 size_t remainingUsecs = timeoutUsecs;
416 const Time::Timestamp remainingMicroseconds =
417 (timeout / Time::Multiplier::Microsecond) +
418 ((timeout % Time::Multiplier::Microsecond) ? 1 : 0);
420 remainingMicroseconds / (Time::Multiplier::Second / Time::Multiplier::Microsecond);
422 remainingMicroseconds % (Time::Multiplier::Second / Time::Multiplier::Microsecond);
426 SemaphoreResult result = acquireWithResult(n, remainingSecs, remainingUsecs,
true);
427 const bool acquired = result.hasValue() && result.value();
428 const SemaphoreError error = result.hasError() ? result.error() : NoError;
430 if (thread && retainedInterruption != Thread::NotInterrupted) {
431 thread->setInterruptionReason(retainedInterruption);
436 if (error == TimedOut) {
441 retainedInterruption = Thread::InterruptedByTimeout;
444 if (thread && retainedInterruption != Thread::NotInterrupted) {
445 thread->setInterruptionReason(retainedInterruption);
450 if (error != Interrupted || !thread ||
451 thread->getInterruptionReason() != Thread::InterruptedBySignal) {
455 if (retainedInterruption != Thread::InterruptedByTimeout) {
456 retainedInterruption = Thread::InterruptedBySignal;
458 thread->clearInterruption();
465 const Time::Timestamp elapsed = Time::getTicks() - started;
466 if (elapsed >= timeout) {
467 thread->setInterruptionReason(retainedInterruption);
471 const Time::Timestamp remaining = timeout - elapsed;
472 const Time::Timestamp remainingMicroseconds =
473 (remaining / Time::Multiplier::Microsecond) +
474 ((remaining % Time::Multiplier::Microsecond) ? 1 : 0);
476 remainingMicroseconds / (Time::Multiplier::Second / Time::Multiplier::Microsecond);
478 remainingMicroseconds % (Time::Multiplier::Second / Time::Multiplier::Microsecond);
485 const bool mutex = isMutexState(loadState(&magic));
486 if (mutex && n != 1) {
487 ERROR(
"Mutex acquisition must request exactly one item");
492 SemaphoreInterruptGuard interrupts(
false);
493 ssize_t value = m_Counter;
495 if ((value -
static_cast<ssize_t
>(n)) < 0) {
498 if (!m_Counter.compareAndSwap(value, value - n)) {
502#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
503 observeMutexTransition(MutexCounterAcquired);
506 if (!__sync_bool_compare_and_swap(&magic, MutexUnlocked, currentMutexOwner())) {
510 ERROR(
"Mutex acquired with stale ownership state");
516 ssize_t value = m_Counter;
517 if ((value -
static_cast<ssize_t
>(n)) < 0) {
520 if (!m_Counter.compareAndSwap(value, value - n)) {
525 EMIT_IF(STRICT_LOCK_ORDERING) {
532 const size_t state = loadState(&magic);
533 assert(state == SemaphoreMagic || isMutexState(state));
534 if (isMutexState(state)) {
535 ERROR(
"Mutex items cannot be drained");
539 ssize_t available = m_Counter;
540 while (available > 0) {
541 if (m_Counter.compareAndSwap(available, 0)) {
542 return static_cast<size_t>(available);
544 available = m_Counter;
556 size_t state = loadState(&magic);
557 assert(state == SemaphoreMagic || isMutexState(state));
559 if (isMutexState(state)) {
561 ERROR(
"Mutex release must return exactly one item");
566 SemaphoreInterruptGuard interrupts(
false);
567 const size_t owner = currentMutexOwner();
568 if (!__sync_bool_compare_and_swap(&magic, owner, MutexUnlocked)) {
569 ERROR(
"Mutex release attempted by a non-owner");
573#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
574 observeMutexTransition(MutexOwnerReleased);
577 if (!m_Counter.compareAndSwap(0, 1)) {
581 __sync_bool_compare_and_swap(&magic, MutexUnlocked, owner);
582 ERROR(
"Mutex release found an invalid binary count");
596 EMIT_IF(STRICT_LOCK_ORDERING) {
602 return static_cast<ssize_t
>(m_Counter);
606 const size_t state = loadState(&magic);
607 if (!isMutexState(state) || state == MutexUnlocked) {
611 return reinterpret_cast<const void*
>(state & ~MutexStateTag);
615 assert(loadState(&magic) == SemaphoreMagic);
616 magic = locked ? currentMutexOwner() : MutexUnlocked;
619void Semaphore::destroyMutex() {
620 if (loadState(&magic) != MutexUnlocked || m_Counter != 1) {
621 FATAL(
"Destroying a locked or corrupt Mutex");
624 magic = SemaphoreMagic;
627bool Semaphore::mutexOwnedByCurrentThread()
const {
628 return loadState(&magic) == currentMutexOwner();
631#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
632void Semaphore::setBeforeWaitHook(BeforeWaitHook hook) {
633 __atomic_store_n(&g_BeforeWaitHook, hook, __ATOMIC_RELEASE);
636void Semaphore::setMutexTransitionHook(MutexTransitionHook hook) {
637 __atomic_store_n(&g_MutexTransitionHook, hook, __ATOMIC_RELEASE);
640size_t Semaphore::getHostedTimeoutCreateCount() {
641 return g_SemaphoreTimeoutCreates;
644size_t Semaphore::getHostedTimeoutDestroyCount() {
645 return g_SemaphoreTimeoutDestroys;
virtual Timer * getTimer()=0
static ProcessorInformation & information()
static bool guardDeviceHardIrqOperation(DeviceHardIrqOperation operation)
static uintptr_t getBasePointer()
virtual size_t getNumber()
virtual size_t serialize(uint8_t *pBuffer)
const void * getDebugMutexOwner() const
MUST_USE_RESULT bool acquireWithError(size_t n, size_t timeoutSecs, size_t timeoutUsecs, SemaphoreError &error)
MUST_USE_RESULT size_t drainAvailable()
MUST_USE_RESULT bool acquireForCompletion(size_t n=1, size_t timeoutSecs=0, size_t timeoutUsecs=0)
Semaphore(size_t nInitialValue, bool canInterrupt=true)
void initialiseMutex(bool locked)
bool tryAcquire(size_t n=1)
bool acquire(size_t n=1, size_t timeoutSecs=0, size_t timeoutUsecs=0)
bool hasActiveTemporarySignalMask()
@ Continue
No unwind necessary, carry on as normal.
void * getKernelStackBase(size_t *size) const
UnwindType getUnwindState()
void cullEvent(Event *pEvent)
bool retainTemporarySignalWaitInterruptionOrClear()
bool hasTemporarySignalWaitInterruption()
bool isTerminationDeferred() const
size_t getStateLevel() const
virtual void removeAlarm(class Event *pEvent)=0
virtual void addAlarm(class Event *pEvent, size_t alarmSecs, size_t alarmUsecs=0)=0
size_t wakeAllIfWaiting(WakeReason reason=WakeReason::Signalled, const Channel &channel=Channel())