EXIT ;\r
}\r
\r
-PDCLIB_OPTIONS = nothread notime dlmalloc ;\r
+PDCLIB_OPTIONS = notime dlmalloc ;\r
\r
CRT0 = [ FDirName platform win32 crt0$(SUFOBJ) ] ;
\ No newline at end of file
--- /dev/null
+#include <stddef.h>\r
+#include <windows.h>\r
+\r
+#ifndef REGTEST\r
+extern PIMAGE_TLS_CALLBACK __crt_xl_start__;\r
+#ifdef __GNUC__\r
+__attribute__((section(".CRT$XLZZZ")))\r
+#else\r
+__declspec(allocate(".CRT$XLZZZ")) \r
+#endif\r
+PIMAGE_TLS_CALLBACK __crt_xl_end__ = NULL;\r
+\r
+/* Runs all TLS callbacks registered in the executable\r
+ */\r
+\r
+void NTAPI _PDCLIB_runTlsCallbacks(void * image, DWORD reason, PVOID pv);\r
+void NTAPI _PDCLIB_runTlsCallbacks(void * image, DWORD reason, PVOID pv)\r
+{\r
+ PIMAGE_TLS_CALLBACK * pcb = &__crt_xl_start__;\r
+\r
+ while(*pcb) (*(pcb++))(image, reason, pv);\r
+}\r
+#endif\r
+\r
+#ifdef TEST\r
+#include <_PDCLIB_test.h>\r
+\r
+/* Tested in tss_get.c */\r
+int main( void )\r
+{\r
+ return TEST_RESULTS;\r
+}\r
+\r
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef REGTEST\r
+#include <stddef.h>\r
+#include <stdint.h>\r
+#include <windows.h>\r
+\r
+/* Win32 TLS support\r
+ *\r
+ * Components which depend upon TLS must express a dependency on the symbol \r
+ * _tls_used. This will cause said symbol to be emitted.\r
+ *\r
+ * The linker (in the case of both Microsoft's linker and Binutils, at least)\r
+ * will point the TLS directory entry in the PE header to _tls_used.\r
+ *\r
+ * NOTE: On Windows versions < NT 6.0, the TLS support _only_ works for \r
+ * the main executable and any DLLs loaded as dependencies of it\r
+ */\r
+\r
+extern char __tls_start__[], __tls_end__[];\r
+ULONG _tls_index = TLS_OUT_OF_INDEXES;\r
+\r
+extern void NTAPI _PDCLIB_runTlsCallbacks(void * image, DWORD reason, PVOID pv);\r
+static PIMAGE_TLS_CALLBACK tlsCallbacks[] = {\r
+ &_PDCLIB_runTlsCallbacks,\r
+ NULL,\r
+};\r
+\r
+#ifdef __GNUC__\r
+__attribute__((__section__(".rdata$T")))\r
+#else\r
+__declspec(allocate(".rdata$T"))\r
+#endif\r
+#ifdef _WIN64\r
+const IMAGE_TLS_DIRECTORY64 _tls_used = {\r
+#else\r
+const IMAGE_TLS_DIRECTORY _tls_used = {\r
+#endif\r
+ (uintptr_t) &__tls_start__,\r
+ (uintptr_t) &__tls_end__,\r
+ (uintptr_t) &_tls_index, // TLS index\r
+ (uintptr_t) &tlsCallbacks[0], // TLS callback array\r
+ (ULONG) 0, // Size of zero fill\r
+ (ULONG) 0 // Characteristics\r
+};\r
+#endif\r
+\r
+#ifdef TEST\r
+#include <_PDCLIB_test.h>\r
+\r
+/* Tested in tss_get.c */\r
+int main( void )\r
+{\r
+ return TEST_RESULTS;\r
+}\r
+\r
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef REGTEST\r
+#include <threads.h>\r
+#include <windows.h>\r
+\r
+static volatile HANDLE onceHandle = NULL;\r
+\r
+static void initOnceHandle( _PDCLIB_once_flag *flag )\r
+{\r
+ HANDLE tOnceHandle = CreateEvent(NULL, TRUE, TRUE, NULL);\r
+ HANDLE oldVal \r
+ = InterlockedCompareExchangePointer(&flag->_Handle, tOnceHandle, NULL);\r
+ if(oldVal != NULL)\r
+ CloseHandle(tOnceHandle);\r
+}\r
+\r
+void _PDCLIB_call_once(_PDCLIB_once_flag *flag, void (*func)(void))\r
+{\r
+ if(!flag->_Handle) initOnceHandle(flag);\r
+\r
+ long oldVal = InterlockedCompareExchange(&flag->_State, 1, -1);\r
+ for(;;) {\r
+ if(oldVal == 0) {\r
+ // Initialized\r
+ return;\r
+ } else if(oldVal == -1) {\r
+ // We are doing the initialization\r
+ func();\r
+ if(InterlockedDecrement(&flag->_State) == 0)\r
+ CloseHandle(flag->_Handle);\r
+ SetEvent(flag->_Handle);\r
+ return;\r
+ } else {\r
+ // Somebody else is initializing - we are waiting\r
+ long newOldVal = InterlockedCompareExchange(&flag->_State, oldVal, \r
+ oldVal+1);\r
+ if(newOldVal == oldVal) {\r
+ // We incremented the "waiters" counter\r
+ if(WaitForSingleObject(flag->_Handle, INFINITE) != WAIT_OBJECT_0)\r
+ abort();\r
+ if(InterlockedDecrement(&flag->_State) == 0)\r
+ CloseHandle(flag->_Handle);\r
+ return;\r
+ } else {\r
+ oldVal = newOldVal;\r
+ continue;\r
+ }\r
+ }\r
+ }\r
+}\r
+#endif\r
+\r
+#ifdef TEST\r
+#include <_PDCLIB_test.h>\r
+\r
+#ifndef REGTEST\r
+static int count = 0;\r
+static once_flag once = ONCE_FLAG_INIT;\r
+\r
+static void do_once(void)\r
+{\r
+ count++;\r
+}\r
+#endif\r
+\r
+int main( void )\r
+{\r
+#ifndef REGTEST\r
+ TESTCASE(count == 0);\r
+ call_once(&once, do_once);\r
+ TESTCASE(count == 1);\r
+ call_once(&once, do_once);\r
+ TESTCASE(count == 1);\r
+ do_once();\r
+ TESTCASE(count == 2);\r
+#endif\r
+ return TEST_RESULTS;\r
+}\r
+\r
+#endif\r
--- /dev/null
+#ifndef REGTEST\r
+#include <threads.h>\r
+#include <windows.h>\r
+\r
+int mtx_init(mtx_t *mtx, int type)\r
+{\r
+ mtx->_WaitEvHandle = CreateEvent(NULL, \r
+ /* bManualReset*/ FALSE, \r
+ /* bInitialState*/ FALSE, \r
+ /* name*/ NULL);\r
+ if(mtx->_WaitEvHandle == NULL)\r
+ return thrd_error;\r
+ \r
+ mtx->_State = -1;\r
+ mtx->_ThreadId = 0;\r
+ mtx->_NestCount = 0;;\r
+\r
+ return thrd_success;\r
+}\r
+#endif\r
+\r
+#ifdef TEST\r
+#include <_PDCLIB_test.h>\r
+\r
+int main( void )\r
+{\r
+ return TEST_RESULTS;\r
+}\r
+\r
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef REGTEST\r
+#include <threads.h>\r
+#include <windows.h>\r
+\r
+int mtx_lock(mtx_t *mtx)\r
+{\r
+ DWORD myId = GetCurrentThreadId();\r
+\r
+ if(mtx->_ThreadId == myId) {\r
+ mtx->_NestCount++;\r
+ return thrd_success;\r
+ }\r
+\r
+ DWORD res = InterlockedIncrement(&mtx->_State);\r
+ if(res == 0) {\r
+ mtx->_ThreadId = myId;\r
+ return thrd_success;\r
+ }\r
+\r
+ // If that increment didn't leave the state == 0, then we have contention\r
+ // -> block on the wait event handle\r
+ DWORD rv = WaitForSingleObject(mtx->_WaitEvHandle, INFINITE);\r
+ if(rv != WAIT_OBJECT_0) \r
+ return thrd_error;\r
+\r
+ // We now own the mutex - so set it up for our use\r
+ mtx->_ThreadId = myId;\r
+ return thrd_success;\r
+}\r
+#endif\r
+\r
+#ifdef TEST\r
+#include <_PDCLIB_test.h>\r
+\r
+int main( void )\r
+{\r
+ return TEST_RESULTS;\r
+}\r
+\r
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef REGTEST\r
+#include <threads.h>\r
+#include <windows.h>\r
+\r
+extern void _PDCLIB_w32errno( void );\r
+int mtx_unlock(mtx_t *mtx)\r
+{\r
+ if(mtx->_NestCount) {\r
+ mtx->_NestCount--;\r
+ return thrd_success;\r
+ }\r
+\r
+ mtx->_ThreadId = 0;\r
+\r
+ DWORD res = InterlockedDecrement(&mtx->_State);\r
+ if(res == (DWORD) -1) {\r
+ // We reset the state to -1; success!\r
+ return thrd_success;\r
+ }\r
+\r
+ DWORD rv = SetEvent(mtx->_WaitEvHandle);\r
+ if(rv == 0) {\r
+ _PDCLIB_w32errno();\r
+ return thrd_error;\r
+ }\r
+\r
+ return thrd_success;\r
+}\r
+#endif\r
+\r
+#ifdef TEST\r
+#include <_PDCLIB_test.h>\r
+\r
+int main( void )\r
+{\r
+ return TEST_RESULTS;\r
+}\r
+\r
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef REGTEST\r
+#include <threads.h>\r
+#include <stdbool.h>\r
+#include <windows.h>\r
+\r
+/* Pull in TLS support */\r
+extern char _tls_used[];\r
+\r
+struct _PDCLIB_tss * _PDCLIB_tss_first = NULL;\r
+\r
+int tss_create( tss_t *key, tss_dtor_t dtor )\r
+{\r
+ *key = malloc( sizeof *key );\r
+ if( !*key ) {\r
+ return thrd_nomem;\r
+ }\r
+\r
+ (*key)->_Key = TlsAlloc();\r
+ if((*key)->_Key == TLS_OUT_OF_INDEXES) {\r
+ return thrd_error;\r
+ }\r
+ (*key)->_Destructor = dtor;\r
+ (*key)->_Next = _PDCLIB_tss_first;\r
+\r
+ // TODO: make this atomic (& validate no other TLS blocks have been \r
+ // simultaneously allocated)\r
+ _PDCLIB_tss_first = *key;\r
+\r
+ return thrd_success;\r
+}\r
+\r
+static void NTAPI runTlsDestructors( void * image, DWORD reason, PVOID pv )\r
+{\r
+ if( reason == DLL_THREAD_DETACH ) {\r
+ for(unsigned i = 0; i < TSS_DTOR_ITERATIONS; i++) {\r
+ struct _PDCLIB_tss * tss = _PDCLIB_tss_first;\r
+ bool destructorsRan = false;\r
+ while( tss ) {\r
+ void * val = TlsGetValue( tss->_Key );\r
+ if( val ) {\r
+ TlsSetValue( tss->_Key, NULL );\r
+ if( tss->_Destructor ) {\r
+ tss->_Destructor( val );\r
+ destructorsRan = true;\r
+ }\r
+ }\r
+\r
+ tss = tss->_Next;\r
+ }\r
+ if(!destructorsRan) break;\r
+ }\r
+ }\r
+}\r
+\r
+#ifdef __GNUC__\r
+__attribute__((__section__(".CRT$XLC")))\r
+#else\r
+__declspec(allocate(".CRT$XLC")) \r
+#endif\r
+PIMAGE_TLS_CALLBACK _PDCLIB_runTlsDestructors = runTlsDestructors;\r
+\r
+#endif\r
+\r
+#ifdef TEST\r
+#include <_PDCLIB_test.h>\r
+\r
+/* Tested in tss_get.c */\r
+int main( void )\r
+{\r
+ return TEST_RESULTS;\r
+}\r
+\r
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef REGTEST\r
+#include <windows.h>\r
+#include <threads.h>\r
+#include <stdlib.h>\r
+\r
+extern struct _PDCLIB_tss * _PDCLIB_tss_first;\r
+void tss_delete( tss_t key )\r
+{\r
+ struct _PDCLIB_tss * prev = NULL;\r
+ struct _PDCLIB_tss * cur = _PDCLIB_tss_first;\r
+ while(cur) {\r
+ if(cur == key) {\r
+ if(prev) {\r
+ prev->_Next = key->_Next;\r
+ } else {\r
+ _PDCLIB_tss_first = key->_Next;\r
+ }\r
+\r
+ TlsFree(key->_Key);\r
+ free(key);\r
+ return;\r
+ }\r
+ }\r
+\r
+ // Not actually a TSS key\r
+ abort();\r
+}\r
+#endif\r
+\r
+#ifdef TEST\r
+#include <_PDCLIB_test.h>\r
+\r
+/* Tested in tss_get.c */\r
+int main( void )\r
+{\r
+ return TEST_RESULTS;\r
+}\r
+\r
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef REGTEST\r
+#include <threads.h>\r
+#include <windows.h>\r
+\r
+void *tss_get(tss_t key)\r
+{\r
+ return TlsGetValue(key->_Key);\r
+}\r
+#endif\r
+\r
+#ifdef TEST\r
+#include <_PDCLIB_test.h>\r
+\r
+#ifndef REGTEST\r
+static tss_t key;\r
+static char v;\r
+#endif\r
+\r
+// Todo: make a thread and test destruction!\r
+\r
+int main( void )\r
+{\r
+#ifndef REGTEST\r
+ TESTCASE(tss_create(&key, NULL) == thrd_success);\r
+ TESTCASE(tss_get(key) == NULL);\r
+ TESTCASE(tss_set(key, &v) == thrd_success);\r
+ TESTCASE(tss_get(key) == &v);\r
+ tss_delete(key);\r
+#endif\r
+ return TEST_RESULTS;\r
+}\r
+\r
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef REGTEST\r
+#include <threads.h>\r
+#include <windows.h>\r
+\r
+int tss_set(tss_t key, void *val)\r
+{\r
+ if(TlsSetValue(key->_Key, val))\r
+ return thrd_success;\r
+ return thrd_error;\r
+}\r
+#endif\r
+\r
+#ifdef TEST\r
+#include <_PDCLIB_test.h>\r
+\r
+/* Tested in tss_get.c */\r
+int main( void )\r
+{\r
+ return TEST_RESULTS;\r
+}\r
+\r
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef _PDCLIB_THREADCONFIG_H\r
+#define _PDCLIB_THREADCONFIG_H\r
+#include <_PDCLIB_aux.h>\r
+#include <_PDCLIB_int.h>\r
+\r
+_PDCLIB_BEGIN_EXTERN_C\r
+#define _PDCLIB_TSS_DTOR_ITERATIONS 3\r
+#define _PDCLIB_ONCE_FLAG_INIT { -1, 0 }\r
+#define _PDCLIB_ONCE_FLAG_IS_DONE( _f ) ((_f)->_State == 0)\r
+typedef struct {\r
+ long _State;\r
+ void *_Handle;\r
+} _PDCLIB_once_flag;\r
+\r
+void _PDCLIB_call_once(_PDCLIB_once_flag *flag, void (*func)(void));\r
+\r
+//#define _PDCLIB_THRD_HAVE_MISC\r
+//#define _PDCLIB_CND_T char\r
+#define _PDCLIB_MTX_T struct _PDCLIB_mtx \r
+\r
+struct _PDCLIB_mtx {\r
+ void * _WaitEvHandle;\r
+ volatile signed long _State;\r
+ volatile unsigned int _ThreadId;\r
+ volatile unsigned int _NestCount;\r
+};\r
+\r
+#define _PDCLIB_TSS_T struct _PDCLIB_tss *\r
+\r
+struct _PDCLIB_tss {\r
+ void (*_Destructor)(void*);\r
+ struct _PDCLIB_tss * _Next;\r
+ unsigned int _Key;\r
+};\r
+\r
+_PDCLIB_END_EXTERN_C\r
+#endif\r