Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

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