gthr-win32.c revision 146895
1163953Srrs/* Implementation of W32-specific threads compatibility routines for
2169382Srrs   libgcc2.  */
3235828Stuexen
4235828Stuexen/* Copyright (C) 1999, 2000, 2002, 2004 Free Software Foundation, Inc.
5163953Srrs   Contributed by Mumit Khan <khan@xraylith.wisc.edu>.
6163953Srrs   Modified and moved to separate file by Danny Smith
7163953Srrs   <dannysmith@users.sourceforge.net>.
8163953Srrs
9163953SrrsThis file is part of GCC.
10228653Stuexen
11163953SrrsGCC is free software; you can redistribute it and/or modify it under
12163953Srrsthe terms of the GNU General Public License as published by the Free
13163953SrrsSoftware Foundation; either version 2, or (at your option) any later
14228653Stuexenversion.
15163953Srrs
16163953SrrsGCC is distributed in the hope that it will be useful, but WITHOUT ANY
17163953SrrsWARRANTY; without even the implied warranty of MERCHANTABILITY or
18163953SrrsFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
19163953Srrsfor more details.
20163953Srrs
21163953SrrsYou should have received a copy of the GNU General Public License
22163953Srrsalong with GCC; see the file COPYING.  If not, write to the Free
23163953SrrsSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA
24163953Srrs02111-1307, USA.  */
25163953Srrs
26163953Srrs/* As a special exception, if you link this library with other files,
27163953Srrs   some of which are compiled with GCC, to produce an executable,
28163953Srrs   this library does not by itself cause the resulting executable
29163953Srrs   to be covered by the GNU General Public License.
30163953Srrs   This exception does not however invalidate any other reasons why
31163953Srrs   the executable file might be covered by the GNU General Public License.  */
32163953Srrs
33163953Srrs
34163953Srrs#include <windows.h>
35163953Srrs#ifndef __GTHREAD_HIDE_WIN32API
36163953Srrs# define __GTHREAD_HIDE_WIN32API 1
37163953Srrs#endif
38163953Srrs#undef  __GTHREAD_I486_INLINE_LOCK_PRIMITIVES
39163953Srrs#define __GTHREAD_I486_INLINE_LOCK_PRIMITIVES
40163953Srrs#include <gthr-win32.h>
41163953Srrs
42163953Srrs/* Windows32 threads specific definitions. The windows32 threading model
43163953Srrs   does not map well into pthread-inspired gcc's threading model, and so
44163953Srrs   there are caveats one needs to be aware of.
45163953Srrs
46163953Srrs   1. The destructor supplied to __gthread_key_create is ignored for
47169208Srrs      generic x86-win32 ports. This will certainly cause memory leaks
48163953Srrs      due to unreclaimed eh contexts (sizeof (eh_context) is at least
49167598Srrs      24 bytes for x86 currently).
50163953Srrs
51170091Srrs      This memory leak may be significant for long-running applications
52170091Srrs      that make heavy use of C++ EH.
53170091Srrs
54170091Srrs      However, Mingw runtime (version 0.3 or newer) provides a mechanism
55170091Srrs      to emulate pthreads key dtors; the runtime provides a special DLL,
56170091Srrs      linked in if -mthreads option is specified, that runs the dtors in
57170091Srrs      the reverse order of registration when each thread exits. If
58170091Srrs      -mthreads option is not given, a stub is linked in instead of the
59170091Srrs      DLL, which results in memory leak. Other x86-win32 ports can use
60170091Srrs      the same technique of course to avoid the leak.
61170091Srrs
62170091Srrs   2. The error codes returned are non-POSIX like, and cast into ints.
63170091Srrs      This may cause incorrect error return due to truncation values on
64170091Srrs      hw where sizeof (DWORD) > sizeof (int).
65170091Srrs
66170091Srrs   3. We are currently using a special mutex instead of the Critical
67170091Srrs      Sections, since Win9x does not support TryEnterCriticalSection
68170091Srrs      (while NT does).
69170091Srrs
70170091Srrs   The basic framework should work well enough. In the long term, GCC
71218211Srrs   needs to use Structured Exception Handling on Windows32.  */
72170091Srrs
73208160Srrsint
74208160Srrs__gthr_win32_once (__gthread_once_t *once, void (*func) (void))
75208160Srrs{
76208160Srrs  if (once == NULL || func == NULL)
77167598Srrs    return EINVAL;
78167598Srrs
79163953Srrs  if (! once->done)
80208160Srrs    {
81163953Srrs      if (InterlockedIncrement (&(once->started)) == 0)
82163953Srrs        {
83167598Srrs	  (*func) ();
84228653Stuexen	  once->done = TRUE;
85163953Srrs	}
86167598Srrs      else
87225676Stuexen	{
88228653Stuexen	  /* Another thread is currently executing the code, so wait for it
89208160Srrs	     to finish; yield the CPU in the meantime.  If performance
90208160Srrs	     does become an issue, the solution is to use an Event that
91175751Srrs	     we wait on here (and set above), but that implies a place to
92167598Srrs	     create the event before this routine is called.  */
93163953Srrs	  while (! once->done)
94163953Srrs	    Sleep (0);
95163953Srrs	}
96167598Srrs    }
97167598Srrs  return 0;
98163953Srrs}
99258221Stuexen
100208160Srrs/* Windows32 thread local keys don't support destructors; this leads to
101208160Srrs   leaks, especially in threaded applications making extensive use of
102208160Srrs   C++ EH. Mingw uses a thread-support DLL to work-around this problem.  */
103258765Stuexen
104258765Stuexenint
105258765Stuexen__gthr_win32_key_create (__gthread_key_t *key, void (*dtor) (void *))
106208160Srrs{
107258221Stuexen  int status = 0;
108208160Srrs  DWORD tls_index = TlsAlloc ();
109208160Srrs  if (tls_index != 0xFFFFFFFF)
110167598Srrs    {
111167598Srrs      *key = tls_index;
112167598Srrs#ifdef MINGW32_SUPPORTS_MT_EH
113163953Srrs      /* Mingw runtime will run the dtors in reverse order for each thread
114163953Srrs         when the thread exits.  */
115178251Srrs      status = __mingwthr_key_dtor (*key, dtor);
116180387Srrs#endif
117167598Srrs    }
118167598Srrs  else
119163953Srrs    status = (int) GetLastError ();
120167598Srrs  return status;
121163953Srrs}
122167598Srrs
123167598Srrsint
124197288Srrs__gthr_win32_key_delete (__gthread_key_t key)
125167598Srrs{
126167598Srrs  return (TlsFree (key) != 0) ? 0 : (int) GetLastError ();
127167598Srrs}
128167598Srrs
129167598Srrsvoid *
130163953Srrs__gthr_win32_getspecific (__gthread_key_t key)
131163953Srrs{
132167598Srrs  DWORD lasterror;
133163953Srrs  void *ptr;
134167598Srrs  lasterror = GetLastError();
135167598Srrs  ptr = TlsGetValue(key);
136167598Srrs  SetLastError( lasterror );
137167598Srrs  return ptr;
138167598Srrs}
139163953Srrs
140167598Srrsint
141163953Srrs__gthr_win32_setspecific (__gthread_key_t key, const void *ptr)
142163953Srrs{
143163953Srrs  return (TlsSetValue (key, (void*) ptr) != 0) ? 0 : (int) GetLastError ();
144180387Srrs}
145163953Srrs
146163953Srrsvoid
147167598Srrs__gthr_win32_mutex_init_function (__gthread_mutex_t *mutex)
148239035Stuexen{
149163953Srrs  mutex->counter = -1;
150167598Srrs  mutex->sema = CreateSemaphore (NULL, 0, 65535, NULL);
151163953Srrs}
152167598Srrs
153239035Stuexenint
154167598Srrs__gthr_win32_mutex_lock (__gthread_mutex_t *mutex)
155167598Srrs{
156167598Srrs  if (InterlockedIncrement (&mutex->counter) == 0 ||
157167598Srrs      WaitForSingleObject (mutex->sema, INFINITE) == WAIT_OBJECT_0)
158167598Srrs    return 0;
159167598Srrs  else
160167598Srrs    {
161167598Srrs      /* WaitForSingleObject returns WAIT_FAILED, and we can only do
162167598Srrs         some best-effort cleanup here.  */
163167598Srrs      InterlockedDecrement (&mutex->counter);
164167598Srrs      return 1;
165167598Srrs    }
166167598Srrs}
167167598Srrs
168172091Srrsint
169167598Srrs__gthr_win32_mutex_trylock (__gthread_mutex_t *mutex)
170167598Srrs{
171167598Srrs  if (__GTHR_W32_InterlockedCompareExchange (&mutex->counter, 0, -1) < 0)
172179783Srrs    return 0;
173196610Stuexen  else
174232724Stuexen    return 1;
175167598Srrs}
176167598Srrs
177167598Srrsint
178232866Srrs__gthr_win32_mutex_unlock (__gthread_mutex_t *mutex)
179167598Srrs{
180167598Srrs  if (InterlockedDecrement (&mutex->counter) >= 0)
181167598Srrs    return ReleaseSemaphore (mutex->sema, 1, NULL) ? 0 : 1;
182167598Srrs  else
183167598Srrs    return 0;
184163953Srrs}
185163953Srrs