gthr-win32.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. /* Implementation of W32-specific threads compatibility routines for
  2. libgcc2. */
  3. /* Copyright (C) 1999-2022 Free Software Foundation, Inc.
  4. Contributed by Mumit Khan <khan@xraylith.wisc.edu>.
  5. Modified and moved to separate file by Danny Smith
  6. <dannysmith@users.sourceforge.net>.
  7. This file is part of GCC.
  8. GCC is free software; you can redistribute it and/or modify it under
  9. the terms of the GNU General Public License as published by the Free
  10. Software Foundation; either version 3, or (at your option) any later
  11. version.
  12. GCC is distributed in the hope that it will be useful, but WITHOUT ANY
  13. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  15. for more details.
  16. Under Section 7 of GPL version 3, you are granted additional
  17. permissions described in the GCC Runtime Library Exception, version
  18. 3.1, as published by the Free Software Foundation.
  19. You should have received a copy of the GNU General Public License and
  20. a copy of the GCC Runtime Library Exception along with this program;
  21. see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
  22. <http://www.gnu.org/licenses/>. */
  23. #include <windows.h>
  24. #ifndef __GTHREAD_HIDE_WIN32API
  25. # define __GTHREAD_HIDE_WIN32API 1
  26. #endif
  27. #include "gthr-win32.h"
  28. /* Windows32 threads specific definitions. The windows32 threading model
  29. does not map well into pthread-inspired gcc's threading model, and so
  30. there are caveats one needs to be aware of.
  31. 1. The destructor supplied to __gthread_key_create is ignored for
  32. generic x86-win32 ports. This will certainly cause memory leaks
  33. due to unreclaimed eh contexts (sizeof (eh_context) is at least
  34. 24 bytes for x86 currently).
  35. This memory leak may be significant for long-running applications
  36. that make heavy use of C++ EH.
  37. However, Mingw runtime (version 0.3 or newer) provides a mechanism
  38. to emulate pthreads key dtors; the runtime provides a special DLL,
  39. linked in if -mthreads option is specified, that runs the dtors in
  40. the reverse order of registration when each thread exits. If
  41. -mthreads option is not given, a stub is linked in instead of the
  42. DLL, which results in memory leak. Other x86-win32 ports can use
  43. the same technique of course to avoid the leak.
  44. 2. The error codes returned are non-POSIX like, and cast into ints.
  45. This may cause incorrect error return due to truncation values on
  46. hw where sizeof (DWORD) > sizeof (int).
  47. 3. We are currently using a special mutex instead of the Critical
  48. Sections, since Win9x does not support TryEnterCriticalSection
  49. (while NT does).
  50. The basic framework should work well enough. In the long term, GCC
  51. needs to use Structured Exception Handling on Windows32. */
  52. int
  53. __gthr_win32_once (__gthread_once_t *once, void (*func) (void))
  54. {
  55. if (once == NULL || func == NULL)
  56. return EINVAL;
  57. if (! once->done)
  58. {
  59. if (InterlockedIncrement (&(once->started)) == 0)
  60. {
  61. (*func) ();
  62. once->done = TRUE;
  63. }
  64. else
  65. {
  66. /* Another thread is currently executing the code, so wait for it
  67. to finish; yield the CPU in the meantime. If performance
  68. does become an issue, the solution is to use an Event that
  69. we wait on here (and set above), but that implies a place to
  70. create the event before this routine is called. */
  71. while (! once->done)
  72. Sleep (0);
  73. }
  74. }
  75. return 0;
  76. }
  77. /* Windows32 thread local keys don't support destructors; this leads to
  78. leaks, especially in threaded applications making extensive use of
  79. C++ EH. Mingw uses a thread-support DLL to work-around this problem. */
  80. int
  81. __gthr_win32_key_create (__gthread_key_t *key,
  82. void (*dtor) (void *) __attribute__((unused)))
  83. {
  84. int status = 0;
  85. DWORD tls_index = TlsAlloc ();
  86. if (tls_index != 0xFFFFFFFF)
  87. {
  88. *key = tls_index;
  89. #ifdef MINGW32_SUPPORTS_MT_EH
  90. /* Mingw runtime will run the dtors in reverse order for each thread
  91. when the thread exits. */
  92. status = __mingwthr_key_dtor (*key, dtor);
  93. #endif
  94. }
  95. else
  96. status = (int) GetLastError ();
  97. return status;
  98. }
  99. int
  100. __gthr_win32_key_delete (__gthread_key_t key)
  101. {
  102. return (TlsFree (key) != 0) ? 0 : (int) GetLastError ();
  103. }
  104. void *
  105. __gthr_win32_getspecific (__gthread_key_t key)
  106. {
  107. DWORD lasterror;
  108. void *ptr;
  109. lasterror = GetLastError();
  110. ptr = TlsGetValue(key);
  111. SetLastError( lasterror );
  112. return ptr;
  113. }
  114. int
  115. __gthr_win32_setspecific (__gthread_key_t key, const void *ptr)
  116. {
  117. if (TlsSetValue (key, CONST_CAST2(void *, const void *, ptr)) != 0)
  118. return 0;
  119. else
  120. return GetLastError ();
  121. }
  122. void
  123. __gthr_win32_mutex_init_function (__gthread_mutex_t *mutex)
  124. {
  125. mutex->counter = -1;
  126. mutex->sema = CreateSemaphoreW (NULL, 0, 65535, NULL);
  127. }
  128. void
  129. __gthr_win32_mutex_destroy (__gthread_mutex_t *mutex)
  130. {
  131. CloseHandle ((HANDLE) mutex->sema);
  132. }
  133. int
  134. __gthr_win32_mutex_lock (__gthread_mutex_t *mutex)
  135. {
  136. if (InterlockedIncrement (&mutex->counter) == 0 ||
  137. WaitForSingleObject (mutex->sema, INFINITE) == WAIT_OBJECT_0)
  138. return 0;
  139. else
  140. {
  141. /* WaitForSingleObject returns WAIT_FAILED, and we can only do
  142. some best-effort cleanup here. */
  143. InterlockedDecrement (&mutex->counter);
  144. return 1;
  145. }
  146. }
  147. int
  148. __gthr_win32_mutex_trylock (__gthread_mutex_t *mutex)
  149. {
  150. if (__GTHR_W32_InterlockedCompareExchange (&mutex->counter, 0, -1) < 0)
  151. return 0;
  152. else
  153. return 1;
  154. }
  155. int
  156. __gthr_win32_mutex_unlock (__gthread_mutex_t *mutex)
  157. {
  158. if (InterlockedDecrement (&mutex->counter) >= 0)
  159. return ReleaseSemaphore (mutex->sema, 1, NULL) ? 0 : 1;
  160. else
  161. return 0;
  162. }
  163. void
  164. __gthr_win32_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
  165. {
  166. mutex->counter = -1;
  167. mutex->depth = 0;
  168. mutex->owner = 0;
  169. mutex->sema = CreateSemaphoreW (NULL, 0, 65535, NULL);
  170. }
  171. int
  172. __gthr_win32_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
  173. {
  174. DWORD me = GetCurrentThreadId();
  175. if (InterlockedIncrement (&mutex->counter) == 0)
  176. {
  177. mutex->depth = 1;
  178. mutex->owner = me;
  179. }
  180. else if (mutex->owner == me)
  181. {
  182. InterlockedDecrement (&mutex->counter);
  183. ++(mutex->depth);
  184. }
  185. else if (WaitForSingleObject (mutex->sema, INFINITE) == WAIT_OBJECT_0)
  186. {
  187. mutex->depth = 1;
  188. mutex->owner = me;
  189. }
  190. else
  191. {
  192. /* WaitForSingleObject returns WAIT_FAILED, and we can only do
  193. some best-effort cleanup here. */
  194. InterlockedDecrement (&mutex->counter);
  195. return 1;
  196. }
  197. return 0;
  198. }
  199. int
  200. __gthr_win32_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
  201. {
  202. DWORD me = GetCurrentThreadId();
  203. if (__GTHR_W32_InterlockedCompareExchange (&mutex->counter, 0, -1) < 0)
  204. {
  205. mutex->depth = 1;
  206. mutex->owner = me;
  207. }
  208. else if (mutex->owner == me)
  209. ++(mutex->depth);
  210. else
  211. return 1;
  212. return 0;
  213. }
  214. int
  215. __gthr_win32_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
  216. {
  217. --(mutex->depth);
  218. if (mutex->depth == 0)
  219. {
  220. mutex->owner = 0;
  221. if (InterlockedDecrement (&mutex->counter) >= 0)
  222. return ReleaseSemaphore (mutex->sema, 1, NULL) ? 0 : 1;
  223. }
  224. return 0;
  225. }
  226. int
  227. __gthr_win32_recursive_mutex_destroy (__gthread_recursive_mutex_t *mutex)
  228. {
  229. CloseHandle ((HANDLE) mutex->sema);
  230. return 0;
  231. }