Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
6515 serge 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 .
6
   Modified and moved to separate file by Danny Smith
7
   .
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
.  */
29
 
30
#include 
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
}