===== Win32 Threading Primitives ===== This documents some of the design decisions made when implementing the C11 threading primitives on Windows ==== tss_t ==== Note: see C11 defect report: tss_t destruction unspecified for issues with the standard specification of tss_t. The PDCLib implementation at present follows that report. Windows provides a thread local storage implementation which mostly implements the requirements of the standard. However, it doesn't implement destructors. To solve that, PDCLib uses two approaches * TLS callbacks: Executables and DLLs can specify "TLS callbacks", which are actions invoked in a similar manner to (but before) the traditional DllMain entry point for a DLL - and, importantly, are present in executables (which do not support DllMain). This works in all cases on NT 6.0 and later; but on older versions of Windows, these will only be invoked for the main executable and any DLLs loaded as direct dependencies of it (i.e. nothing loaded dynamically with LoadLibrary) * DllMain: This works for all libraries everywhere, but doesn't work for executables. There are three cases to consider: * Linked statically from the executable: In this case we must use TLS callbacks * Linked statically from a DLL: In this case we must use DllMain for wide support * Linked dynamically: In this case we use our own DllMain Our implementation strategy: * TBD ==== mtx_t ==== Our implementation doesn't use Win32 CRITICAL_SECTIONs; primarily because this would involve exposing '''' to all people who include '''', or duplicating the definition of CRITICAL_SECTION (messy). Instead, we implement a locking primitive on top of Windows' event handles - Every mutex has two members, ''_WaitEvHandle'', which is a automatic reset Win32 event handle used for blocking, and ''_ThreadId'', the ID of the current thread - ''_ThreadId'' is initialized to 0 - To lock, ''mtx_lock'' calls ''InterlockedCompareExchange'' on ''_ThreadId''. If the return value is 0, we successfully locked the mutex. If it is not 0, then we must block, so go ahead and block on the event handle - To unlock, ''mtx_unlock'' sets ''_ThreadId'' to 0 and invokes ''SetEvent'' to unblock a thread