shell32: Implement UnixFolder_IShellFolder2_GetDefaultColumn.
[wine/multimedia.git] / dlls / ntdll / pthread.c
blob60b6033c3f3d629313dfff4d895ef61c0cc9055b
1 /*
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "config.h"
23 #include "wine/port.h"
25 #ifdef HAVE_PTHREAD_H
27 #define _GNU_SOURCE /* we may need to override some GNU extensions */
29 #include <assert.h>
30 #include <errno.h>
31 #include <stdarg.h>
32 #include <stdlib.h>
33 #include <setjmp.h>
34 #ifdef HAVE_UNISTD_H
35 # include <unistd.h>
36 #endif
37 #include <string.h>
38 #include <sys/types.h>
39 #ifdef HAVE_SYS_SOCKET_H
40 # include <sys/socket.h>
41 #endif
42 #ifdef HAVE_SYS_MMAN_H
43 #include <sys/mman.h>
44 #endif
46 #include "windef.h"
47 #include "winbase.h"
48 #include "winternl.h"
49 #include "ntdll_misc.h"
50 #include "wine/pthread.h"
52 #define P_OUTPUT(stuff) write(2,stuff,strlen(stuff))
54 /* NOTE: This is a truly extremely incredibly ugly hack!
55 * But it does seem to work... */
57 /* assume that pthread_mutex_t has room for at least one pointer,
58 * and hope that the users of pthread_mutex_t considers it opaque
59 * (never checks what's in it)
60 * also: assume that static initializer sets pointer to NULL
62 typedef struct
64 #ifdef __GLIBC__
65 int reserved;
66 #endif
67 CRITICAL_SECTION *critsect;
68 } *wine_mutex;
70 /* see wine_mutex above for comments */
71 typedef struct {
72 RTL_RWLOCK *lock;
73 } *wine_rwlock;
75 struct pthread_thread_init
77 void* (*start_routine)(void*);
78 void* arg;
81 static void wine_pthread_exit(void *retval, char *currentframe)
83 RtlFreeThreadActivationContextStack();
84 RtlExitUserThread( PtrToUlong(retval) );
87 static void CALLBACK pthread_thread_start(LPVOID data)
89 struct pthread_thread_init init = *(struct pthread_thread_init*)data;
90 RtlFreeHeap(GetProcessHeap(),0,data);
91 wine_pthread_exit( init.start_routine(init.arg), NULL );
94 static int wine_pthread_create(pthread_t* thread, const pthread_attr_t* attr, void*
95 (*start_routine)(void *), void* arg)
97 HANDLE handle;
98 CLIENT_ID client_id;
99 struct pthread_thread_init* idata;
101 if (!(idata = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(*idata)))) return ENOMEM;
103 idata->start_routine = start_routine;
104 idata->arg = arg;
105 if (!RtlCreateUserThread( NtCurrentProcess(), NULL, FALSE, NULL, 0, 0,
106 pthread_thread_start, idata, &handle, &client_id ))
108 NtClose( handle );
109 *thread = (pthread_t)client_id.UniqueThread;
111 else
113 RtlFreeHeap( GetProcessHeap(), 0, idata );
114 return EAGAIN;
117 return 0;
120 static int wine_pthread_cancel(pthread_t thread)
122 CLIENT_ID cid;
123 NTSTATUS status;
124 HANDLE handle;
126 cid.UniqueProcess = 0;
127 cid.UniqueThread = (HANDLE)thread;
128 status = NtOpenThread( &handle, THREAD_TERMINATE, NULL, &cid );
129 if (!status)
131 status = NtTerminateThread( handle, 0 );
132 NtClose( handle );
134 if (status) return EINVAL;
135 return 0;
138 static int wine_pthread_join(pthread_t thread, void **value_ptr)
140 THREAD_BASIC_INFORMATION info;
141 CLIENT_ID cid;
142 NTSTATUS status;
143 HANDLE handle;
145 cid.UniqueProcess = 0;
146 cid.UniqueThread = (HANDLE)thread;
147 status = NtOpenThread( &handle, THREAD_QUERY_INFORMATION|SYNCHRONIZE, NULL, &cid );
148 if (!status)
150 NtWaitForMultipleObjects( 1, &handle, FALSE, FALSE, NULL );
151 status = NtQueryInformationThread( handle, ThreadBasicInformation, &info, sizeof(info), NULL );
152 NtClose( handle );
153 if (!status) *value_ptr = UlongToPtr(info.ExitStatus);
155 if (status) return EINVAL; /* FIXME: make this more correctly match windows errors */
156 return 0;
159 /*FIXME: not sure what to do with this one... */
160 static int wine_pthread_detach(pthread_t thread)
162 P_OUTPUT("FIXME:pthread_detach\n");
163 return 0;
166 /***** MUTEXES *****/
168 static int wine_pthread_mutex_init(pthread_mutex_t *mutex,
169 const pthread_mutexattr_t *mutexattr)
171 /* glibc has a tendency to initialize mutexes very often, even
172 in situations where they are not really used later on.
174 As for us, initializing a mutex is very expensive, we postpone
175 the real initialization until the time the mutex is first used. */
177 ((wine_mutex)mutex)->critsect = NULL;
178 return 0;
181 static void mutex_real_init( pthread_mutex_t *mutex )
183 CRITICAL_SECTION *critsect = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(CRITICAL_SECTION));
184 RtlInitializeCriticalSection(critsect);
186 if (interlocked_cmpxchg_ptr((void**)&(((wine_mutex)mutex)->critsect),critsect,NULL) != NULL) {
187 /* too late, some other thread already did it */
188 RtlDeleteCriticalSection(critsect);
189 RtlFreeHeap(GetProcessHeap(), 0, critsect);
193 static int wine_pthread_mutex_lock(pthread_mutex_t *mutex)
195 if (!((wine_mutex)mutex)->critsect)
196 mutex_real_init( mutex );
198 RtlEnterCriticalSection(((wine_mutex)mutex)->critsect);
199 return 0;
202 static int wine_pthread_mutex_trylock(pthread_mutex_t *mutex)
204 if (!((wine_mutex)mutex)->critsect)
205 mutex_real_init( mutex );
207 if (!RtlTryEnterCriticalSection(((wine_mutex)mutex)->critsect)) return EBUSY;
208 return 0;
211 static int wine_pthread_mutex_unlock(pthread_mutex_t *mutex)
213 CRITICAL_SECTION *crit = ((wine_mutex)mutex)->critsect;
215 if (!crit) return 0;
216 if (crit->OwningThread != ULongToHandle(GetCurrentThreadId())) return EPERM;
217 RtlLeaveCriticalSection( crit );
218 return 0;
221 static int wine_pthread_mutex_destroy(pthread_mutex_t *mutex)
223 if (!((wine_mutex)mutex)->critsect) return 0;
224 if (((wine_mutex)mutex)->critsect->RecursionCount) {
225 #if 0 /* there seems to be a bug in libc6 that makes this a bad idea */
226 return EBUSY;
227 #else
228 while (((wine_mutex)mutex)->critsect->RecursionCount)
229 RtlLeaveCriticalSection(((wine_mutex)mutex)->critsect);
230 #endif
232 RtlDeleteCriticalSection(((wine_mutex)mutex)->critsect);
233 RtlFreeHeap(GetProcessHeap(), 0, ((wine_mutex)mutex)->critsect);
234 ((wine_mutex)mutex)->critsect = NULL;
235 return 0;
238 /***** READ-WRITE LOCKS *****/
240 static void rwlock_real_init(pthread_rwlock_t *rwlock)
242 RTL_RWLOCK *lock = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(RTL_RWLOCK));
243 RtlInitializeResource(lock);
245 if (interlocked_cmpxchg_ptr((void**)&(((wine_rwlock)rwlock)->lock),lock,NULL) != NULL) {
246 /* too late, some other thread already did it */
247 RtlDeleteResource(lock);
248 RtlFreeHeap(GetProcessHeap(), 0, lock);
252 static int wine_pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *rwlock_attr)
254 ((wine_rwlock)rwlock)->lock = NULL;
255 return 0;
258 static int wine_pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
260 if (!((wine_rwlock)rwlock)->lock) return 0;
261 RtlDeleteResource(((wine_rwlock)rwlock)->lock);
262 RtlFreeHeap(GetProcessHeap(), 0, ((wine_rwlock)rwlock)->lock);
263 return 0;
266 static int wine_pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
268 if (!((wine_rwlock)rwlock)->lock)
269 rwlock_real_init( rwlock );
271 while(TRUE)
272 if (RtlAcquireResourceShared(((wine_rwlock)rwlock)->lock, TRUE))
273 return 0;
276 static int wine_pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
278 if (!((wine_rwlock)rwlock)->lock)
279 rwlock_real_init( rwlock );
281 if (!RtlAcquireResourceShared(((wine_rwlock)rwlock)->lock, FALSE)) return EBUSY;
282 return 0;
285 static int wine_pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
287 if (!((wine_rwlock)rwlock)->lock)
288 rwlock_real_init( rwlock );
290 while(TRUE)
291 if (RtlAcquireResourceExclusive(((wine_rwlock)rwlock)->lock, TRUE))
292 return 0;
295 static int wine_pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
297 if (!((wine_rwlock)rwlock)->lock)
298 rwlock_real_init( rwlock );
300 if (!RtlAcquireResourceExclusive(((wine_rwlock)rwlock)->lock, FALSE)) return EBUSY;
301 return 0;
304 static int wine_pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
306 if (!((wine_rwlock)rwlock)->lock) return 0;
307 RtlReleaseResource( ((wine_rwlock)rwlock)->lock );
308 return 0;
311 /***** CONDITIONS *****/
313 /* The condition code is basically cut-and-pasted from Douglas
314 * Schmidt's paper:
315 * "Strategies for Implementing POSIX Condition Variables on Win32",
316 * at http://www.cs.wustl.edu/~schmidt/win32-cv-1.html and
317 * http://www.cs.wustl.edu/~schmidt/win32-cv-2.html.
318 * This paper formed the basis for the condition variable
319 * implementation used in the ACE library.
322 /* Possible problems with ACE:
323 * - unimplemented pthread_mutexattr_init
325 typedef struct {
326 /* Number of waiting threads. */
327 int waiters_count;
329 /* Serialize access to <waiters_count>. */
330 CRITICAL_SECTION waiters_count_lock;
333 * Semaphore used to queue up threads waiting for the condition to
334 * become signaled.
336 HANDLE sema;
339 * An auto-reset event used by the broadcast/signal thread to wait
340 * for all the waiting thread(s) to wake up and be released from the
341 * semaphore.
343 HANDLE waiters_done;
346 * Keeps track of whether we were broadcasting or signaling. This
347 * allows us to optimize the code if we're just signaling.
349 size_t was_broadcast;
350 } wine_cond_detail;
352 /* see wine_mutex above for comments */
353 typedef struct {
354 wine_cond_detail *cond;
355 } *wine_cond;
357 static void wine_cond_real_init(pthread_cond_t *cond)
359 wine_cond_detail *detail = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(wine_cond_detail));
360 detail->waiters_count = 0;
361 detail->was_broadcast = 0;
362 NtCreateSemaphore( &detail->sema, SEMAPHORE_ALL_ACCESS, NULL, 0, 0x7fffffff );
363 NtCreateEvent( &detail->waiters_done, EVENT_ALL_ACCESS, NULL, FALSE, FALSE );
364 RtlInitializeCriticalSection (&detail->waiters_count_lock);
366 if (interlocked_cmpxchg_ptr((void**)&(((wine_cond)cond)->cond), detail, NULL) != NULL)
368 /* too late, some other thread already did it */
369 P_OUTPUT("FIXME:pthread_cond_init:expect troubles...\n");
370 NtClose(detail->sema);
371 RtlDeleteCriticalSection(&detail->waiters_count_lock);
372 NtClose(detail->waiters_done);
373 RtlFreeHeap(GetProcessHeap(), 0, detail);
377 static int wine_pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr)
379 /* The same as for wine_pthread_mutex_init, we postpone initialization
380 until condition is really used.*/
381 ((wine_cond)cond)->cond = NULL;
382 return 0;
385 static int wine_pthread_cond_destroy(pthread_cond_t *cond)
387 wine_cond_detail *detail = ((wine_cond)cond)->cond;
389 if (!detail) return 0;
390 NtClose(detail->sema);
391 RtlDeleteCriticalSection(&detail->waiters_count_lock);
392 NtClose(detail->waiters_done);
393 RtlFreeHeap(GetProcessHeap(), 0, detail);
394 ((wine_cond)cond)->cond = NULL;
395 return 0;
398 static int wine_pthread_cond_signal(pthread_cond_t *cond)
400 int have_waiters;
401 wine_cond_detail *detail;
403 if ( !((wine_cond)cond)->cond ) wine_cond_real_init(cond);
404 detail = ((wine_cond)cond)->cond;
406 RtlEnterCriticalSection (&detail->waiters_count_lock);
407 have_waiters = detail->waiters_count > 0;
408 RtlLeaveCriticalSection (&detail->waiters_count_lock);
410 /* If there aren't any waiters, then this is a no-op. */
411 if (have_waiters)
412 NtReleaseSemaphore(detail->sema, 1, NULL);
414 return 0;
417 static int wine_pthread_cond_broadcast(pthread_cond_t *cond)
419 int have_waiters = 0;
420 wine_cond_detail *detail;
422 if ( !((wine_cond)cond)->cond ) wine_cond_real_init(cond);
423 detail = ((wine_cond)cond)->cond;
426 * This is needed to ensure that <waiters_count> and <was_broadcast> are
427 * consistent relative to each other.
429 RtlEnterCriticalSection (&detail->waiters_count_lock);
431 if (detail->waiters_count > 0) {
433 * We are broadcasting, even if there is just one waiter...
434 * Record that we are broadcasting, which helps optimize
435 * <pthread_cond_wait> for the non-broadcast case.
437 detail->was_broadcast = 1;
438 have_waiters = 1;
441 if (have_waiters) {
442 /* Wake up all the waiters atomically. */
443 NtReleaseSemaphore(detail->sema, detail->waiters_count, NULL);
445 RtlLeaveCriticalSection (&detail->waiters_count_lock);
447 /* Wait for all the awakened threads to acquire the counting semaphore. */
448 NtWaitForMultipleObjects( 1, &detail->waiters_done, FALSE, FALSE, NULL );
451 * This assignment is okay, even without the <waiters_count_lock> held
452 * because no other waiter threads can wake up to access it.
454 detail->was_broadcast = 0;
456 else
457 RtlLeaveCriticalSection (&detail->waiters_count_lock);
458 return 0;
461 static int wine_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
463 wine_cond_detail *detail;
464 int last_waiter;
466 if ( !((wine_cond)cond)->cond ) wine_cond_real_init(cond);
467 detail = ((wine_cond)cond)->cond;
469 /* Avoid race conditions. */
470 RtlEnterCriticalSection (&detail->waiters_count_lock);
471 detail->waiters_count++;
472 RtlLeaveCriticalSection (&detail->waiters_count_lock);
474 RtlLeaveCriticalSection ( ((wine_mutex)mutex)->critsect );
475 NtWaitForMultipleObjects( 1, &detail->sema, FALSE, FALSE, NULL );
477 /* Reacquire lock to avoid race conditions. */
478 RtlEnterCriticalSection (&detail->waiters_count_lock);
480 /* We're no longer waiting... */
481 detail->waiters_count--;
483 /* Check to see if we're the last waiter after <pthread_cond_broadcast>. */
484 last_waiter = detail->was_broadcast && detail->waiters_count == 0;
486 RtlLeaveCriticalSection (&detail->waiters_count_lock);
489 * If we're the last waiter thread during this particular broadcast
490 * then let all the other threads proceed.
492 if (last_waiter) NtSetEvent( detail->waiters_done, NULL );
493 RtlEnterCriticalSection (((wine_mutex)mutex)->critsect);
494 return 0;
497 static int wine_pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
498 const struct timespec *abstime)
500 LARGE_INTEGER time;
501 int last_waiter;
502 wine_cond_detail *detail;
504 if ( !((wine_cond)cond)->cond ) wine_cond_real_init(cond);
505 detail = ((wine_cond)cond)->cond;
507 /* Avoid race conditions. */
508 RtlEnterCriticalSection (&detail->waiters_count_lock);
509 detail->waiters_count++;
510 RtlLeaveCriticalSection (&detail->waiters_count_lock);
512 RtlLeaveCriticalSection (((wine_mutex)mutex)->critsect);
514 time.QuadPart = (ULONGLONG)abstime->tv_sec * 10000000 + abstime->tv_nsec / 100;
515 time.QuadPart = -time.QuadPart;
516 NtWaitForMultipleObjects( 1, &detail->sema, FALSE, FALSE, &time );
518 /* Reacquire lock to avoid race conditions. */
519 RtlEnterCriticalSection (&detail->waiters_count_lock);
521 /* We're no longer waiting... */
522 detail->waiters_count--;
524 /* Check to see if we're the last waiter after <pthread_cond_broadcast>. */
525 last_waiter = detail->was_broadcast && detail->waiters_count == 0;
527 RtlLeaveCriticalSection (&detail->waiters_count_lock);
530 * If we're the last waiter thread during this particular broadcast
531 * then let all the other threads proceed.
533 if (last_waiter) NtSetEvent( detail->waiters_done, NULL );
534 RtlEnterCriticalSection (((wine_mutex)mutex)->critsect);
535 return 0;
538 /***** MISC *****/
540 static pthread_t wine_pthread_self(void)
542 return (pthread_t)GetCurrentThreadId();
545 static int wine_pthread_equal(pthread_t thread1, pthread_t thread2)
547 return (DWORD)thread1 == (DWORD)thread2;
550 static void *wine_get_thread_data(void)
552 return ntdll_get_thread_data()->pthread_data;
555 static void wine_set_thread_data( void *data )
557 ntdll_get_thread_data()->pthread_data = data;
560 static const struct wine_pthread_callbacks callbacks =
562 wine_get_thread_data, /* ptr_get_thread_data */
563 wine_set_thread_data, /* ptr_set_thread_data */
564 wine_pthread_self, /* ptr_pthread_self */
565 wine_pthread_equal, /* ptr_pthread_equal */
566 wine_pthread_create, /* ptr_pthread_create */
567 wine_pthread_cancel, /* ptr_pthread_cancel */
568 wine_pthread_join, /* ptr_pthread_join */
569 wine_pthread_detach, /* ptr_pthread_detach */
570 wine_pthread_exit, /* ptr_pthread_exit */
571 wine_pthread_mutex_init, /* ptr_pthread_mutex_init */
572 wine_pthread_mutex_lock, /* ptr_pthread_mutex_lock */
573 wine_pthread_mutex_trylock, /* ptr_pthread_mutex_trylock */
574 wine_pthread_mutex_unlock, /* ptr_pthread_mutex_unlock */
575 wine_pthread_mutex_destroy, /* ptr_pthread_mutex_destroy */
576 wine_pthread_rwlock_init, /* ptr_pthread_rwlock_init */
577 wine_pthread_rwlock_destroy, /* ptr_pthread_rwlock_destroy */
578 wine_pthread_rwlock_rdlock, /* ptr_pthread_rwlock_rdlock */
579 wine_pthread_rwlock_tryrdlock, /* ptr_pthread_rwlock_tryrdlock */
580 wine_pthread_rwlock_wrlock, /* ptr_pthread_rwlock_wrlock */
581 wine_pthread_rwlock_trywrlock, /* ptr_pthread_rwlock_trywrlock */
582 wine_pthread_rwlock_unlock, /* ptr_pthread_rwlock_unlock */
583 wine_pthread_cond_init, /* ptr_pthread_cond_init */
584 wine_pthread_cond_destroy, /* ptr_pthread_cond_destroy */
585 wine_pthread_cond_signal, /* ptr_pthread_cond_signal */
586 wine_pthread_cond_broadcast, /* ptr_pthread_cond_broadcast */
587 wine_pthread_cond_wait, /* ptr_pthread_cond_wait */
588 wine_pthread_cond_timedwait /* ptr_pthread_cond_timedwait */
591 static struct wine_pthread_functions pthread_functions;
593 void pthread_init(void)
595 wine_pthread_get_functions( &pthread_functions, sizeof(pthread_functions) );
596 pthread_functions.init_process( &callbacks, sizeof(callbacks) );
599 #endif /* HAVE_PTHREAD_H */