The Pedigree Project 0.1
pthread-syscalls.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/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"
26
27#include <limits.h>
28
29#include "PosixSubsystem.h"
31#include <pthread-syscalls.h>
32
34#define FUTEX_WAIT 0
35#define FUTEX_WAKE 1
36#define FUTEX_FD 2
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
46
47extern "C" {
48extern void pthread_stub();
49extern char pthread_stub_end;
50}
51
52struct FutexKey {
53 FutexKey() : owner(0), address(0) {}
54
55 FutexKey(Process* process, int* userAddress, bool privateFutex = true)
56 : owner(reinterpret_cast<uintptr_t>(process->getAddressSpace())),
57 address(reinterpret_cast<uintptr_t>(userAddress)) {
58 uintptr_t identity = 0;
59 size_t offset = 0;
60 if (!privateFutex &&
61 MemoryMapManager::instance().sharedBacking(process, address, identity, offset)) {
62 // Address-space objects are aligned; odd owners identify persistent
63 // file tokens, whose lifetime is independent of the mapping and File.
64 owner = (identity << 1) | 1;
65 address = offset;
66 }
67 }
68
69 uintptr_t owner;
70 uintptr_t address;
71};
72
73static WaitQueue g_FutexWaiters;
74
75namespace {
76void discardAbsoluteFutexWait(void* context);
77
78struct AbsoluteFutexWait {
79 ~AbsoluteFutexWait();
80 FutexKey key;
81 AbsoluteFutexWait* next = nullptr;
82 void* alarm = nullptr;
83 bool linked = false;
84 bool woken = false;
85 bool realtime = false;
86 Thread::StackDiscardScope discardScope{&discardAbsoluteFutexWait, this};
87};
88
89AbsoluteFutexWait* absoluteFutexHead = nullptr;
90
91bool sameFutex(const FutexKey& a, const FutexKey& b) {
92 return a.owner == b.owner && a.address == b.address;
93}
94
95int wakeAbsoluteFutexes(WaitQueue::Guard& guard, const FutexKey& key, int count) {
96 int woken = 0;
97 for (auto* wait = absoluteFutexHead; wait && woken < count; wait = wait->next) {
98 if (!wait->woken && sameFutex(wait->key, key)) {
99 // Retain a wake while the owner cancels or re-arms its clock alarm.
100 wait->woken = true;
101 guard.wakeOne(WaitQueue::WakeReason::Signalled, WaitQueue::Channel(wait));
102 ++woken;
103 }
104 }
105 return woken;
106}
107
108int requeueAbsoluteFutexes(const FutexKey& source, const FutexKey& destination, int count) {
109 int moved = 0;
110 for (auto* wait = absoluteFutexHead; wait && moved < count; wait = wait->next) {
111 if (!wait->woken && sameFutex(wait->key, source)) {
112 wait->key = destination;
113 ++moved;
114 }
115 }
116 return moved;
117}
118
119void retireAbsoluteFutexWait(AbsoluteFutexWait* wait) {
120 if (wait->linked) {
121 auto** link = &absoluteFutexHead;
122 while (*link != wait)
123 link = &(*link)->next;
124 *link = wait->next;
125 wait->linked = false;
126 }
127}
128
129void discardAbsoluteFutexWait(void* context) {
130 auto* wait = static_cast<AbsoluteFutexWait*>(context);
131 {
132 auto guard = g_FutexWaiters.acquire();
133 retireAbsoluteFutexWait(wait);
134 }
135 // Alarm cancellation drains admitted event deliveries and can block.
136 void* alarm = wait->alarm;
137 wait->alarm = nullptr;
138 if (alarm)
139 Time::removeAlarm(alarm);
140}
141
142AbsoluteFutexWait::~AbsoluteFutexWait() {
143 discardAbsoluteFutexWait(this);
144}
145
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;
150 if (timed) {
151 struct timespec timeout = {};
152 if (!PosixSubsystem::copyFromUser(&timeout, reinterpret_cast<void*>(timeoutAddress),
153 sizeof(timeout))) {
154 SYSCALL_ERROR(BadAddress);
155 return -1;
156 }
157 if (timeout.tv_sec < 0 || timeout.tv_nsec < 0 || timeout.tv_nsec >= 1000000000) {
158 SYSCALL_ERROR(InvalidArgument);
159 return -1;
160 }
161 constexpr Time::Timestamp maximumDeadline = 0x7FFFFFFFFFFFFFFFULL;
162 const Time::Timestamp seconds = timeout.tv_sec;
163 deadline = seconds > (maximumDeadline - timeout.tv_nsec) / Time::Multiplier::Second
164 ? maximumDeadline
165 : seconds * Time::Multiplier::Second + timeout.tv_nsec;
166 }
167
168 Thread* thread = Processor::information().getCurrentThread();
170 AbsoluteFutexWait wait;
171 wait.realtime = realtime && timed;
172 {
174 MemoryMapManager::OperationGuard mappingGuard(mappings);
175 bool accessible = PosixSubsystem::checkAddress(reinterpret_cast<uintptr_t>(address),
176 sizeof(*address), PosixSubsystem::SafeRead) &&
177 mappings.faultIn(reinterpret_cast<uintptr_t>(address), false);
178 if (accessible)
179 wait.key = FutexKey(process, address, privateFutex);
180 auto guard = g_FutexWaiters.acquire();
181 uint32_t observed = 0;
182 accessible = accessible && process->getAddressSpace()->tryReadUser32(
183 reinterpret_cast<uintptr_t>(address), observed);
184 if (!accessible) {
185 SYSCALL_ERROR(BadAddress);
186 return -1;
187 }
188 if (observed != static_cast<uint32_t>(expected)) {
189 SYSCALL_ERROR(NoMoreProcesses); // EAGAIN precedes deadline expiry.
190 return -1;
191 }
192 wait.next = absoluteFutexHead;
193 absoluteFutexHead = &wait;
194 wait.linked = true;
195 }
196
197 bool interrupted = false;
198 for (;;) {
199 WaitQueue::WakeReason reason;
200 {
201 auto guard = g_FutexWaiters.acquire();
202 if (wait.woken) {
203 retireAbsoluteFutexWait(&wait);
204 return 0;
205 }
206 if (interrupted || thread->getInterruptionReason() == Thread::InterruptedBySignal ||
207 thread->getUnwindState() != Thread::Continue) {
208 retireAbsoluteFutexWait(&wait);
209 SYSCALL_ERROR(Interrupted);
210 return -1;
211 }
212 if (timed) {
213 const Time::Timestamp now = realtime ? Time::getTimeNanoseconds() : Time::getTicks();
214 if (now >= deadline) {
215 retireAbsoluteFutexWait(&wait);
216 SYSCALL_ERROR(TimedOut);
217 return -1;
218 }
219 Time::Timestamp duration = deadline - now;
220 const auto remainder = duration % Time::Multiplier::Microsecond;
221 if (remainder)
222 duration += Time::Multiplier::Microsecond - remainder;
223 wait.alarm = Time::addAlarm(duration);
224 }
225 // A private channel survives requeue changes to the futex identity.
226 reason = guard.wait(WaitQueue::Channel(&wait), Thread::FutexWait,
227 reinterpret_cast<uintptr_t>(address));
228 }
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;
234 if (alarm)
235 Time::removeAlarm(alarm);
236 interrupted |= thread->getInterruptionReason() == Thread::InterruptedBySignal;
238 }
239}
240
241struct FutexDiscard {
242 void* alarm;
243};
244
245void discardFutexWait(void* context) {
246 FutexDiscard* discard = reinterpret_cast<FutexDiscard*>(context);
247 void* alarm = discard->alarm;
248 discard->alarm = nullptr;
249 if (alarm) {
250 Time::removeAlarm(alarm);
251 }
252}
253} // namespace
254
255static WaitQueue::Channel futexChannel(const FutexKey& key) {
256 return WaitQueue::Channel(reinterpret_cast<const void*>(key.owner), key.address);
257}
258
259int posix_futex_wake(Process* process, int* uaddr, int count, bool privateFutex) {
260 if (!process || !uaddr || count <= 0) {
261 return 0;
262 }
263
264 const FutexKey key(process, uaddr, privateFutex);
265 auto guard = g_FutexWaiters.acquire();
266 int woken = 0;
267 for (int i = 0; i < count; ++i) {
268 if (!guard.wakeOne(WaitQueue::WakeReason::Signalled, futexChannel(key))) {
269 break;
270 }
271 ++woken;
272 }
273 woken += wakeAbsoluteFutexes(guard, key, count - woken);
274 return woken;
275}
276
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)
281 guard.wakeOne(WaitQueue::WakeReason::Spurious, WaitQueue::Channel(wait));
282 }
283}
284
285namespace {
286bool prepareExitUserAccess(Process* process, uintptr_t address, size_t width, bool write) {
287 Thread* current = Processor::information().getCurrentThread();
288 if (!current || current->getParent() != process ||
289 &Processor::information().getVirtualAddressSpace() != process->getAddressSpace() ||
290 !Processor::getInterrupts() || Processor::inDeviceHardIrq() || (address % width)) {
291 return false;
292 }
294 address, width, write ? PosixSubsystem::SafeWrite : PosixSubsystem::SafeRead) &&
295 MemoryMapManager::instance().faultIn(address, write);
296}
297
298bool readRobustPointer(Process* process, uintptr_t address, uintptr_t& value) {
299 VirtualAddressSpace* space = process->getAddressSpace();
300 return space->tryReadUserPointer(address, value) ||
301 (prepareExitUserAccess(process, address, sizeof(value), false) &&
302 space->tryReadUserPointer(address, value));
303}
304
305void recoverRobustFutex(Process* process, uintptr_t entry, uintptr_t offset, size_t ownerId) {
306 if (!entry || (entry & 1)) {
307 return; // PI-tagged robust entries require the separate PI protocol.
308 }
309 uintptr_t address = 0;
310 if (static_cast<intptr_t>(offset) >= 0) {
311 if (entry > ~uintptr_t(0) - offset) {
312 return;
313 }
314 address = entry + offset;
315 } else {
316 const uintptr_t magnitude = uintptr_t(0) - offset;
317 if (entry < magnitude) {
318 return;
319 }
320 address = entry - magnitude;
321 }
322
323 VirtualAddressSpace* space = process->getAddressSpace();
324 uint32_t observed = 0;
325 if (!space->tryReadUser32(address, observed) &&
326 !(prepareExitUserAccess(process, address, sizeof(observed), false) &&
327 space->tryReadUser32(address, observed))) {
328 return;
329 }
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;
337 if (!space->tryCompareExchangeUser32(address, observed, replacement, exchanged) &&
338 !(prepareExitUserAccess(process, address, sizeof(observed), true) &&
339 space->tryCompareExchangeUser32(address, observed, replacement, exchanged))) {
340 return;
341 }
342 if (exchanged) {
343 if (hadWaiters) {
344 posix_futex_wake(process, reinterpret_cast<int*>(address), 1, false);
345 }
346 return;
347 }
348 }
349}
350} // namespace
351
352bool posix_clear_child_tid(Process* process, uintptr_t address) {
353 if (!process || !process->getAddressSpace()) {
354 return false;
355 }
357 VirtualAddressSpace* space = process->getAddressSpace();
358 return space->tryWriteUser32(address, 0) ||
359 (prepareExitUserAccess(process, address, sizeof(uint32_t), true) &&
360 space->tryWriteUser32(address, 0));
361}
362
363void posix_robust_list_exit(Thread* thread) {
364 size_t ownerId = 0;
365 const uintptr_t head = thread->takeRobustList(ownerId);
366 Process* process = thread->getParent();
367 if (!head || !ownerId || !process || ownerId > 0x3FFFFFFF ||
368 head > ~uintptr_t(0) - 2 * sizeof(uintptr_t)) {
369 return;
370 }
371
372 // Ordinary shutdown runs before leaving the owner's address space, allowing
373 // fallible demand/COW resolution. Foreign destructor cleanup uses only the
374 // no-fault aliases; it must not replace another process's active mappings.
376 VirtualAddressSpace* space = process->getAddressSpace();
377 uintptr_t entry = 0;
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)) {
383 return;
384 }
385
386 for (size_t traversed = 0; traversed < 2048 && (entry & ~uintptr_t(1)) != head; ++traversed) {
387 uintptr_t next = 0;
388 if (!readRobustPointer(process, entry & ~uintptr_t(1), next)) {
389 break;
390 }
391 if ((entry & ~uintptr_t(1)) != (pending & ~uintptr_t(1))) {
392 recoverRobustFutex(process, entry, offset, ownerId);
393 }
394 entry = next;
395 }
396 recoverRobustFutex(process, pending, offset, ownerId);
397}
398
399int posix_futex(int* uaddr, int futex_op, int val, uintptr_t argument4, int* uaddr2, int val3) {
400 Thread* pThread = Processor::information().getCurrentThread();
401 Process* pProcess = pThread->getParent();
402 PosixSubsystem* pSubsystem = static_cast<PosixSubsystem*>(pProcess->getSubsystem());
403 if (!pSubsystem) {
404 ERROR("No subsystem for this process!");
405 return -1;
406 }
407
408 PT_NOTICE("futex(" << Hex << uaddr << ", " << futex_op << ", " << val << ", " << argument4 << ", "
409 << uaddr2 << ", " << val3 << ")");
410
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);
416 return -1;
417 }
418
419 if (reinterpret_cast<uintptr_t>(uaddr) % alignof(int)) {
420 SYSCALL_ERROR(InvalidArgument);
421 return -1;
422 }
423 int r = 0;
424
425 switch (futex_op) {
426 case FUTEX_WAIT_BITSET:
427 if (!val3) {
428 SYSCALL_ERROR(InvalidArgument);
429 return -1;
430 }
431 if (static_cast<uint32_t>(val3) != UINT32_MAX) {
432 // Selective bitset wake remains outside the implemented contract.
433 SYSCALL_ERROR(Unimplemented);
434 return -1;
435 }
436 return waitAbsoluteFutex(pProcess, uaddr, val, argument4, privateFutex, realtime);
437
438 case FUTEX_WAIT: {
439 PT_NOTICE(" -> FUTEX_WAIT");
440
441 const struct timespec* userTimeout = reinterpret_cast<const struct timespec*>(argument4);
442 struct timespec timeout = {};
443 if (userTimeout && !PosixSubsystem::copyFromUser(&timeout, userTimeout, sizeof(timeout))) {
444 SYSCALL_ERROR(BadAddress);
445 return -1;
446 }
447
448 Time::Timestamp timeoutNanoseconds = Time::Infinity;
449 if (userTimeout) {
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);
453 return -1;
454 }
455
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);
460 return -1;
461 }
462
463 timeoutNanoseconds = seconds * Time::Multiplier::Second + nanoseconds;
464 }
465
467 FutexKey key;
468 uint32_t observed = 0;
469 bool accessible = false;
470 auto guard = [&]() {
472 MemoryMapManager::OperationGuard mappingGuard(mappings);
473 accessible = PosixSubsystem::checkAddress(reinterpret_cast<uintptr_t>(uaddr),
474 sizeof(*uaddr), PosixSubsystem::SafeRead) &&
475 mappings.faultIn(reinterpret_cast<uintptr_t>(uaddr), false);
476 if (accessible) {
477 key = FutexKey(pProcess, uaddr, privateFutex);
478 }
479 // Materialization may sleep. Only the final atomic comparison runs
480 // under the queue lock, which also serializes wake and enrolment.
481 auto queueGuard = g_FutexWaiters.acquire();
482 if (accessible) {
483 accessible = pProcess->getAddressSpace()->tryReadUser32(
484 reinterpret_cast<uintptr_t>(uaddr), observed);
485 }
486 return queueGuard;
487 }();
488
489 if (!accessible) {
490 SYSCALL_ERROR(BadAddress);
491 r = -1;
492 } else if (observed != static_cast<uint32_t>(val)) {
493 SYSCALL_ERROR(NoMoreProcesses); // EAGAIN
494 r = -1;
495 } else if (userTimeout && !timeoutNanoseconds) {
496 SYSCALL_ERROR(TimedOut);
497 r = -1;
498 } else {
499 void* pAlarm = nullptr;
500 if (userTimeout) {
501 pAlarm = Time::addAlarm(timeoutNanoseconds);
502 }
503 FutexDiscard discard = {pAlarm};
504 Thread::StackDiscardScope discardScope(pAlarm ? &discardFutexWait : nullptr, &discard);
505
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!");
511
512 const Thread::InterruptionReason interruption = pThread->getInterruptionReason();
513 discardFutexWait(&discard);
515
516 if (wakeReason != WaitQueue::WakeReason::Signalled) {
517 if (userTimeout && interruption == Thread::InterruptedByTimeout) {
518 SYSCALL_ERROR(TimedOut);
519 } else {
520 SYSCALL_ERROR(Interrupted);
521 }
522 r = -1;
523 }
524 }
525 break;
526 }
527
528 case FUTEX_WAKE: {
529 PT_NOTICE(" -> FUTEX_WAKE");
530
531 if (val < 0) {
532 SYSCALL_ERROR(InvalidArgument);
533 r = -1;
534 break;
535 }
536
538 if (!PosixSubsystem::checkAddress(reinterpret_cast<uintptr_t>(uaddr), sizeof(*uaddr),
539 PosixSubsystem::SafeRead)) {
540 SYSCALL_ERROR(BadAddress);
541 r = -1;
542 break;
543 }
544 r = posix_futex_wake(pProcess, uaddr, val, privateFutex);
545
546 break;
547 }
548
549 case FUTEX_REQUEUE: {
550 PT_NOTICE(" -> FUTEX_REQUEUE");
551
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);
555 r = -1;
556 break;
557 }
558 const int requeueCount = static_cast<int>(rawRequeueCount);
559 if (reinterpret_cast<uintptr_t>(uaddr2) % alignof(int)) {
560 SYSCALL_ERROR(InvalidArgument);
561 r = -1;
562 break;
563 }
565 if (!PosixSubsystem::checkAddress(reinterpret_cast<uintptr_t>(uaddr), sizeof(*uaddr),
566 PosixSubsystem::SafeRead) ||
567 !PosixSubsystem::checkAddress(reinterpret_cast<uintptr_t>(uaddr2), sizeof(*uaddr2),
568 PosixSubsystem::SafeRead)) {
569 SYSCALL_ERROR(BadAddress);
570 r = -1;
571 break;
572 }
573
574 const FutexKey key(pProcess, uaddr, privateFutex);
575 const FutexKey destinationKey(pProcess, uaddr2, privateFutex);
576 auto guard = g_FutexWaiters.acquire();
577 int woken = 0;
578 while (woken < val && guard.wakeOne(WaitQueue::WakeReason::Signalled, futexChannel(key)))
579 ++woken;
580 woken += wakeAbsoluteFutexes(guard, key, val - woken);
581 const int moved = static_cast<int>(guard.wakeAndRequeue(
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.");
585 break;
586 }
587
588 default:
589 PT_NOTICE(" -> unsupported futex operation");
590 SYSCALL_ERROR(Unimplemented);
591 r = -1;
592 }
593
594 PT_NOTICE(" -> " << Dec << r);
595 return r;
596}
597
601void pedigree_copy_posix_thread(Thread* origThread, PosixSubsystem* origSubsystem,
602 Thread* newThread, PosixSubsystem* newSubsystem) {
603 PosixSubsystem::PosixThread* pOldPosixThread = origSubsystem->getThread(origThread->getId());
604 if (!pOldPosixThread) {
605 // Nothing to see here.
606 return;
607 }
608
610 pNewPosixThread->pThread = newThread;
611 pNewPosixThread->returnValue = 0;
612
613 // Copy thread-specific data across.
615 pOldPosixThread->m_ThreadData.begin();
616 it != pOldPosixThread->m_ThreadData.end(); ++it) {
617 size_t key = it.key();
618 PosixSubsystem::PosixThreadKey* data = it.value();
619
620 pNewPosixThread->addThreadData(key, data);
621 pNewPosixThread->m_ThreadKeys.set(key);
622 }
623
624 pNewPosixThread->lastDataKey = pOldPosixThread->lastDataKey;
625 pNewPosixThread->nextDataKey = pOldPosixThread->nextDataKey;
626
627 newSubsystem->insertThread(newThread->getId(), pNewPosixThread);
628}
629
637void pedigree_init_pthreads() {
638 PT_NOTICE("init_pthreads");
639 // Make sure we can write to the trampoline area.
640 Processor::information().getVirtualAddressSpace().setFlags(
641 reinterpret_cast<void*>(Event::getTrampoline()), VirtualAddressSpace::Write |
644 MemoryCopy(
645 reinterpret_cast<void*>(Event::getSecondaryTrampoline()),
646 reinterpret_cast<void*>(pthread_stub),
647 (reinterpret_cast<uintptr_t>(&pthread_stub_end) - reinterpret_cast<uintptr_t>(pthread_stub)));
648 Processor::information().getVirtualAddressSpace().setFlags(
649 reinterpret_cast<void*>(Event::getTrampoline()), VirtualAddressSpace::Execute |
652
653 // Make sure the main thread is actually known.
654 Thread* pThread = Processor::information().getCurrentThread();
655 Process* pProcess = pThread->getParent();
656 PosixSubsystem* pSubsystem = static_cast<PosixSubsystem*>(pProcess->getSubsystem());
657 if (!pSubsystem) {
658 ERROR("No subsystem for this process!");
659 return;
660 }
661
663 pPosixThread->pThread = pThread;
664 pPosixThread->returnValue = 0;
665 pSubsystem->insertThread(pThread->getId(), pPosixThread);
666}
667
668void* posix_pedigree_create_waiter() {
669 PT_NOTICE("posix_pedigree_create_waiter");
670
671 Process* pProcess = Processor::information().getCurrentThread()->getParent();
672 PosixSubsystem* pSubsystem = static_cast<PosixSubsystem*>(pProcess->getSubsystem());
673 if (!pSubsystem) {
674 ERROR("No subsystem for this process!");
675 return 0;
676 }
677
678 Semaphore* sem = new Semaphore(0);
679 void* descriptor = pSubsystem->insertThreadWaiter(sem);
680 if (!descriptor) {
681 delete sem;
682 }
683
684 return descriptor;
685}
686
687int posix_pedigree_thread_wait_for(void* waiter) {
688 PT_NOTICE("posix_pedigree_thread_wait_for");
689
690 Process* pProcess = Processor::information().getCurrentThread()->getParent();
691 PosixSubsystem* pSubsystem = static_cast<PosixSubsystem*>(pProcess->getSubsystem());
692 if (!pSubsystem) {
693 ERROR("No subsystem for this process!");
694 return -1;
695 }
696
697 Semaphore* sem = pSubsystem->getThreadWaiter(waiter);
698 if (!sem) {
699 return -1;
700 }
701
702 // Deadlock detection - don't wait if nothing can wake this waiter.
705 if (pProcess->getNumThreads() <= 1) {
706 SYSCALL_ERROR(Deadlock);
707 return -1;
708 }
709
710 // This descriptor remains owned by the subsystem until its matching
711 // trigger. A signal may run while blocked, but cannot abandon the waiter
712 // storage or consume the eventual notification.
713 if (!sem->acquireForCompletion()) {
714 FATAL("POSIX thread-waiter completion barrier failed.");
715 }
716
717 return 0;
718}
719
720int posix_pedigree_thread_trigger(void* waiter) {
721 PT_NOTICE("posix_pedigree_thread_trigger");
722
723 Process* pProcess = Processor::information().getCurrentThread()->getParent();
724 PosixSubsystem* pSubsystem = static_cast<PosixSubsystem*>(pProcess->getSubsystem());
725 if (!pSubsystem) {
726 ERROR("No subsystem for this process!");
727 return 0;
728 }
729
730 Semaphore* sem = pSubsystem->getThreadWaiter(waiter);
731 if (!sem)
732 return 0;
733 if (sem->getValue())
734 return 0; // Nothing to wake up.
735
736 // Wake up a waiter.
737 sem->release();
738 return 1;
739}
740
741void posix_pedigree_destroy_waiter(void* waiter) {
742 PT_NOTICE("posix_pedigree_destroy_waiter");
743
744 Process* pProcess = Processor::information().getCurrentThread()->getParent();
745 PosixSubsystem* pSubsystem = static_cast<PosixSubsystem*>(pProcess->getSubsystem());
746 if (!pSubsystem) {
747 ERROR("No subsystem for this process!");
748 return;
749 }
750
751 Semaphore* sem = pSubsystem->getThreadWaiter(waiter);
752 if (!sem) {
753 return;
754 }
755 pSubsystem->removeThreadWaiter(waiter);
756 delete sem;
757}
758
759pid_t posix_gettid(bool linuxAbi) {
760 // Go caches this value before creating another thread, so it must not
761 // change when the process transitions from one thread to several.
762 Thread* current = Processor::information().getCurrentThread();
763 return linuxAbi ? current->getUserspaceTaskId() : current->getId();
764}
765
766pid_t posix_set_tid_address(int* tidptr, bool linuxAbi) {
767 Thread* thread = Processor::information().getCurrentThread();
768 thread->setClearChildTid(reinterpret_cast<uintptr_t>(tidptr));
769 return linuxAbi ? thread->getUserspaceTaskId() : thread->getId();
770}
Memory-mapped file interface.
static uintptr_t getTrampoline()
Definition Event.cc:201
static uintptr_t getSecondaryTrampoline()
Definition Event.cc:209
void set(size_t n)
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)
Process * getParent()
Definition Process.h:620
VirtualAddressSpace * getAddressSpace()
Definition Process.h:530
size_t getNumThreads()
Definition Process.cc:1380
static bool getInterrupts()
static ProcessorInformation & information()
static bool inDeviceHardIrq()
Definition Processor.h:581
ssize_t getValue()
Definition Semaphore.cc:601
void release(size_t n=1)
Definition Semaphore.cc:549
MUST_USE_RESULT bool acquireForCompletion(size_t n=1, size_t timeoutSecs=0, size_t timeoutUsecs=0)
Definition Semaphore.cc:372
@ Continue
No unwind necessary, carry on as normal.
Definition Thread.h:517
UnwindType getUnwindState()
Definition Thread.h:535
bool retainTemporarySignalWaitInterruptionOrClear()
Definition Thread.cc:2156
void setClearChildTid(uintptr_t address)
Definition Thread.cc:653
Process * getParent() const
Definition Thread.h:340
size_t getId()
Definition Thread.h:465
size_t getUserspaceTaskId(const UserspacePidNamespace *space=nullptr) const
Definition Thread.cc:3743
An iterator applicable for many data structures.
Definition Iterator.h:147
virtual bool tryWriteUser32(uintptr_t address, uint32_t value)
virtual bool tryCompareExchangeUser32(uintptr_t address, uint32_t &expected, uint32_t desired, bool &exchanged)
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)
Definition WaitQueue.cc:104
size_t wakeAndRequeue(const Channel &source, size_t wakeCount, const Channel &destination, size_t requeueCount)
Definition WaitQueue.cc:183
@ Dec
Definition Log.h:126
@ Hex
Definition Log.h:124