20#include "pedigree/kernel/errors.h"
21#include "pedigree/kernel/process/Process.h"
22#include "pedigree/kernel/process/Scheduler.h"
23#include "pedigree/kernel/process/WaitQueue.h"
24#include "pedigree/kernel/syscallError.h"
25#include "pedigree/kernel/time/Time.h"
29#include "PosixSubsystem.h"
31#include <pthread-syscalls.h>
37#define FUTEX_REQUEUE 3
38#define FUTEX_CMP_REQUEUE 4
39#define FUTEX_WAKE_OP 5
40#define FUTEX_LOCK_PI 6
41#define FUTEX_UNLOCK_PI 7
42#define FUTEX_TRYLOCK_PI 8
43#define FUTEX_WAIT_BITSET 9
44#define FUTEX_PRIVATE 128
45#define FUTEX_CLOCK_REALTIME 256
48extern void pthread_stub();
49extern char pthread_stub_end;
57 address(
reinterpret_cast<uintptr_t
>(userAddress)) {
76void discardAbsoluteFutexWait(
void* context);
78struct AbsoluteFutexWait {
81 AbsoluteFutexWait* next =
nullptr;
82 void* alarm =
nullptr;
85 bool realtime =
false;
89AbsoluteFutexWait* absoluteFutexHead =
nullptr;
92 return a.owner == b.owner && a.address == b.address;
97 for (
auto* wait = absoluteFutexHead; wait && woken < count; wait = wait->next) {
98 if (!wait->woken && sameFutex(wait->key, key)) {
108int requeueAbsoluteFutexes(
const FutexKey& source,
const FutexKey& destination,
int count) {
110 for (
auto* wait = absoluteFutexHead; wait && moved < count; wait = wait->next) {
111 if (!wait->woken && sameFutex(wait->key, source)) {
112 wait->key = destination;
119void retireAbsoluteFutexWait(AbsoluteFutexWait* wait) {
121 auto** link = &absoluteFutexHead;
122 while (*link != wait)
123 link = &(*link)->next;
125 wait->linked =
false;
129void discardAbsoluteFutexWait(
void* context) {
130 auto* wait =
static_cast<AbsoluteFutexWait*
>(context);
132 auto guard = g_FutexWaiters.acquire();
133 retireAbsoluteFutexWait(wait);
136 void* alarm = wait->alarm;
137 wait->alarm =
nullptr;
139 Time::removeAlarm(alarm);
142AbsoluteFutexWait::~AbsoluteFutexWait() {
143 discardAbsoluteFutexWait(
this);
146int waitAbsoluteFutex(
Process* process,
int* address,
int expected, uintptr_t timeoutAddress,
147 bool privateFutex,
bool realtime) {
148 const bool timed = timeoutAddress != 0;
149 Time::Timestamp deadline = 0;
151 struct timespec timeout = {};
154 SYSCALL_ERROR(BadAddress);
157 if (timeout.tv_sec < 0 || timeout.tv_nsec < 0 || timeout.tv_nsec >= 1000000000) {
158 SYSCALL_ERROR(InvalidArgument);
161 constexpr Time::Timestamp maximumDeadline = 0x7FFFFFFFFFFFFFFFULL;
162 const Time::Timestamp seconds = timeout.tv_sec;
163 deadline = seconds > (maximumDeadline - timeout.tv_nsec) / Time::Multiplier::Second
165 : seconds * Time::Multiplier::Second + timeout.tv_nsec;
170 AbsoluteFutexWait wait;
171 wait.realtime = realtime && timed;
176 sizeof(*address), PosixSubsystem::SafeRead) &&
177 mappings.faultIn(
reinterpret_cast<uintptr_t
>(address),
false);
179 wait.key =
FutexKey(process, address, privateFutex);
180 auto guard = g_FutexWaiters.acquire();
181 uint32_t observed = 0;
183 reinterpret_cast<uintptr_t
>(address), observed);
185 SYSCALL_ERROR(BadAddress);
188 if (observed !=
static_cast<uint32_t
>(expected)) {
189 SYSCALL_ERROR(NoMoreProcesses);
192 wait.next = absoluteFutexHead;
193 absoluteFutexHead = &wait;
197 bool interrupted =
false;
199 WaitQueue::WakeReason reason;
201 auto guard = g_FutexWaiters.acquire();
203 retireAbsoluteFutexWait(&wait);
206 if (interrupted || thread->getInterruptionReason() == Thread::InterruptedBySignal ||
208 retireAbsoluteFutexWait(&wait);
209 SYSCALL_ERROR(Interrupted);
213 const Time::Timestamp now = realtime ? Time::getTimeNanoseconds() : Time::getTicks();
214 if (now >= deadline) {
215 retireAbsoluteFutexWait(&wait);
216 SYSCALL_ERROR(TimedOut);
219 Time::Timestamp duration = deadline - now;
220 const auto remainder = duration % Time::Multiplier::Microsecond;
222 duration += Time::Multiplier::Microsecond - remainder;
223 wait.alarm = Time::addAlarm(duration);
227 reinterpret_cast<uintptr_t
>(address));
229 interrupted = thread->getInterruptionReason() == Thread::InterruptedBySignal ||
230 reason == WaitQueue::WakeReason::Unwinding ||
231 reason == WaitQueue::WakeReason::Terminating;
232 void* alarm = wait.alarm;
233 wait.alarm =
nullptr;
235 Time::removeAlarm(alarm);
236 interrupted |= thread->getInterruptionReason() == Thread::InterruptedBySignal;
245void discardFutexWait(
void* context) {
246 FutexDiscard* discard =
reinterpret_cast<FutexDiscard*
>(context);
247 void* alarm = discard->alarm;
248 discard->alarm =
nullptr;
250 Time::removeAlarm(alarm);
259int posix_futex_wake(
Process* process,
int* uaddr,
int count,
bool privateFutex) {
260 if (!process || !uaddr || count <= 0) {
264 const FutexKey key(process, uaddr, privateFutex);
265 auto guard = g_FutexWaiters.acquire();
267 for (
int i = 0; i < count; ++i) {
268 if (!guard.wakeOne(WaitQueue::WakeReason::Signalled, futexChannel(key))) {
273 woken += wakeAbsoluteFutexes(guard, key, count - woken);
277void posix_futex_clock_changed() {
278 auto guard = g_FutexWaiters.acquire();
279 for (
auto* wait = absoluteFutexHead; wait; wait = wait->next) {
280 if (wait->realtime && !wait->woken)
286bool prepareExitUserAccess(
Process* process, uintptr_t address,
size_t width,
bool write) {
288 if (!current || current->
getParent() != process ||
294 address, width, write ? PosixSubsystem::SafeWrite :
PosixSubsystem::SafeRead) &&
298bool readRobustPointer(
Process* process, uintptr_t address, uintptr_t& value) {
300 return space->tryReadUserPointer(address, value) ||
301 (prepareExitUserAccess(process, address,
sizeof(value),
false) &&
302 space->tryReadUserPointer(address, value));
305void recoverRobustFutex(
Process* process, uintptr_t entry, uintptr_t offset,
size_t ownerId) {
306 if (!entry || (entry & 1)) {
309 uintptr_t address = 0;
310 if (
static_cast<intptr_t
>(offset) >= 0) {
311 if (entry > ~uintptr_t(0) - offset) {
314 address = entry + offset;
316 const uintptr_t magnitude = uintptr_t(0) - offset;
317 if (entry < magnitude) {
320 address = entry - magnitude;
324 uint32_t observed = 0;
326 !(prepareExitUserAccess(process, address,
sizeof(observed),
false) &&
330 constexpr uint32_t OwnerMask = 0x3FFFFFFF;
331 constexpr uint32_t OwnerDied = 0x40000000;
332 constexpr uint32_t Waiters = 0x80000000;
333 for (
size_t attempt = 0; attempt < 32 && (observed & OwnerMask) == ownerId; ++attempt) {
334 const bool hadWaiters = (observed & Waiters) != 0;
335 const uint32_t replacement = (observed & Waiters) | OwnerDied;
336 bool exchanged =
false;
338 !(prepareExitUserAccess(process, address,
sizeof(observed),
true) &&
344 posix_futex_wake(process,
reinterpret_cast<int*
>(address), 1,
false);
352bool posix_clear_child_tid(
Process* process, uintptr_t address) {
359 (prepareExitUserAccess(process, address,
sizeof(uint32_t),
true) &&
363void posix_robust_list_exit(
Thread* thread) {
365 const uintptr_t head = thread->takeRobustList(ownerId);
367 if (!head || !ownerId || !process || ownerId > 0x3FFFFFFF ||
368 head > ~uintptr_t(0) - 2 *
sizeof(uintptr_t)) {
378 uintptr_t offset = 0;
379 uintptr_t pending = 0;
380 if (!space || !readRobustPointer(process, head, entry) ||
381 !readRobustPointer(process, head +
sizeof(uintptr_t), offset) ||
382 !readRobustPointer(process, head + 2 *
sizeof(uintptr_t), pending)) {
386 for (
size_t traversed = 0; traversed < 2048 && (entry & ~uintptr_t(1)) != head; ++traversed) {
388 if (!readRobustPointer(process, entry & ~uintptr_t(1), next)) {
391 if ((entry & ~uintptr_t(1)) != (pending & ~uintptr_t(1))) {
392 recoverRobustFutex(process, entry, offset, ownerId);
396 recoverRobustFutex(process, pending, offset, ownerId);
399int posix_futex(
int* uaddr,
int futex_op,
int val, uintptr_t argument4,
int* uaddr2,
int val3) {
404 ERROR(
"No subsystem for this process!");
408 PT_NOTICE(
"futex(" <<
Hex << uaddr <<
", " << futex_op <<
", " << val <<
", " << argument4 <<
", "
409 << uaddr2 <<
", " << val3 <<
")");
411 const bool realtime = (futex_op & FUTEX_CLOCK_REALTIME) != 0;
412 const bool privateFutex = (futex_op & FUTEX_PRIVATE) != 0;
413 futex_op &= ~(FUTEX_PRIVATE | FUTEX_CLOCK_REALTIME);
414 if (realtime && futex_op != FUTEX_WAIT_BITSET) {
415 SYSCALL_ERROR(Unimplemented);
419 if (
reinterpret_cast<uintptr_t
>(uaddr) %
alignof(
int)) {
420 SYSCALL_ERROR(InvalidArgument);
426 case FUTEX_WAIT_BITSET:
428 SYSCALL_ERROR(InvalidArgument);
431 if (
static_cast<uint32_t
>(val3) != UINT32_MAX) {
433 SYSCALL_ERROR(Unimplemented);
436 return waitAbsoluteFutex(pProcess, uaddr, val, argument4, privateFutex, realtime);
439 PT_NOTICE(
" -> FUTEX_WAIT");
441 const struct timespec* userTimeout =
reinterpret_cast<const struct timespec*
>(argument4);
442 struct timespec timeout = {};
444 SYSCALL_ERROR(BadAddress);
448 Time::Timestamp timeoutNanoseconds = Time::Infinity;
450 if (timeout.tv_sec < 0 || timeout.tv_nsec < 0 ||
451 timeout.tv_nsec >=
static_cast<decltype(timeout.tv_nsec)
>(Time::Multiplier::Second)) {
452 SYSCALL_ERROR(InvalidArgument);
456 const Time::Timestamp nanoseconds =
static_cast<Time::Timestamp
>(timeout.tv_nsec);
457 const Time::Timestamp seconds =
static_cast<Time::Timestamp
>(timeout.tv_sec);
458 if (seconds > (Time::Infinity - nanoseconds) / Time::Multiplier::Second) {
459 SYSCALL_ERROR(InvalidArgument);
463 timeoutNanoseconds = seconds * Time::Multiplier::Second + nanoseconds;
468 uint32_t observed = 0;
469 bool accessible =
false;
474 sizeof(*uaddr), PosixSubsystem::SafeRead) &&
475 mappings.faultIn(
reinterpret_cast<uintptr_t
>(uaddr),
false);
477 key =
FutexKey(pProcess, uaddr, privateFutex);
481 auto queueGuard = g_FutexWaiters.acquire();
484 reinterpret_cast<uintptr_t
>(uaddr), observed);
490 SYSCALL_ERROR(BadAddress);
492 }
else if (observed !=
static_cast<uint32_t
>(val)) {
493 SYSCALL_ERROR(NoMoreProcesses);
495 }
else if (userTimeout && !timeoutNanoseconds) {
496 SYSCALL_ERROR(TimedOut);
499 void* pAlarm =
nullptr;
501 pAlarm = Time::addAlarm(timeoutNanoseconds);
503 FutexDiscard discard = {pAlarm};
506 PT_NOTICE(
" -> waiting...");
507 WaitQueue::WakeReason wakeReason =
508 guard.
wait(futexChannel(key), Thread::FutexWait,
509 reinterpret_cast<uintptr_t
>(__builtin_return_address(0)));
510 PT_NOTICE(
" -> waiting complete!");
512 const Thread::InterruptionReason interruption = pThread->getInterruptionReason();
513 discardFutexWait(&discard);
516 if (wakeReason != WaitQueue::WakeReason::Signalled) {
517 if (userTimeout && interruption == Thread::InterruptedByTimeout) {
518 SYSCALL_ERROR(TimedOut);
520 SYSCALL_ERROR(Interrupted);
529 PT_NOTICE(
" -> FUTEX_WAKE");
532 SYSCALL_ERROR(InvalidArgument);
539 PosixSubsystem::SafeRead)) {
540 SYSCALL_ERROR(BadAddress);
544 r = posix_futex_wake(pProcess, uaddr, val, privateFutex);
549 case FUTEX_REQUEUE: {
550 PT_NOTICE(
" -> FUTEX_REQUEUE");
552 const uint32_t rawRequeueCount =
static_cast<uint32_t
>(argument4);
553 if (val < 0 || rawRequeueCount >
static_cast<uint32_t
>(INT_MAX)) {
554 SYSCALL_ERROR(InvalidArgument);
558 const int requeueCount =
static_cast<int>(rawRequeueCount);
559 if (
reinterpret_cast<uintptr_t
>(uaddr2) %
alignof(int)) {
560 SYSCALL_ERROR(InvalidArgument);
566 PosixSubsystem::SafeRead) ||
568 PosixSubsystem::SafeRead)) {
569 SYSCALL_ERROR(BadAddress);
574 const FutexKey key(pProcess, uaddr, privateFutex);
575 const FutexKey destinationKey(pProcess, uaddr2, privateFutex);
576 auto guard = g_FutexWaiters.acquire();
578 while (woken < val && guard.wakeOne(WaitQueue::WakeReason::Signalled, futexChannel(key)))
580 woken += wakeAbsoluteFutexes(guard, key, val - woken);
582 futexChannel(key), 0, futexChannel(destinationKey),
static_cast<size_t>(requeueCount)));
583 r = woken + moved + requeueAbsoluteFutexes(key, destinationKey, requeueCount - moved);
584 PT_NOTICE(
" -> affected " <<
Dec << r <<
" threads.");
589 PT_NOTICE(
" -> unsupported futex operation");
590 SYSCALL_ERROR(Unimplemented);
594 PT_NOTICE(
" -> " <<
Dec << r);
604 if (!pOldPosixThread) {
610 pNewPosixThread->pThread = newThread;
611 pNewPosixThread->returnValue = 0;
617 size_t key = it.key();
621 pNewPosixThread->m_ThreadKeys.
set(key);
637void pedigree_init_pthreads() {
638 PT_NOTICE(
"init_pthreads");
646 reinterpret_cast<void*
>(pthread_stub),
647 (
reinterpret_cast<uintptr_t
>(&pthread_stub_end) -
reinterpret_cast<uintptr_t
>(pthread_stub)));
658 ERROR(
"No subsystem for this process!");
663 pPosixThread->pThread = pThread;
664 pPosixThread->returnValue = 0;
668void* posix_pedigree_create_waiter() {
669 PT_NOTICE(
"posix_pedigree_create_waiter");
674 ERROR(
"No subsystem for this process!");
687int posix_pedigree_thread_wait_for(
void*
waiter) {
688 PT_NOTICE(
"posix_pedigree_thread_wait_for");
693 ERROR(
"No subsystem for this process!");
706 SYSCALL_ERROR(Deadlock);
714 FATAL(
"POSIX thread-waiter completion barrier failed.");
720int posix_pedigree_thread_trigger(
void*
waiter) {
721 PT_NOTICE(
"posix_pedigree_thread_trigger");
726 ERROR(
"No subsystem for this process!");
741void posix_pedigree_destroy_waiter(
void*
waiter) {
742 PT_NOTICE(
"posix_pedigree_destroy_waiter");
747 ERROR(
"No subsystem for this process!");
759pid_t posix_gettid(
bool linuxAbi) {
766pid_t posix_set_tid_address(
int* tidptr,
bool linuxAbi) {
Memory-mapped file interface.
static uintptr_t getTrampoline()
static uintptr_t getSecondaryTrampoline()
static MemoryMapManager & instance()
Tree< size_t, PosixThreadKey * > m_ThreadData
size_t lastDataKey
Last data key that was allocated (for the bitmap)
size_t nextDataKey
Next data key available.
bool addThreadData(size_t key, PosixThreadKey *info)
static bool copyFromUser(void *destination, const void *source, size_t count, size_t elementSize=1)
void * insertThreadWaiter(Semaphore *waiter)
PosixThread * getThread(size_t n)
void insertThread(size_t n, PosixThread *thread)
static bool checkAddress(uintptr_t addr, size_t extent, size_t flags)
Semaphore * getThreadWaiter(void *n)
void removeThreadWaiter(void *n)
VirtualAddressSpace * getAddressSpace()
static bool getInterrupts()
static ProcessorInformation & information()
static bool inDeviceHardIrq()
MUST_USE_RESULT bool acquireForCompletion(size_t n=1, size_t timeoutSecs=0, size_t timeoutUsecs=0)
@ Continue
No unwind necessary, carry on as normal.
UnwindType getUnwindState()
bool retainTemporarySignalWaitInterruptionOrClear()
void setClearChildTid(uintptr_t address)
Process * getParent() const
size_t getUserspaceTaskId(const UserspacePidNamespace *space=nullptr) const
An iterator applicable for many data structures.
static const size_t RuntimeMapping
virtual bool tryWriteUser32(uintptr_t address, uint32_t value)
static const size_t Shared
virtual bool tryCompareExchangeUser32(uintptr_t address, uint32_t &expected, uint32_t desired, bool &exchanged)
static const size_t Write
static const size_t Execute
virtual bool tryReadUser32(uintptr_t address, uint32_t &value)
MUST_USE_RESULT WakeReason wait(const Channel &channel=Channel(), size_t debugState=0, uintptr_t debugAddress=0, StackDiscardCleanup onStackDiscard=nullptr, void *stackDiscardContext=nullptr)
size_t wakeAndRequeue(const Channel &source, size_t wakeCount, const Channel &destination, size_t requeueCount)