The Pedigree Project 0.1
Semaphore.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
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"
35
36namespace {
37constexpr size_t SemaphoreMagic = 0xdeadbaba;
38constexpr size_t MutexStateTag = 1;
39constexpr size_t MutexUnlocked = MutexStateTag;
40
41size_t loadState(const size_t* state) {
42 return __atomic_load_n(state, __ATOMIC_ACQUIRE);
43}
44
45bool isMutexState(size_t state) {
46 return (state & MutexStateTag) == MutexStateTag;
47}
48
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);
53#else
54 Thread* thread = Processor::information().getCurrentThread();
55 uintptr_t owner = thread ? reinterpret_cast<uintptr_t>(thread)
56 : reinterpret_cast<uintptr_t>(&Processor::information());
57#endif
58 assert((owner & MutexStateTag) == 0);
59 return owner | MutexStateTag;
60}
61
62#if defined(PEDIGREE_BUILDUTILS)
63class SemaphoreInterruptGuard {
64 public:
65 explicit SemaphoreInterruptGuard(bool) {}
66};
67#else
68using SemaphoreInterruptGuard = EnsureInterrupts;
69#endif
70
71void destroyTimeoutEvent(Thread* thread, Event* event) {
72 if (!event) {
73 return;
74 }
75
76 // Timer removal is the publication barrier; culling then covers a timeout
77 // that was already queued while another wake reason won the wait.
78 Machine::instance().getTimer()->removeAlarm(event);
79 thread->cullEvent(event);
80 // A timer dispatch may have crossed the removal boundary while its
81 // Thread::sendEvent admission was still in flight. Close admission and
82 // drain that lease before releasing the timeout event storage.
83 event->waitForDeliveries();
84 delete event;
85}
86
87struct SemaphoreTimeoutDiscard {
88 Thread* thread;
89 Event* event;
90};
91
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);
97}
98
99void finishSemaphoreTimeout(SemaphoreTimeoutDiscard& discard) {
100 Event* event = discard.event;
101 discard.event = nullptr;
102 destroyTimeoutEvent(discard.thread, event);
103}
104
105#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
106Semaphore::BeforeWaitHook g_BeforeWaitHook = nullptr;
107Semaphore::MutexTransitionHook g_MutexTransitionHook = nullptr;
108Atomic<size_t> g_SemaphoreTimeoutCreates(0);
109Atomic<size_t> g_SemaphoreTimeoutDestroys(0);
110
111void observeMutexTransition(Semaphore::MutexTransitionWindow window) {
112 Semaphore::MutexTransitionHook hook = __atomic_load_n(&g_MutexTransitionHook, __ATOMIC_ACQUIRE);
113 if (hook) {
114 hook(window);
115 }
116}
117#endif
118} // namespace
119
120static void interruptSemaphore(uint8_t* pBuffer) {
121 EMIT_IF(THREADS) {
122 Processor::information().getCurrentThread()->markTimeoutInterruptedWait();
123 }
124}
125
126Semaphore::SemaphoreEvent::SemaphoreEvent(size_t nestingLevel)
127 : Event(reinterpret_cast<uintptr_t>(&interruptSemaphore), false /* Not deletable */,
128 nestingLevel) {
129#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
130 g_SemaphoreTimeoutCreates += 1;
131#endif
132}
133
134Semaphore::SemaphoreEvent::~SemaphoreEvent() {
135#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
136 g_SemaphoreTimeoutDestroys += 1;
137#endif
138}
139
140size_t Semaphore::SemaphoreEvent::serialize(uint8_t* pBuffer) {
141 return 0;
142}
143
144bool Semaphore::SemaphoreEvent::unserialize(uint8_t* pBuffer, Semaphore::SemaphoreEvent& event) {
145 return true;
146}
147
149 return EventNumbers::Interrupt;
150}
151
152Semaphore::Semaphore(size_t nInitialValue, bool canInterrupt)
153 : magic(SemaphoreMagic), m_Counter(nInitialValue), m_Waiters(), m_bCanInterrupt(canInterrupt) {
154 assert(magic == SemaphoreMagic);
155}
156
158 assert(magic == SemaphoreMagic);
159}
160
161Semaphore::SemaphoreResult Semaphore::acquireWithResult(size_t n, size_t timeoutSecs,
162 size_t timeoutUsecs, bool deferTerminal) {
163 EMIT_IF(!PEDIGREE_BENCHMARK) {
164 if (!Processor::guardDeviceHardIrqOperation(DeviceHardIrqOperation::SemaphoreAcquire)) {
165 return SemaphoreResult::withError(Interrupted);
166 }
167 }
168
169 size_t state = loadState(&magic);
170 assert(state == SemaphoreMagic || isMutexState(state));
171 if (isMutexState(state)) {
172 if (n != 1) {
173 FATAL("Mutex acquisition must request exactly one item");
174 }
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)
179 // The debugger may itself need locks or mappings; preserve the original
180 // callers first, without consulting the address-space implementation.
181 Thread* thread = Processor::information().getCurrentThread();
182 if (thread) {
183 size_t stackSize = 0;
184 uintptr_t stackBase = reinterpret_cast<uintptr_t>(thread->getKernelStackBase(&stackSize));
185 uintptr_t frame = Processor::getBasePointer();
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)) {
189 break;
190 }
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];
194 if (next <= frame) {
195 break;
196 }
197 frame = next;
198 }
199 }
200#endif
201 FATAL("Recursive Mutex acquisition");
202 }
203 }
204
205 // Spin 10 times in the case that the lock is about to be released on
206 // multiprocessor systems, and just once for uniprocessor systems, so we don't
207 // go through the rigmarole of creating a timeout event if the lock is
208 // available.
209 EMIT_IF(MULTIPROCESSOR) {
210 for (int i = 0; i < 10; i++) {
211 if (tryAcquire(n))
212 return SemaphoreResult::withValue(true);
213 }
214 }
215
216 if (tryAcquire(n))
217 return SemaphoreResult::withValue(true);
218
219 Metrics::increment(Metrics::SemaphoreContended);
220
221 EMIT_IF(!THREADS) {
222 // failed to tryAcquire - no point doing anything else here.
223 return SemaphoreResult::withError(TimedOut);
224 }
225 else {
226 Thread* pThread = Processor::information().getCurrentThread();
227 const bool retainedSignalInterruption = pThread->retainTemporarySignalWaitInterruptionOrClear();
228 if (retainedSignalInterruption && m_bCanInterrupt) {
229 return SemaphoreResult::withError(Interrupted);
230 }
231 // Explicit completion waits always finish. A non-interruptible ownership
232 // wait does so only while its caller has deferred terminal teardown.
233 const bool completionWait =
234 deferTerminal || (!m_bCanInterrupt && pThread->isTerminationDeferred());
235
236 // If we have a timeout, create the event and register it.
237 Event* pEvent = 0;
238 if (timeoutSecs || timeoutUsecs) {
239 pEvent = new SemaphoreEvent(pThread->getStateLevel());
240 Machine::instance().getTimer()->addAlarm(pEvent, timeoutSecs, timeoutUsecs);
241 }
242 SemaphoreTimeoutDiscard timeoutDiscard = {pThread, pEvent};
243 Thread::StackDiscardScope discardScope(pEvent ? &discardSemaphoreWait : nullptr,
244 &timeoutDiscard);
245 SemaphoreResult result = SemaphoreResult::withValue(true);
246 while (true) {
247 if (!completionWait && pThread->getUnwindState() != Thread::Continue) {
248 finishSemaphoreTimeout(timeoutDiscard);
249 return SemaphoreResult::withError(Interrupted);
250 }
251
252 // The timeout handler can run before this thread reaches
253 // WaitQueue::wait(). Keep its state as a predicate rather than
254 // clearing the only evidence that the deadline expired.
255 if (pThread->getInterruptionReason() == Thread::InterruptedByTimeout) {
256 finishSemaphoreTimeout(timeoutDiscard);
257 pThread->clearInterruption();
258 return SemaphoreResult::withError(TimedOut);
259 }
260
261 if (tryAcquire(n)) {
262 finishSemaphoreTimeout(timeoutDiscard);
263
264 return result;
265 }
266
267 auto guard = m_Waiters.acquire();
268#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
269 if (auto hook = __atomic_load_n(&g_BeforeWaitHook, __ATOMIC_ACQUIRE)) {
270 hook(this);
271 }
272#endif
273 guard.prepareToWait();
274
275 // The predicate is checked while serialised with release(). The
276 // WaitQueue publishes a persistent wait record before dropping this
277 // guard, closing both wake-before-enrol and wake-before-sleep gaps.
278 if (tryAcquire(n)) {
279 finishSemaphoreTimeout(timeoutDiscard);
280 return result;
281 }
282
283 // A competing acquire can defeat tryAcquire's single CAS while
284 // leaving enough tokens. Only sleep after observing a shortage.
285 if (static_cast<ssize_t>(m_Counter) >= static_cast<ssize_t>(n)) {
286 continue;
287 }
288
289 // The handler may have completed after the entry check but before this
290 // wait queue was published. The second resource check above preserves
291 // resource/readiness precedence; this state-level predicate closes the
292 // remaining delivered-signal-before-enrolment window.
293 if (m_bCanInterrupt && pThread->hasTemporarySignalWaitInterruption()) {
294 finishSemaphoreTimeout(timeoutDiscard);
295 return SemaphoreResult::withError(Interrupted);
296 }
297
298 WaitQueue::WakeReason wakeReason =
299 completionWait
300 ? guard.waitForCompletion(WaitQueue::Channel(this), Thread::SemWait,
301 reinterpret_cast<uintptr_t>(__builtin_return_address(0)))
302 : guard.wait(WaitQueue::Channel(this), Thread::SemWait,
303 reinterpret_cast<uintptr_t>(__builtin_return_address(0)));
304
305 // Event delivery can follow an ordinary wake which already won
306 // waiter.reason. The per-wait marker remains authoritative.
307 const Thread::InterruptionReason interruption = pThread->getInterruptionReason();
308 if (wakeReason == WaitQueue::WakeReason::Event && interruption == Thread::NotInterrupted &&
309 pThread->hasActiveTemporarySignalMask() &&
310 pThread->getUnwindState() == Thread::Continue) {
311 // Default signal actions and unrelated kernel callbacks do not
312 // terminate a signal-aware wait. A caught handler sets the explicit
313 // signal marker before control returns here.
314 continue;
315 }
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)) {
322 continue;
323 }
324
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)) {
330 // A Mutex wait is not an interruptible operation. The
331 // event was delivered, but must not leak into the next
332 // unrelated interruptible wait. The interruption marker
333 // also matters when an ordinary release won waiter.reason
334 // just before the event was dispatched.
336 continue;
337 } else {
338 result = SemaphoreResult::withError(Interrupted);
339
340 // Callers such as lwIP expose only a boolean/timeout
341 // result. Keep the signal reason on the Thread so the
342 // syscall boundary can still distinguish EINTR.
343 if (interruption != Thread::InterruptedBySignal) {
344 pThread->clearInterruption();
345 }
346 }
347
348 finishSemaphoreTimeout(timeoutDiscard);
349 return result;
350 }
351 }
352 }
353}
354
355bool Semaphore::acquire(size_t n, size_t timeoutSecs, size_t timeoutUsecs) {
356 SemaphoreResult result = acquireWithResult(n, timeoutSecs, timeoutUsecs);
357 return result.hasValue() && result.value();
358}
359
360bool Semaphore::acquireWithError(size_t n, size_t timeoutSecs, size_t timeoutUsecs,
361 SemaphoreError& error) {
362 SemaphoreResult result = acquireWithResult(n, timeoutSecs, timeoutUsecs);
363 if (result.hasError()) {
364 error = result.error();
365 return false;
366 }
367
368 error = NoError;
369 return result.value();
370}
371
372bool Semaphore::acquireForCompletion(size_t n, size_t timeoutSecs, size_t timeoutUsecs) {
373 EMIT_IF(!THREADS) {
374 return acquire(n, timeoutSecs, timeoutUsecs);
375 }
376 else {
377 if (!timeoutSecs && !timeoutUsecs && n == 1 && loadState(&magic) == MutexUnlocked) {
378 EMIT_IF(!PEDIGREE_BENCHMARK) {
379 if (!Processor::guardDeviceHardIrqOperation(DeviceHardIrqOperation::SemaphoreAcquire)) {
380 return false;
381 }
382 }
383 if (tryAcquire(n)) {
384 return true;
385 }
386 }
387
388 Thread* thread = Processor::information().getCurrentThread();
389 const bool hasTimeout = timeoutSecs || timeoutUsecs;
390 const Time::Timestamp started = hasTimeout ? Time::getTicks() : 0;
391
392 Time::Timestamp timeout = 0;
393 if (hasTimeout) {
394 const Time::Timestamp maximum = Time::Infinity - 1;
395 if (timeoutSecs > (maximum / Time::Multiplier::Second)) {
396 timeout = maximum;
397 } else {
398 timeout = timeoutSecs * Time::Multiplier::Second;
399 const Time::Timestamp microseconds =
400 timeoutUsecs > (maximum / Time::Multiplier::Microsecond)
401 ? maximum
402 : timeoutUsecs * Time::Multiplier::Microsecond;
403 timeout = microseconds > (maximum - timeout) ? maximum : timeout + microseconds;
404 }
405 }
406
407 Thread::InterruptionReason retainedInterruption =
408 thread ? thread->getInterruptionReason() : Thread::NotInterrupted;
409 if (thread && retainedInterruption != Thread::NotInterrupted) {
410 thread->clearInterruption();
411 }
412
413 size_t remainingSecs = timeoutSecs;
414 size_t remainingUsecs = timeoutUsecs;
415 if (hasTimeout) {
416 const Time::Timestamp remainingMicroseconds =
417 (timeout / Time::Multiplier::Microsecond) +
418 ((timeout % Time::Multiplier::Microsecond) ? 1 : 0);
419 remainingSecs =
420 remainingMicroseconds / (Time::Multiplier::Second / Time::Multiplier::Microsecond);
421 remainingUsecs =
422 remainingMicroseconds % (Time::Multiplier::Second / Time::Multiplier::Microsecond);
423 }
424
425 while (true) {
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;
429 if (acquired) {
430 if (thread && retainedInterruption != Thread::NotInterrupted) {
431 thread->setInterruptionReason(retainedInterruption);
432 }
433 return true;
434 }
435
436 if (error == TimedOut) {
437 if (!hasTimeout) {
438 // This semaphore owns no alarm, so the timeout marker
439 // belongs to an outer wait whose mutex/lifetime state we
440 // are reacquiring. Retain it and finish ownership.
441 retainedInterruption = Thread::InterruptedByTimeout;
442 continue;
443 }
444 if (thread && retainedInterruption != Thread::NotInterrupted) {
445 thread->setInterruptionReason(retainedInterruption);
446 }
447 return false;
448 }
449
450 if (error != Interrupted || !thread ||
451 thread->getInterruptionReason() != Thread::InterruptedBySignal) {
452 return false;
453 }
454
455 if (retainedInterruption != Thread::InterruptedByTimeout) {
456 retainedInterruption = Thread::InterruptedBySignal;
457 }
458 thread->clearInterruption();
459
460 if (!hasTimeout) {
461 continue;
462 }
463
464 if (hasTimeout) {
465 const Time::Timestamp elapsed = Time::getTicks() - started;
466 if (elapsed >= timeout) {
467 thread->setInterruptionReason(retainedInterruption);
468 return false;
469 }
470
471 const Time::Timestamp remaining = timeout - elapsed;
472 const Time::Timestamp remainingMicroseconds =
473 (remaining / Time::Multiplier::Microsecond) +
474 ((remaining % Time::Multiplier::Microsecond) ? 1 : 0);
475 remainingSecs =
476 remainingMicroseconds / (Time::Multiplier::Second / Time::Multiplier::Microsecond);
477 remainingUsecs =
478 remainingMicroseconds % (Time::Multiplier::Second / Time::Multiplier::Microsecond);
479 }
480 }
481 }
482}
483
484bool Semaphore::tryAcquire(size_t n) {
485 const bool mutex = isMutexState(loadState(&magic));
486 if (mutex && n != 1) {
487 ERROR("Mutex acquisition must request exactly one item");
488 return false;
489 }
490
491 if (mutex) {
492 SemaphoreInterruptGuard interrupts(false);
493 ssize_t value = m_Counter;
494
495 if ((value - static_cast<ssize_t>(n)) < 0) {
496 return false;
497 }
498 if (!m_Counter.compareAndSwap(value, value - n)) {
499 return false;
500 }
501
502#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
503 observeMutexTransition(MutexCounterAcquired);
504#endif
505
506 if (!__sync_bool_compare_and_swap(&magic, MutexUnlocked, currentMutexOwner())) {
507 // The binary count and ownership record must move together. Put
508 // the item back if a corrupt ownership state is ever observed.
509 m_Counter += n;
510 ERROR("Mutex acquired with stale ownership state");
511 return false;
512 }
513 } else {
514 // Counting Semaphore transitions remain independent of Mutex
515 // ownership and do not alter interrupt state.
516 ssize_t value = m_Counter;
517 if ((value - static_cast<ssize_t>(n)) < 0) {
518 return false;
519 }
520 if (!m_Counter.compareAndSwap(value, value - n)) {
521 return false;
522 }
523 }
524
525 EMIT_IF(STRICT_LOCK_ORDERING) {
526 // TODO LockManager::acquired(*this);
527 }
528 return true;
529}
530
532 const size_t state = loadState(&magic);
533 assert(state == SemaphoreMagic || isMutexState(state));
534 if (isMutexState(state)) {
535 ERROR("Mutex items cannot be drained");
536 return 0;
537 }
538
539 ssize_t available = m_Counter;
540 while (available > 0) {
541 if (m_Counter.compareAndSwap(available, 0)) {
542 return static_cast<size_t>(available);
543 }
544 available = m_Counter;
545 }
546 return 0;
547}
548
549void Semaphore::release(size_t n) {
550 EMIT_IF(!PEDIGREE_BENCHMARK) {
551 if (!Processor::guardDeviceHardIrqOperation(DeviceHardIrqOperation::SemaphoreRelease)) {
552 return;
553 }
554 }
555
556 size_t state = loadState(&magic);
557 assert(state == SemaphoreMagic || isMutexState(state));
558
559 if (isMutexState(state)) {
560 if (n != 1) {
561 ERROR("Mutex release must return exactly one item");
562 return;
563 }
564
565 {
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");
570 return;
571 }
572
573#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
574 observeMutexTransition(MutexOwnerReleased);
575#endif
576
577 if (!m_Counter.compareAndSwap(0, 1)) {
578 // Do not allow a double release to turn a mutex into a
579 // counting semaphore. Restore ownership so the actual owner
580 // can recover.
581 __sync_bool_compare_and_swap(&magic, MutexUnlocked, owner);
582 ERROR("Mutex release found an invalid binary count");
583 return;
584 }
585 }
586 } else {
587 m_Counter += n;
588 }
589
590 EMIT_IF(THREADS) {
591 // Waiters can request different counts, so wake all and let each retry
592 // the counter predicate under the queue guard.
593 m_Waiters.wakeAllIfWaiting(WaitQueue::WakeReason::Signalled, WaitQueue::Channel(this));
594 }
595
596 EMIT_IF(STRICT_LOCK_ORDERING) {
597 // TODO LockManager::released(*this);
598 }
599}
600
602 return static_cast<ssize_t>(m_Counter);
603}
604
605const void* Semaphore::getDebugMutexOwner() const {
606 const size_t state = loadState(&magic);
607 if (!isMutexState(state) || state == MutexUnlocked) {
608 return nullptr;
609 }
610
611 return reinterpret_cast<const void*>(state & ~MutexStateTag);
612}
613
614void Semaphore::initialiseMutex(bool locked) {
615 assert(loadState(&magic) == SemaphoreMagic);
616 magic = locked ? currentMutexOwner() : MutexUnlocked;
617}
618
619void Semaphore::destroyMutex() {
620 if (loadState(&magic) != MutexUnlocked || m_Counter != 1) {
621 FATAL("Destroying a locked or corrupt Mutex");
622 }
623
624 magic = SemaphoreMagic;
625}
626
627bool Semaphore::mutexOwnedByCurrentThread() const {
628 return loadState(&magic) == currentMutexOwner();
629}
630
631#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
632void Semaphore::setBeforeWaitHook(BeforeWaitHook hook) {
633 __atomic_store_n(&g_BeforeWaitHook, hook, __ATOMIC_RELEASE);
634}
635
636void Semaphore::setMutexTransitionHook(MutexTransitionHook hook) {
637 __atomic_store_n(&g_MutexTransitionHook, hook, __ATOMIC_RELEASE);
638}
639
640size_t Semaphore::getHostedTimeoutCreateCount() {
641 return g_SemaphoreTimeoutCreates;
642}
643
644size_t Semaphore::getHostedTimeoutDestroyCount() {
645 return g_SemaphoreTimeoutDestroys;
646}
647#endif
Definition Event.h:49
virtual Timer * getTimer()=0
static ProcessorInformation & information()
static bool guardDeviceHardIrqOperation(DeviceHardIrqOperation operation)
Definition Processor.h:585
static uintptr_t getBasePointer()
virtual size_t getNumber()
Definition Semaphore.cc:148
virtual size_t serialize(uint8_t *pBuffer)
Definition Semaphore.cc:140
ssize_t getValue()
Definition Semaphore.cc:601
const void * getDebugMutexOwner() const
Definition Semaphore.cc:605
void release(size_t n=1)
Definition Semaphore.cc:549
virtual ~Semaphore()
Definition Semaphore.cc:157
MUST_USE_RESULT bool acquireWithError(size_t n, size_t timeoutSecs, size_t timeoutUsecs, SemaphoreError &error)
Definition Semaphore.cc:360
MUST_USE_RESULT size_t drainAvailable()
Definition Semaphore.cc:531
MUST_USE_RESULT bool acquireForCompletion(size_t n=1, size_t timeoutSecs=0, size_t timeoutUsecs=0)
Definition Semaphore.cc:372
Semaphore(size_t nInitialValue, bool canInterrupt=true)
Definition Semaphore.cc:152
void initialiseMutex(bool locked)
Definition Semaphore.cc:614
bool tryAcquire(size_t n=1)
Definition Semaphore.cc:484
bool acquire(size_t n=1, size_t timeoutSecs=0, size_t timeoutUsecs=0)
Definition Semaphore.cc:355
bool hasActiveTemporarySignalMask()
Definition Thread.cc:2151
@ Continue
No unwind necessary, carry on as normal.
Definition Thread.h:517
void * getKernelStackBase(size_t *size) const
Definition Thread.cc:1080
UnwindType getUnwindState()
Definition Thread.h:535
void cullEvent(Event *pEvent)
Definition Thread.cc:2172
bool retainTemporarySignalWaitInterruptionOrClear()
Definition Thread.cc:2156
bool hasTemporarySignalWaitInterruption()
Definition Thread.cc:2144
bool isTerminationDeferred() const
Definition Thread.h:569
size_t getStateLevel() const
Definition Thread.h:316
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())
Definition WaitQueue.cc:345
@ Dec
Definition Log.h:126
@ Hex
Definition Log.h:124