1117395Skan/* Implementation of W32-specific threads compatibility routines for
2132718Skan   libgcc2.  */
3117395Skan
4132718Skan/* Copyright (C) 1999, 2000, 2002, 2004 Free Software Foundation, Inc.
5117395Skan   Contributed by Mumit Khan <khan@xraylith.wisc.edu>.
6117395Skan   Modified and moved to separate file by Danny Smith
7117395Skan   <dannysmith@users.sourceforge.net>.
8117395Skan
9117395SkanThis file is part of GCC.
10117395Skan
11117395SkanGCC is free software; you can redistribute it and/or modify it under
12117395Skanthe terms of the GNU General Public License as published by the Free
13117395SkanSoftware Foundation; either version 2, or (at your option) any later
14117395Skanversion.
15117395Skan
16117395SkanGCC is distributed in the hope that it will be useful, but WITHOUT ANY
17117395SkanWARRANTY; without even the implied warranty of MERCHANTABILITY or
18117395SkanFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
19117395Skanfor more details.
20117395Skan
21117395SkanYou should have received a copy of the GNU General Public License
22117395Skanalong with GCC; see the file COPYING.  If not, write to the Free
23169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
24169689Skan02110-1301, USA.  */
25117395Skan
26117395Skan/* As a special exception, if you link this library with other files,
27117395Skan   some of which are compiled with GCC, to produce an executable,
28117395Skan   this library does not by itself cause the resulting executable
29117395Skan   to be covered by the GNU General Public License.
30117395Skan   This exception does not however invalidate any other reasons why
31117395Skan   the executable file might be covered by the GNU General Public License.  */
32117395Skan
33117395Skan
34146895Skan#include <windows.h>
35117395Skan#ifndef __GTHREAD_HIDE_WIN32API
36119256Skan# define __GTHREAD_HIDE_WIN32API 1
37117395Skan#endif
38146895Skan#undef  __GTHREAD_I486_INLINE_LOCK_PRIMITIVES
39146895Skan#define __GTHREAD_I486_INLINE_LOCK_PRIMITIVES
40117395Skan#include <gthr-win32.h>
41117395Skan
42117395Skan/* Windows32 threads specific definitions. The windows32 threading model
43117395Skan   does not map well into pthread-inspired gcc's threading model, and so
44117395Skan   there are caveats one needs to be aware of.
45117395Skan
46117395Skan   1. The destructor supplied to __gthread_key_create is ignored for
47117395Skan      generic x86-win32 ports. This will certainly cause memory leaks
48117395Skan      due to unreclaimed eh contexts (sizeof (eh_context) is at least
49117395Skan      24 bytes for x86 currently).
50117395Skan
51117395Skan      This memory leak may be significant for long-running applications
52117395Skan      that make heavy use of C++ EH.
53117395Skan
54117395Skan      However, Mingw runtime (version 0.3 or newer) provides a mechanism
55117395Skan      to emulate pthreads key dtors; the runtime provides a special DLL,
56117395Skan      linked in if -mthreads option is specified, that runs the dtors in
57117395Skan      the reverse order of registration when each thread exits. If
58117395Skan      -mthreads option is not given, a stub is linked in instead of the
59117395Skan      DLL, which results in memory leak. Other x86-win32 ports can use
60117395Skan      the same technique of course to avoid the leak.
61117395Skan
62117395Skan   2. The error codes returned are non-POSIX like, and cast into ints.
63117395Skan      This may cause incorrect error return due to truncation values on
64117395Skan      hw where sizeof (DWORD) > sizeof (int).
65117395Skan
66146895Skan   3. We are currently using a special mutex instead of the Critical
67146895Skan      Sections, since Win9x does not support TryEnterCriticalSection
68146895Skan      (while NT does).
69117395Skan
70117395Skan   The basic framework should work well enough. In the long term, GCC
71117395Skan   needs to use Structured Exception Handling on Windows32.  */
72117395Skan
73117395Skanint
74117395Skan__gthr_win32_once (__gthread_once_t *once, void (*func) (void))
75117395Skan{
76117395Skan  if (once == NULL || func == NULL)
77117395Skan    return EINVAL;
78117395Skan
79117395Skan  if (! once->done)
80117395Skan    {
81117395Skan      if (InterlockedIncrement (&(once->started)) == 0)
82117395Skan        {
83117395Skan	  (*func) ();
84117395Skan	  once->done = TRUE;
85117395Skan	}
86117395Skan      else
87117395Skan	{
88117395Skan	  /* Another thread is currently executing the code, so wait for it
89117395Skan	     to finish; yield the CPU in the meantime.  If performance
90117395Skan	     does become an issue, the solution is to use an Event that
91117395Skan	     we wait on here (and set above), but that implies a place to
92117395Skan	     create the event before this routine is called.  */
93117395Skan	  while (! once->done)
94117395Skan	    Sleep (0);
95117395Skan	}
96117395Skan    }
97117395Skan  return 0;
98117395Skan}
99117395Skan
100117395Skan/* Windows32 thread local keys don't support destructors; this leads to
101117395Skan   leaks, especially in threaded applications making extensive use of
102117395Skan   C++ EH. Mingw uses a thread-support DLL to work-around this problem.  */
103117395Skan
104117395Skanint
105117395Skan__gthr_win32_key_create (__gthread_key_t *key, void (*dtor) (void *))
106117395Skan{
107117395Skan  int status = 0;
108117395Skan  DWORD tls_index = TlsAlloc ();
109117395Skan  if (tls_index != 0xFFFFFFFF)
110117395Skan    {
111117395Skan      *key = tls_index;
112117395Skan#ifdef MINGW32_SUPPORTS_MT_EH
113117395Skan      /* Mingw runtime will run the dtors in reverse order for each thread
114117395Skan         when the thread exits.  */
115117395Skan      status = __mingwthr_key_dtor (*key, dtor);
116117395Skan#endif
117117395Skan    }
118117395Skan  else
119117395Skan    status = (int) GetLastError ();
120117395Skan  return status;
121117395Skan}
122117395Skan
123117395Skanint
124117395Skan__gthr_win32_key_delete (__gthread_key_t key)
125117395Skan{
126117395Skan  return (TlsFree (key) != 0) ? 0 : (int) GetLastError ();
127117395Skan}
128117395Skan
129117395Skanvoid *
130117395Skan__gthr_win32_getspecific (__gthread_key_t key)
131117395Skan{
132117395Skan  DWORD lasterror;
133117395Skan  void *ptr;
134117395Skan  lasterror = GetLastError();
135117395Skan  ptr = TlsGetValue(key);
136117395Skan  SetLastError( lasterror );
137117395Skan  return ptr;
138117395Skan}
139117395Skan
140117395Skanint
141117395Skan__gthr_win32_setspecific (__gthread_key_t key, const void *ptr)
142117395Skan{
143117395Skan  return (TlsSetValue (key, (void*) ptr) != 0) ? 0 : (int) GetLastError ();
144117395Skan}
145117395Skan
146117395Skanvoid
147117395Skan__gthr_win32_mutex_init_function (__gthread_mutex_t *mutex)
148117395Skan{
149146895Skan  mutex->counter = -1;
150146895Skan  mutex->sema = CreateSemaphore (NULL, 0, 65535, NULL);
151117395Skan}
152117395Skan
153117395Skanint
154117395Skan__gthr_win32_mutex_lock (__gthread_mutex_t *mutex)
155117395Skan{
156146895Skan  if (InterlockedIncrement (&mutex->counter) == 0 ||
157146895Skan      WaitForSingleObject (mutex->sema, INFINITE) == WAIT_OBJECT_0)
158117395Skan    return 0;
159117395Skan  else
160146895Skan    {
161146895Skan      /* WaitForSingleObject returns WAIT_FAILED, and we can only do
162146895Skan         some best-effort cleanup here.  */
163146895Skan      InterlockedDecrement (&mutex->counter);
164146895Skan      return 1;
165146895Skan    }
166117395Skan}
167117395Skan
168117395Skanint
169117395Skan__gthr_win32_mutex_trylock (__gthread_mutex_t *mutex)
170117395Skan{
171146895Skan  if (__GTHR_W32_InterlockedCompareExchange (&mutex->counter, 0, -1) < 0)
172117395Skan    return 0;
173117395Skan  else
174117395Skan    return 1;
175117395Skan}
176117395Skan
177117395Skanint
178117395Skan__gthr_win32_mutex_unlock (__gthread_mutex_t *mutex)
179117395Skan{
180146895Skan  if (InterlockedDecrement (&mutex->counter) >= 0)
181146895Skan    return ReleaseSemaphore (mutex->sema, 1, NULL) ? 0 : 1;
182146895Skan  else
183146895Skan    return 0;
184117395Skan}
185169689Skan
186169689Skanvoid
187169689Skan__gthr_win32_recursive_mutex_init_function (__gthread_recursive_mutex_t *mutex)
188169689Skan{
189169689Skan  mutex->counter = -1;
190169689Skan  mutex->depth = 0;
191169689Skan  mutex->owner = 0;
192169689Skan  mutex->sema = CreateSemaphore (NULL, 0, 65535, NULL);
193169689Skan}
194169689Skan
195169689Skanint
196169689Skan__gthr_win32_recursive_mutex_lock (__gthread_recursive_mutex_t *mutex)
197169689Skan{
198169689Skan  DWORD me = GetCurrentThreadId();
199169689Skan  if (InterlockedIncrement (&mutex->counter) == 0)
200169689Skan    {
201169689Skan      mutex->depth = 1;
202169689Skan      mutex->owner = me;
203169689Skan    }
204169689Skan  else if (mutex->owner == me)
205169689Skan    {
206169689Skan      InterlockedDecrement (&mutex->counter);
207169689Skan      ++(mutex->depth);
208169689Skan    }
209169689Skan  else if (WaitForSingleObject (mutex->sema, INFINITE) == WAIT_OBJECT_0)
210169689Skan    {
211169689Skan      mutex->depth = 1;
212169689Skan      mutex->owner = me;
213169689Skan    }
214169689Skan  else
215169689Skan    {
216169689Skan      /* WaitForSingleObject returns WAIT_FAILED, and we can only do
217169689Skan         some best-effort cleanup here.  */
218169689Skan      InterlockedDecrement (&mutex->counter);
219169689Skan      return 1;
220169689Skan    }
221169689Skan  return 0;
222169689Skan}
223169689Skan
224169689Skanint
225169689Skan__gthr_win32_recursive_mutex_trylock (__gthread_recursive_mutex_t *mutex)
226169689Skan{
227169689Skan  DWORD me = GetCurrentThreadId();
228169689Skan  if (__GTHR_W32_InterlockedCompareExchange (&mutex->counter, 0, -1) < 0)
229169689Skan    {
230169689Skan      mutex->depth = 1;
231169689Skan      mutex->owner = me;
232169689Skan    }
233169689Skan  else if (mutex->owner == me)
234169689Skan    ++(mutex->depth);
235169689Skan  else
236169689Skan    return 1;
237169689Skan
238169689Skan  return 0;
239169689Skan}
240169689Skan
241169689Skanint
242169689Skan__gthr_win32_recursive_mutex_unlock (__gthread_recursive_mutex_t *mutex)
243169689Skan{
244169689Skan  --(mutex->depth);
245169689Skan  if (mutex->depth == 0)
246169689Skan    {
247169689Skan      mutex->owner = 0;
248169689Skan
249169689Skan      if (InterlockedDecrement (&mutex->counter) >= 0)
250169689Skan	return ReleaseSemaphore (mutex->sema, 1, NULL) ? 0 : 1;
251169689Skan    }
252169689Skan
253169689Skan  return 0;
254169689Skan}
255