This commit is contained in:
2025-11-24 14:19:51 +05:30
commit f5c1412b28
6734 changed files with 1527575 additions and 0 deletions

View File

@ -0,0 +1,360 @@
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
#include "ThreadEmulation.h"
#include <assert.h>
#include <vector>
#include <set>
#include <map>
#include <mutex>
using namespace std;
using namespace Platform;
using namespace Windows::Foundation;
using namespace Windows::System::Threading;
namespace ThreadEmulation
{
// Stored data for CREATE_SUSPENDED and ResumeThread.
struct PendingThreadInfo
{
LPTHREAD_START_ROUTINE lpStartAddress;
LPVOID lpParameter;
HANDLE completionEvent;
int nPriority;
};
static map<HANDLE, PendingThreadInfo> pendingThreads;
static mutex pendingThreadsLock;
// Thread local storage.
typedef vector<void*> ThreadLocalData;
static __declspec(thread) ThreadLocalData* currentThreadData = nullptr;
static set<ThreadLocalData*> allThreadData;
static DWORD nextTlsIndex = 0;
static vector<DWORD> freeTlsIndices;
static mutex tlsAllocationLock;
// Converts a Win32 thread priority to WinRT format.
static WorkItemPriority GetWorkItemPriority(int nPriority)
{
if (nPriority < 0)
return WorkItemPriority::Low;
else if (nPriority > 0)
return WorkItemPriority::High;
else
return WorkItemPriority::Normal;
}
// Helper shared between CreateThread and ResumeThread.
static void StartThread(LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, HANDLE completionEvent, int nPriority)
{
auto workItemHandler = ref new WorkItemHandler([=](IAsyncAction^)
{
// Run the user callback.
try
{
lpStartAddress(lpParameter);
}
catch (Exception ^e)
{
Platform::String ^exceptionString = e->ToString();
OutputDebugStringW(exceptionString->Data());
}
// Clean up any TLS allocations made by this thread.
TlsShutdown();
// Signal that the thread has completed.
SetEvent(completionEvent);
CloseHandle(completionEvent);
}, CallbackContext::Any);
ThreadPool::RunAsync(workItemHandler, GetWorkItemPriority(nPriority), WorkItemOptions::TimeSliced);
}
_Use_decl_annotations_ HANDLE WINAPI CreateThread(LPSECURITY_ATTRIBUTES unusedThreadAttributes, SIZE_T unusedStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD unusedThreadId)
{
// Validate parameters.
assert(unusedThreadAttributes == nullptr);
assert(unusedStackSize == 0);
assert((dwCreationFlags & ~CREATE_SUSPENDED) == 0);
assert(unusedThreadId == nullptr);
// Create a handle that will be signalled when the thread has completed.
HANDLE threadHandle = CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);
if (!threadHandle)
return nullptr;
// Make a copy of the handle for internal use. This is necessary because
// the caller is responsible for closing the handle returned by CreateThread,
// and they may do that before or after the thread has finished running.
HANDLE completionEvent;
if (!DuplicateHandle(GetCurrentProcess(), threadHandle, GetCurrentProcess(), &completionEvent, 0, false, DUPLICATE_SAME_ACCESS))
{
CloseHandle(threadHandle);
return nullptr;
}
try
{
if (dwCreationFlags & CREATE_SUSPENDED)
{
// Store info about a suspended thread.
PendingThreadInfo info;
info.lpStartAddress = lpStartAddress;
info.lpParameter = lpParameter;
info.completionEvent = completionEvent;
info.nPriority = 0;
lock_guard<mutex> lock(pendingThreadsLock);
pendingThreads[threadHandle] = info;
}
else
{
// Start the thread immediately.
StartThread(lpStartAddress, lpParameter, completionEvent, 0);
}
return threadHandle;
}
catch (...)
{
// Clean up if thread creation fails.
CloseHandle(threadHandle);
CloseHandle(completionEvent);
return nullptr;
}
}
_Use_decl_annotations_ DWORD WINAPI ResumeThread(HANDLE hThread)
{
lock_guard<mutex> lock(pendingThreadsLock);
// Look up the requested thread.
auto threadInfo = pendingThreads.find(hThread);
if (threadInfo == pendingThreads.end())
{
// Can only resume threads while they are in CREATE_SUSPENDED state.
assert(false);
return (DWORD)-1;
}
// Start the thread.
try
{
PendingThreadInfo& info = threadInfo->second;
StartThread(info.lpStartAddress, info.lpParameter, info.completionEvent, info.nPriority);
}
catch (...)
{
return (DWORD)-1;
}
// Remove this thread from the pending list.
pendingThreads.erase(threadInfo);
return 0;
}
_Use_decl_annotations_ BOOL WINAPI SetThreadPriority(HANDLE hThread, int nPriority)
{
lock_guard<mutex> lock(pendingThreadsLock);
// Look up the requested thread.
auto threadInfo = pendingThreads.find(hThread);
if (threadInfo == pendingThreads.end())
{
// Can only set priority on threads while they are in CREATE_SUSPENDED state.
assert(false);
return false;
}
// Store the new priority.
threadInfo->second.nPriority = nPriority;
return true;
}
_Use_decl_annotations_ VOID WINAPI Sleep(DWORD dwMilliseconds)
{
static HANDLE singletonEvent = nullptr;
HANDLE sleepEvent = singletonEvent;
// Demand create the event.
if (!sleepEvent)
{
sleepEvent = CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);
if (!sleepEvent)
return;
HANDLE previousEvent = InterlockedCompareExchangePointerRelease(&singletonEvent, sleepEvent, nullptr);
if (previousEvent)
{
// Back out if multiple threads try to demand create at the same time.
CloseHandle(sleepEvent);
sleepEvent = previousEvent;
}
}
// Emulate sleep by waiting with timeout on an event that is never signalled.
WaitForSingleObjectEx(sleepEvent, dwMilliseconds, false);
}
DWORD WINAPI TlsAlloc()
{
lock_guard<mutex> lock(tlsAllocationLock);
// Can we reuse a previously freed TLS slot?
if (!freeTlsIndices.empty())
{
DWORD result = freeTlsIndices.back();
freeTlsIndices.pop_back();
return result;
}
// Allocate a new TLS slot.
return nextTlsIndex++;
}
_Use_decl_annotations_ BOOL WINAPI TlsFree(DWORD dwTlsIndex)
{
lock_guard<mutex> lock(tlsAllocationLock);
assert(dwTlsIndex < nextTlsIndex);
assert(find(freeTlsIndices.begin(), freeTlsIndices.end(), dwTlsIndex) == freeTlsIndices.end());
// Store this slot for reuse by TlsAlloc.
try
{
freeTlsIndices.push_back(dwTlsIndex);
}
catch (...)
{
return false;
}
// Zero the value for all threads that might be using this now freed slot.
for each (auto threadData in allThreadData)
{
if (threadData->size() > dwTlsIndex)
{
threadData->at(dwTlsIndex) = nullptr;
}
}
return true;
}
_Use_decl_annotations_ LPVOID WINAPI TlsGetValue(DWORD dwTlsIndex)
{
ThreadLocalData* threadData = currentThreadData;
if (threadData && threadData->size() > dwTlsIndex)
{
// Return the value of an allocated TLS slot.
return threadData->at(dwTlsIndex);
}
else
{
// Default value for unallocated slots.
return nullptr;
}
}
_Use_decl_annotations_ BOOL WINAPI TlsSetValue(DWORD dwTlsIndex, LPVOID lpTlsValue)
{
ThreadLocalData* threadData = currentThreadData;
if (!threadData)
{
// First time allocation of TLS data for this thread.
try
{
threadData = new ThreadLocalData(dwTlsIndex + 1, nullptr);
lock_guard<mutex> lock(tlsAllocationLock);
allThreadData.insert(threadData);
currentThreadData = threadData;
}
catch (...)
{
if (threadData)
delete threadData;
return false;
}
}
else if (threadData->size() <= dwTlsIndex)
{
// This thread already has a TLS data block, but it must be expanded to fit the specified slot.
try
{
lock_guard<mutex> lock(tlsAllocationLock);
threadData->resize(dwTlsIndex + 1, nullptr);
}
catch (...)
{
return false;
}
}
// Store the new value for this slot.
threadData->at(dwTlsIndex) = lpTlsValue;
return true;
}
// Called at thread exit to clean up TLS allocations.
void WINAPI TlsShutdown()
{
ThreadLocalData* threadData = currentThreadData;
if (threadData)
{
{
lock_guard<mutex> lock(tlsAllocationLock);
allThreadData.erase(threadData);
}
currentThreadData = nullptr;
delete threadData;
}
}
}

