| 1010 | } |
| 1011 | |
| 1012 | NTSTATUS ThreadTerm(HANDLE Thread, LONG ExitCode) { |
| 1013 | if (!FEX::Windows::ValidateHandleAccess(Thread, THREAD_TERMINATE)) { |
| 1014 | return STATUS_ACCESS_DENIED; |
| 1015 | } |
| 1016 | |
| 1017 | auto ThreadDup = FEX::Windows::DupHandle(Thread, THREAD_QUERY_INFORMATION | THREAD_SUSPEND_RESUME); |
| 1018 | |
| 1019 | THREAD_BASIC_INFORMATION Info; |
| 1020 | if (auto Err = NtQueryInformationThread(*ThreadDup, ThreadBasicInformation, &Info, sizeof(Info), nullptr); Err) { |
| 1021 | return Err; |
| 1022 | } |
| 1023 | |
| 1024 | const auto ThreadTID = reinterpret_cast<uint64_t>(Info.ClientId.UniqueThread); |
| 1025 | bool Self = ThreadTID == GetCurrentThreadId(); |
| 1026 | if (!Self) { |
| 1027 | CONTEXT TmpContext; |
| 1028 | // If we are suspending a thread that isn't ourselves, try to suspend it first so we know internal JIT locks aren't being held. |
| 1029 | NtSuspendThread(*ThreadDup, NULL); |
| 1030 | // This will wait for the thread to be suspended |
| 1031 | NtGetContextThread(*ThreadDup, &TmpContext); |
| 1032 | } |
| 1033 | |
| 1034 | const auto [Err, CPUArea] = GetThreadCPUArea(*ThreadDup); |
| 1035 | if (Err) { |
| 1036 | return Err; |
| 1037 | } |
| 1038 | |
| 1039 | { |
| 1040 | std::scoped_lock Lock(ThreadCreationMutex); |
| 1041 | auto it = Threads.find(ThreadTID); |
| 1042 | if (it == Threads.end()) { |
| 1043 | // Thread already terminated |
| 1044 | return STATUS_SUCCESS; |
| 1045 | } |
| 1046 | |
| 1047 | Threads.erase(it); |
| 1048 | if (StatAllocHandler) { |
| 1049 | StatAllocHandler->DeallocateSlot(CPUArea.ThreadState()->ThreadStats); |
| 1050 | } |
| 1051 | } |
| 1052 | auto ThreadState = CPUArea.ThreadState(); |
| 1053 | |
| 1054 | // GDT and LDT are mirrored, only free one. |
| 1055 | delete[] ThreadState->CurrentFrame->State.segment_arrays[FEXCore::Core::CPUState::SEGMENT_ARRAY_INDEX_GDT]; |
| 1056 | |
| 1057 | FEX::Windows::CallRetStack::DestroyThread(ThreadState); |
| 1058 | CTX->DestroyThread(ThreadState); |
| 1059 | ::VirtualFree(reinterpret_cast<void*>(CPUArea.EmulatorStackLimit()), 0, MEM_RELEASE); |
| 1060 | if (ThreadTID == GetCurrentThreadId()) { |
| 1061 | FEX::Windows::DeinitCRTThread(); |
| 1062 | } |
| 1063 | return STATUS_SUCCESS; |
| 1064 | } |
| 1065 | |
| 1066 | BOOLEAN BTCpu64IsProcessorFeaturePresent(UINT Feature) { |
| 1067 | return CPUFeatures->IsFeaturePresent(Feature) ? TRUE : FALSE; |
nothing calls this directly
no test coverage detected