| 542 | } |
| 543 | |
| 544 | void OSExitThread(sint32 exitValue) |
| 545 | { |
| 546 | PPCInterpreter_t* hCPU = PPCInterpreter_getCurrentInstance(); |
| 547 | hCPU->gpr[3] = exitValue; |
| 548 | OSThread_t* currentThread = coreinit::OSGetCurrentThread(); |
| 549 | |
| 550 | // thread cleanup callback |
| 551 | if (currentThread->cleanupCallback) |
| 552 | { |
| 553 | currentThread->stateFlags = _swapEndianU32(_swapEndianU32(currentThread->stateFlags) | 0x00000001); |
| 554 | PPCCoreCallback(currentThread->cleanupCallback.GetMPTR(), currentThread, currentThread->stackEnd); |
| 555 | } |
| 556 | // cpp exception cleanup |
| 557 | if (gCoreinitData->__cpp_exception_cleanup_ptr != 0 && currentThread->crt.eh_globals != nullptr) |
| 558 | { |
| 559 | PPCCoreCallback(_swapEndianU32(gCoreinitData->__cpp_exception_cleanup_ptr), ¤tThread->crt.eh_globals); |
| 560 | currentThread->crt.eh_globals = nullptr; |
| 561 | } |
| 562 | // set exit code |
| 563 | currentThread->exitValue = exitValue; |
| 564 | |
| 565 | __OSLockScheduler(); |
| 566 | |
| 567 | // release held synchronization primitives |
| 568 | if (!currentThread->mutexQueue.isEmpty()) |
| 569 | { |
| 570 | cemuLog_log(LogType::Force, "OSExitThread: Thread is holding mutexes"); |
| 571 | while (true) |
| 572 | { |
| 573 | OSMutex* mutex = currentThread->mutexQueue.getFirst(); |
| 574 | if (!mutex) |
| 575 | break; |
| 576 | if (mutex->owner != currentThread) |
| 577 | { |
| 578 | cemuLog_log(LogType::Force, "OSExitThread: Thread is holding mutex which it doesn't own"); |
| 579 | currentThread->mutexQueue.removeMutex(mutex); |
| 580 | continue; |
| 581 | } |
| 582 | coreinit::OSUnlockMutexInternal(mutex); |
| 583 | } |
| 584 | } |
| 585 | // todo - release all fast mutexes |
| 586 | |
| 587 | // handle join queue |
| 588 | if (!currentThread->joinQueue.isEmpty()) |
| 589 | currentThread->joinQueue.wakeupEntireWaitQueue(false); |
| 590 | |
| 591 | if ((currentThread->attr & 8) != 0) |
| 592 | { |
| 593 | // deactivate thread since it is detached |
| 594 | currentThread->state = OSThread_t::THREAD_STATE::STATE_NONE; |
| 595 | coreinit::__OSDeactivateThread(currentThread); |
| 596 | // queue call to thread deallocator if set |
| 597 | if (!currentThread->deallocatorFunc.IsNull()) |
| 598 | __OSQueueThreadDeallocation(currentThread); |
| 599 | } |
| 600 | else |
| 601 | { |
no test coverage detected