View File

@ -0,0 +1,53 @@
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Emulates a subset of the Win32 threading API as a layer on top of WinRT threadpools.
//
// Supported features:
//
// - CreateThread (returns a standard Win32 handle which can be waited on, then closed)
// - CREATE_SUSPENDED and ResumeThread
// - Partial support for SetThreadPriority (see below)
// - Sleep
// - Thread local storage (TlsAlloc, TlsFree, TlsGetValue, TlsSetValue)
//
// Differences from Win32:
//
// - If using TLS other than from this CreateThread emulation, call TlsShutdown before thread/task exit
// - No ExitThread or TerminateThread (just return from the thread function to exit)
// - No SuspendThread, so ResumeThread is only useful in combination with CREATE_SUSPENDED
// - SetThreadPriority is only available while a thread is in CREATE_SUSPENDED state
// - SetThreadPriority only supports three priority levels (negative, zero, or positive)
// - No thread identifier APIs (GetThreadId, GetCurrentThreadId, OpenThread)
// - No affinity APIs
// - No GetExitCodeThread
// - Failure cases return error codes but do not always call SetLastError
#pragma once
#include <windows.h>
namespace ThreadEmulation
{
#ifndef CREATE_SUSPENDED
#define CREATE_SUSPENDED 0x00000004
#endif
HANDLE WINAPI CreateThread(_In_opt_ LPSECURITY_ATTRIBUTES unusedThreadAttributes, _In_ SIZE_T unusedStackSize, _In_ LPTHREAD_START_ROUTINE lpStartAddress, _In_opt_ LPVOID lpParameter, _In_ DWORD dwCreationFlags, _Out_opt_ LPDWORD unusedThreadId);
DWORD WINAPI ResumeThread(_In_ HANDLE hThread);
BOOL WINAPI SetThreadPriority(_In_ HANDLE hThread, _In_ int nPriority);
VOID WINAPI Sleep(_In_ DWORD dwMilliseconds);
DWORD WINAPI TlsAlloc();
BOOL WINAPI TlsFree(_In_ DWORD dwTlsIndex);
LPVOID WINAPI TlsGetValue(_In_ DWORD dwTlsIndex);
BOOL WINAPI TlsSetValue(_In_ DWORD dwTlsIndex, _In_opt_ LPVOID lpTlsValue);
void WINAPI TlsShutdown();
}