2 * pthread emulation for re-entrant libcs
4 * Copyright 1999 Ove Kåven
5 * Copyright 2003 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "wine/port.h"
25 #define _GNU_SOURCE /* we may need to override some GNU extensions */
36 #include <sys/types.h>
38 # include <sys/socket.h>
40 #ifdef HAVE_SYS_MMAN_H
48 #include "wine/pthread.h"
50 #define P_OUTPUT(stuff) write(2,stuff,strlen(stuff))
52 static const struct wine_pthread_functions functions;
54 DECL_GLOBAL_CONSTRUCTOR(pthread_init) { wine_pthread_init_process( &functions ); }
56 static inline int init_done(void) { return GetProcessHeap() != 0; }
58 /* NOTE: This is a truly extremely incredibly ugly hack!
59 * But it does seem to work... */
61 /* assume that pthread_mutex_t has room for at least one pointer,
62 * and hope that the users of pthread_mutex_t considers it opaque
63 * (never checks what's in it)
64 * also: assume that static initializer sets pointer to NULL
71 CRITICAL_SECTION *critsect;
74 /* see wine_mutex above for comments */
79 struct pthread_thread_init
81 void* (*start_routine)(void*);
85 static DWORD CALLBACK pthread_thread_start(LPVOID data)
87 struct pthread_thread_init init = *(struct pthread_thread_init*)data;
88 HeapFree(GetProcessHeap(),0,data);
89 return (DWORD)init.start_routine(init.arg);
92 static int wine_pthread_create(pthread_t* thread, const pthread_attr_t* attr, void*
93 (*start_routine)(void *), void* arg)
96 struct pthread_thread_init* idata = HeapAlloc(GetProcessHeap(), 0, sizeof(struct pthread_thread_init));
98 idata->start_routine = start_routine;
100 hThread = CreateThread( NULL, 0, pthread_thread_start, idata, 0, (LPDWORD)thread);
103 CloseHandle(hThread);
106 HeapFree(GetProcessHeap(),0,idata); /* free idata struct on failure */
113 static int wine_pthread_cancel(pthread_t thread)
115 HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, (DWORD)thread);
117 if(!TerminateThread(hThread, 0))
119 CloseHandle(hThread);
120 return EINVAL; /* return error */
123 CloseHandle(hThread);
125 return 0; /* return success */
128 static int wine_pthread_join(pthread_t thread, void **value_ptr)
130 HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, (DWORD)thread);
132 WaitForSingleObject(hThread, INFINITE);
133 if(!GetExitCodeThread(hThread, (LPDWORD)value_ptr))
135 CloseHandle(hThread);
136 return EINVAL; /* FIXME: make this more correctly match */
137 } /* windows errors */
139 CloseHandle(hThread);
143 /*FIXME: not sure what to do with this one... */
144 static int wine_pthread_detach(pthread_t thread)
146 P_OUTPUT("FIXME:pthread_detach\n");
150 /***** MUTEXES *****/
152 static int wine_pthread_mutex_init(pthread_mutex_t *mutex,
153 const pthread_mutexattr_t *mutexattr)
155 /* glibc has a tendency to initialize mutexes very often, even
156 in situations where they are not really used later on.
158 As for us, initializing a mutex is very expensive, we postpone
159 the real initialization until the time the mutex is first used. */
161 ((wine_mutex)mutex)->critsect = NULL;
165 static void mutex_real_init( pthread_mutex_t *mutex )
167 CRITICAL_SECTION *critsect = HeapAlloc(GetProcessHeap(), 0, sizeof(CRITICAL_SECTION));
168 RtlInitializeCriticalSection(critsect);
170 if (InterlockedCompareExchangePointer((void**)&(((wine_mutex)mutex)->critsect),critsect,NULL) != NULL) {
171 /* too late, some other thread already did it */
172 RtlDeleteCriticalSection(critsect);
173 HeapFree(GetProcessHeap(), 0, critsect);
177 static int wine_pthread_mutex_lock(pthread_mutex_t *mutex)
179 if (!init_done()) return 0;
180 if (!((wine_mutex)mutex)->critsect)
181 mutex_real_init( mutex );
183 RtlEnterCriticalSection(((wine_mutex)mutex)->critsect);
187 static int wine_pthread_mutex_trylock(pthread_mutex_t *mutex)
189 if (!init_done()) return 0;
190 if (!((wine_mutex)mutex)->critsect)
191 mutex_real_init( mutex );
193 if (!RtlTryEnterCriticalSection(((wine_mutex)mutex)->critsect)) {
200 static int wine_pthread_mutex_unlock(pthread_mutex_t *mutex)
202 if (!((wine_mutex)mutex)->critsect) return 0;
203 RtlLeaveCriticalSection(((wine_mutex)mutex)->critsect);
207 static int wine_pthread_mutex_destroy(pthread_mutex_t *mutex)
209 if (!((wine_mutex)mutex)->critsect) return 0;
210 if (((wine_mutex)mutex)->critsect->RecursionCount) {
211 #if 0 /* there seems to be a bug in libc6 that makes this a bad idea */
214 while (((wine_mutex)mutex)->critsect->RecursionCount)
215 RtlLeaveCriticalSection(((wine_mutex)mutex)->critsect);
218 RtlDeleteCriticalSection(((wine_mutex)mutex)->critsect);
219 HeapFree(GetProcessHeap(), 0, ((wine_mutex)mutex)->critsect);
220 ((wine_mutex)mutex)->critsect = NULL;
224 /***** READ-WRITE LOCKS *****/
226 static void rwlock_real_init(pthread_rwlock_t *rwlock)
228 RTL_RWLOCK *lock = HeapAlloc(GetProcessHeap(), 0, sizeof(RTL_RWLOCK));
229 RtlInitializeResource(lock);
231 if (InterlockedCompareExchangePointer((void**)&(((wine_rwlock)rwlock)->lock),lock,NULL) != NULL) {
232 /* too late, some other thread already did it */
233 RtlDeleteResource(lock);
234 HeapFree(GetProcessHeap(), 0, lock);
238 static int wine_pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *rwlock_attr)
240 ((wine_rwlock)rwlock)->lock = NULL;
244 static int wine_pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
246 if (!((wine_rwlock)rwlock)->lock) return 0;
247 RtlDeleteResource(((wine_rwlock)rwlock)->lock);
248 HeapFree(GetProcessHeap(), 0, ((wine_rwlock)rwlock)->lock);
252 static int wine_pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
254 if (!init_done()) return 0;
255 if (!((wine_rwlock)rwlock)->lock)
256 rwlock_real_init( rwlock );
259 if (RtlAcquireResourceShared(((wine_rwlock)rwlock)->lock, TRUE))
263 static int wine_pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
265 if (!init_done()) return 0;
266 if (!((wine_rwlock)rwlock)->lock)
267 rwlock_real_init( rwlock );
269 if (!RtlAcquireResourceShared(((wine_rwlock)rwlock)->lock, FALSE)) {
276 static int wine_pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
278 if (!init_done()) return 0;
279 if (!((wine_rwlock)rwlock)->lock)
280 rwlock_real_init( rwlock );
283 if (RtlAcquireResourceExclusive(((wine_rwlock)rwlock)->lock, TRUE))
287 static int wine_pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
289 if (!init_done()) return 0;
290 if (!((wine_rwlock)rwlock)->lock)
291 rwlock_real_init( rwlock );
293 if (!RtlAcquireResourceExclusive(((wine_rwlock)rwlock)->lock, FALSE)) {
300 static int wine_pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
302 if (!((wine_rwlock)rwlock)->lock) return 0;
303 RtlReleaseResource( ((wine_rwlock)rwlock)->lock );
309 static pthread_t wine_pthread_self(void)
311 return (pthread_t)GetCurrentThreadId();
314 static int wine_pthread_equal(pthread_t thread1, pthread_t thread2)
316 return (DWORD)thread1 == (DWORD)thread2;
319 static void wine_pthread_exit(void *retval, char *currentframe)
321 ExitThread((DWORD)retval);
324 static void *wine_get_thread_data(void)
326 return NtCurrentTeb()->pthread_data;
329 static void wine_set_thread_data( void *data )
331 NtCurrentTeb()->pthread_data = data;
334 static const struct wine_pthread_functions functions =
336 wine_get_thread_data, /* ptr_get_thread_data */
337 wine_set_thread_data, /* ptr_set_thread_data */
338 wine_pthread_self, /* ptr_pthread_self */
339 wine_pthread_equal, /* ptr_pthread_equal */
340 wine_pthread_create, /* ptr_pthread_create */
341 wine_pthread_cancel, /* ptr_pthread_cancel */
342 wine_pthread_join, /* ptr_pthread_join */
343 wine_pthread_detach, /* ptr_pthread_detach */
344 wine_pthread_exit, /* ptr_pthread_exit */
345 wine_pthread_mutex_init, /* ptr_pthread_mutex_init */
346 wine_pthread_mutex_lock, /* ptr_pthread_mutex_lock */
347 wine_pthread_mutex_trylock, /* ptr_pthread_mutex_trylock */
348 wine_pthread_mutex_unlock, /* ptr_pthread_mutex_unlock */
349 wine_pthread_mutex_destroy, /* ptr_pthread_mutex_destroy */
350 wine_pthread_rwlock_init, /* ptr_pthread_rwlock_init */
351 wine_pthread_rwlock_destroy, /* ptr_pthread_rwlock_destroy */
352 wine_pthread_rwlock_rdlock, /* ptr_pthread_rwlock_rdlock */
353 wine_pthread_rwlock_tryrdlock, /* ptr_pthread_rwlock_tryrdlock */
354 wine_pthread_rwlock_wrlock, /* ptr_pthread_rwlock_wrlock */
355 wine_pthread_rwlock_trywrlock, /* ptr_pthread_rwlock_trywrlock */
356 wine_pthread_rwlock_unlock /* ptr_pthread_rwlock_unlock */