wined3d: Correctly destroy the adapter on format initialization failure in no3d mode.
[wine/zf.git] / dlls / ntdll / sync.c
blobedbdd91c1b9f162da97e7241f5e8ef996ceec435
1 /*
2 * Process synchronisation
4 * Copyright 1996, 1997, 1998 Marcus Meissner
5 * Copyright 1997, 1999 Alexandre Julliard
6 * Copyright 1999, 2000 Juergen Schmied
7 * Copyright 2003 Eric Pouech
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include <limits.h>
25 #include <string.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <time.h>
31 #include "ntstatus.h"
32 #define WIN32_NO_STATUS
33 #define NONAMELESSUNION
34 #include "windef.h"
35 #include "winternl.h"
36 #include "wine/server.h"
37 #include "wine/debug.h"
38 #include "ntdll_misc.h"
41 /******************************************************************
42 * RtlRunOnceInitialize (NTDLL.@)
44 void WINAPI RtlRunOnceInitialize( RTL_RUN_ONCE *once )
46 once->Ptr = NULL;
49 /******************************************************************
50 * RtlRunOnceBeginInitialize (NTDLL.@)
52 DWORD WINAPI RtlRunOnceBeginInitialize( RTL_RUN_ONCE *once, ULONG flags, void **context )
54 if (flags & RTL_RUN_ONCE_CHECK_ONLY)
56 ULONG_PTR val = (ULONG_PTR)once->Ptr;
58 if (flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER;
59 if ((val & 3) != 2) return STATUS_UNSUCCESSFUL;
60 if (context) *context = (void *)(val & ~3);
61 return STATUS_SUCCESS;
64 for (;;)
66 ULONG_PTR next, val = (ULONG_PTR)once->Ptr;
68 switch (val & 3)
70 case 0: /* first time */
71 if (!InterlockedCompareExchangePointer( &once->Ptr,
72 (flags & RTL_RUN_ONCE_ASYNC) ? (void *)3 : (void *)1, 0 ))
73 return STATUS_PENDING;
74 break;
76 case 1: /* in progress, wait */
77 if (flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER;
78 next = val & ~3;
79 if (InterlockedCompareExchangePointer( &once->Ptr, (void *)((ULONG_PTR)&next | 1),
80 (void *)val ) == (void *)val)
81 NtWaitForKeyedEvent( 0, &next, FALSE, NULL );
82 break;
84 case 2: /* done */
85 if (context) *context = (void *)(val & ~3);
86 return STATUS_SUCCESS;
88 case 3: /* in progress, async */
89 if (!(flags & RTL_RUN_ONCE_ASYNC)) return STATUS_INVALID_PARAMETER;
90 return STATUS_PENDING;
95 /******************************************************************
96 * RtlRunOnceComplete (NTDLL.@)
98 DWORD WINAPI RtlRunOnceComplete( RTL_RUN_ONCE *once, ULONG flags, void *context )
100 if ((ULONG_PTR)context & 3) return STATUS_INVALID_PARAMETER;
102 if (flags & RTL_RUN_ONCE_INIT_FAILED)
104 if (context) return STATUS_INVALID_PARAMETER;
105 if (flags & RTL_RUN_ONCE_ASYNC) return STATUS_INVALID_PARAMETER;
107 else context = (void *)((ULONG_PTR)context | 2);
109 for (;;)
111 ULONG_PTR val = (ULONG_PTR)once->Ptr;
113 switch (val & 3)
115 case 1: /* in progress */
116 if (InterlockedCompareExchangePointer( &once->Ptr, context, (void *)val ) != (void *)val) break;
117 val &= ~3;
118 while (val)
120 ULONG_PTR next = *(ULONG_PTR *)val;
121 NtReleaseKeyedEvent( 0, (void *)val, FALSE, NULL );
122 val = next;
124 return STATUS_SUCCESS;
126 case 3: /* in progress, async */
127 if (!(flags & RTL_RUN_ONCE_ASYNC)) return STATUS_INVALID_PARAMETER;
128 if (InterlockedCompareExchangePointer( &once->Ptr, context, (void *)val ) != (void *)val) break;
129 return STATUS_SUCCESS;
131 default:
132 return STATUS_UNSUCCESSFUL;
137 /******************************************************************
138 * RtlRunOnceExecuteOnce (NTDLL.@)
140 DWORD WINAPI RtlRunOnceExecuteOnce( RTL_RUN_ONCE *once, PRTL_RUN_ONCE_INIT_FN func,
141 void *param, void **context )
143 DWORD ret = RtlRunOnceBeginInitialize( once, 0, context );
145 if (ret != STATUS_PENDING) return ret;
147 if (!func( once, param, context ))
149 RtlRunOnceComplete( once, RTL_RUN_ONCE_INIT_FAILED, NULL );
150 return STATUS_UNSUCCESSFUL;
153 return RtlRunOnceComplete( once, 0, context ? *context : NULL );
157 /* SRW locks implementation
159 * The memory layout used by the lock is:
161 * 32 31 16 0
162 * ________________ ________________
163 * | X| #exclusive | #shared |
164 * ¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
165 * Since there is no space left for a separate counter of shared access
166 * threads inside the locked section the #shared field is used for multiple
167 * purposes. The following table lists all possible states the lock can be
168 * in, notation: [X, #exclusive, #shared]:
170 * [0, 0, N] -> locked by N shared access threads, if N=0 it's unlocked
171 * [0, >=1, >=1] -> threads are requesting exclusive locks, but there are
172 * still shared access threads inside. #shared should not be incremented
173 * anymore!
174 * [1, >=1, >=0] -> lock is owned by an exclusive thread and the #shared
175 * counter can be used again to count the number of threads waiting in the
176 * queue for shared access.
178 * the following states are invalid and will never occur:
179 * [0, >=1, 0], [1, 0, >=0]
181 * The main problem arising from the fact that we have no separate counter
182 * of shared access threads inside the locked section is that in the state
183 * [0, >=1, >=1] above we cannot add additional waiting threads to the
184 * shared access queue - it wouldn't be possible to distinguish waiting
185 * threads and those that are still inside. To solve this problem the lock
186 * uses the following approach: a thread that isn't able to allocate a
187 * shared lock just uses the exclusive queue instead. As soon as the thread
188 * is woken up it is in the state [1, >=1, >=0]. In this state it's again
189 * possible to use the shared access queue. The thread atomically moves
190 * itself to the shared access queue and releases the exclusive lock, so
191 * that the "real" exclusive access threads have a chance. As soon as they
192 * are all ready the shared access threads are processed.
195 #define SRWLOCK_MASK_IN_EXCLUSIVE 0x80000000
196 #define SRWLOCK_MASK_EXCLUSIVE_QUEUE 0x7fff0000
197 #define SRWLOCK_MASK_SHARED_QUEUE 0x0000ffff
198 #define SRWLOCK_RES_EXCLUSIVE 0x00010000
199 #define SRWLOCK_RES_SHARED 0x00000001
201 #ifdef WORDS_BIGENDIAN
202 #define srwlock_key_exclusive(lock) ((void *)(((ULONG_PTR)&lock->Ptr + 1) & ~1))
203 #define srwlock_key_shared(lock) ((void *)(((ULONG_PTR)&lock->Ptr + 3) & ~1))
204 #else
205 #define srwlock_key_exclusive(lock) ((void *)(((ULONG_PTR)&lock->Ptr + 3) & ~1))
206 #define srwlock_key_shared(lock) ((void *)(((ULONG_PTR)&lock->Ptr + 1) & ~1))
207 #endif
209 static inline void srwlock_check_invalid( unsigned int val )
211 /* Throw exception if it's impossible to acquire/release this lock. */
212 if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) == SRWLOCK_MASK_EXCLUSIVE_QUEUE ||
213 (val & SRWLOCK_MASK_SHARED_QUEUE) == SRWLOCK_MASK_SHARED_QUEUE)
214 RtlRaiseStatus(STATUS_RESOURCE_NOT_OWNED);
217 static inline unsigned int srwlock_lock_exclusive( unsigned int *dest, int incr )
219 unsigned int val, tmp;
220 /* Atomically modifies the value of *dest by adding incr. If the shared
221 * queue is empty and there are threads waiting for exclusive access, then
222 * sets the mark SRWLOCK_MASK_IN_EXCLUSIVE to signal other threads that
223 * they are allowed again to use the shared queue counter. */
224 for (val = *dest;; val = tmp)
226 tmp = val + incr;
227 srwlock_check_invalid( tmp );
228 if ((tmp & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(tmp & SRWLOCK_MASK_SHARED_QUEUE))
229 tmp |= SRWLOCK_MASK_IN_EXCLUSIVE;
230 if ((tmp = InterlockedCompareExchange( (int *)dest, tmp, val )) == val)
231 break;
233 return val;
236 static inline unsigned int srwlock_unlock_exclusive( unsigned int *dest, int incr )
238 unsigned int val, tmp;
239 /* Atomically modifies the value of *dest by adding incr. If the queue of
240 * threads waiting for exclusive access is empty, then remove the
241 * SRWLOCK_MASK_IN_EXCLUSIVE flag (only the shared queue counter will
242 * remain). */
243 for (val = *dest;; val = tmp)
245 tmp = val + incr;
246 srwlock_check_invalid( tmp );
247 if (!(tmp & SRWLOCK_MASK_EXCLUSIVE_QUEUE))
248 tmp &= SRWLOCK_MASK_SHARED_QUEUE;
249 if ((tmp = InterlockedCompareExchange( (int *)dest, tmp, val )) == val)
250 break;
252 return val;
255 static inline void srwlock_leave_exclusive( RTL_SRWLOCK *lock, unsigned int val )
257 /* Used when a thread leaves an exclusive section. If there are other
258 * exclusive access threads they are processed first, followed by
259 * the shared waiters. */
260 if (val & SRWLOCK_MASK_EXCLUSIVE_QUEUE)
261 NtReleaseKeyedEvent( 0, srwlock_key_exclusive(lock), FALSE, NULL );
262 else
264 val &= SRWLOCK_MASK_SHARED_QUEUE; /* remove SRWLOCK_MASK_IN_EXCLUSIVE */
265 while (val--)
266 NtReleaseKeyedEvent( 0, srwlock_key_shared(lock), FALSE, NULL );
270 static inline void srwlock_leave_shared( RTL_SRWLOCK *lock, unsigned int val )
272 /* Wake up one exclusive thread as soon as the last shared access thread
273 * has left. */
274 if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(val & SRWLOCK_MASK_SHARED_QUEUE))
275 NtReleaseKeyedEvent( 0, srwlock_key_exclusive(lock), FALSE, NULL );
278 /***********************************************************************
279 * RtlInitializeSRWLock (NTDLL.@)
281 * NOTES
282 * Please note that SRWLocks do not keep track of the owner of a lock.
283 * It doesn't make any difference which thread for example unlocks an
284 * SRWLock (see corresponding tests). This implementation uses two
285 * keyed events (one for the exclusive waiters and one for the shared
286 * waiters) and is limited to 2^15-1 waiting threads.
288 void WINAPI RtlInitializeSRWLock( RTL_SRWLOCK *lock )
290 lock->Ptr = NULL;
293 /***********************************************************************
294 * RtlAcquireSRWLockExclusive (NTDLL.@)
296 * NOTES
297 * Unlike RtlAcquireResourceExclusive this function doesn't allow
298 * nested calls from the same thread. "Upgrading" a shared access lock
299 * to an exclusive access lock also doesn't seem to be supported.
301 void WINAPI RtlAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
303 if (unix_funcs->fast_RtlAcquireSRWLockExclusive( lock ) != STATUS_NOT_IMPLEMENTED)
304 return;
306 if (srwlock_lock_exclusive( (unsigned int *)&lock->Ptr, SRWLOCK_RES_EXCLUSIVE ))
307 NtWaitForKeyedEvent( 0, srwlock_key_exclusive(lock), FALSE, NULL );
310 /***********************************************************************
311 * RtlAcquireSRWLockShared (NTDLL.@)
313 * NOTES
314 * Do not call this function recursively - it will only succeed when
315 * there are no threads waiting for an exclusive lock!
317 void WINAPI RtlAcquireSRWLockShared( RTL_SRWLOCK *lock )
319 unsigned int val, tmp;
321 if (unix_funcs->fast_RtlAcquireSRWLockShared( lock ) != STATUS_NOT_IMPLEMENTED)
322 return;
324 /* Acquires a shared lock. If it's currently not possible to add elements to
325 * the shared queue, then request exclusive access instead. */
326 for (val = *(unsigned int *)&lock->Ptr;; val = tmp)
328 if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(val & SRWLOCK_MASK_IN_EXCLUSIVE))
329 tmp = val + SRWLOCK_RES_EXCLUSIVE;
330 else
331 tmp = val + SRWLOCK_RES_SHARED;
332 if ((tmp = InterlockedCompareExchange( (int *)&lock->Ptr, tmp, val )) == val)
333 break;
336 /* Drop exclusive access again and instead requeue for shared access. */
337 if ((val & SRWLOCK_MASK_EXCLUSIVE_QUEUE) && !(val & SRWLOCK_MASK_IN_EXCLUSIVE))
339 NtWaitForKeyedEvent( 0, srwlock_key_exclusive(lock), FALSE, NULL );
340 val = srwlock_unlock_exclusive( (unsigned int *)&lock->Ptr, (SRWLOCK_RES_SHARED
341 - SRWLOCK_RES_EXCLUSIVE) ) - SRWLOCK_RES_EXCLUSIVE;
342 srwlock_leave_exclusive( lock, val );
345 if (val & SRWLOCK_MASK_EXCLUSIVE_QUEUE)
346 NtWaitForKeyedEvent( 0, srwlock_key_shared(lock), FALSE, NULL );
349 /***********************************************************************
350 * RtlReleaseSRWLockExclusive (NTDLL.@)
352 void WINAPI RtlReleaseSRWLockExclusive( RTL_SRWLOCK *lock )
354 if (unix_funcs->fast_RtlReleaseSRWLockExclusive( lock ) != STATUS_NOT_IMPLEMENTED)
355 return;
357 srwlock_leave_exclusive( lock, srwlock_unlock_exclusive( (unsigned int *)&lock->Ptr,
358 - SRWLOCK_RES_EXCLUSIVE ) - SRWLOCK_RES_EXCLUSIVE );
361 /***********************************************************************
362 * RtlReleaseSRWLockShared (NTDLL.@)
364 void WINAPI RtlReleaseSRWLockShared( RTL_SRWLOCK *lock )
366 if (unix_funcs->fast_RtlReleaseSRWLockShared( lock ) != STATUS_NOT_IMPLEMENTED)
367 return;
369 srwlock_leave_shared( lock, srwlock_lock_exclusive( (unsigned int *)&lock->Ptr,
370 - SRWLOCK_RES_SHARED ) - SRWLOCK_RES_SHARED );
373 /***********************************************************************
374 * RtlTryAcquireSRWLockExclusive (NTDLL.@)
376 * NOTES
377 * Similarly to AcquireSRWLockExclusive, recursive calls are not allowed
378 * and will fail with a FALSE return value.
380 BOOLEAN WINAPI RtlTryAcquireSRWLockExclusive( RTL_SRWLOCK *lock )
382 NTSTATUS ret;
384 if ((ret = unix_funcs->fast_RtlTryAcquireSRWLockExclusive( lock )) != STATUS_NOT_IMPLEMENTED)
385 return (ret == STATUS_SUCCESS);
387 return InterlockedCompareExchange( (int *)&lock->Ptr, SRWLOCK_MASK_IN_EXCLUSIVE |
388 SRWLOCK_RES_EXCLUSIVE, 0 ) == 0;
391 /***********************************************************************
392 * RtlTryAcquireSRWLockShared (NTDLL.@)
394 BOOLEAN WINAPI RtlTryAcquireSRWLockShared( RTL_SRWLOCK *lock )
396 unsigned int val, tmp;
397 NTSTATUS ret;
399 if ((ret = unix_funcs->fast_RtlTryAcquireSRWLockShared( lock )) != STATUS_NOT_IMPLEMENTED)
400 return (ret == STATUS_SUCCESS);
402 for (val = *(unsigned int *)&lock->Ptr;; val = tmp)
404 if (val & SRWLOCK_MASK_EXCLUSIVE_QUEUE)
405 return FALSE;
406 if ((tmp = InterlockedCompareExchange( (int *)&lock->Ptr, val + SRWLOCK_RES_SHARED, val )) == val)
407 break;
409 return TRUE;
412 /***********************************************************************
413 * RtlInitializeConditionVariable (NTDLL.@)
415 * Initializes the condition variable with NULL.
417 * PARAMS
418 * variable [O] condition variable
420 * RETURNS
421 * Nothing.
423 void WINAPI RtlInitializeConditionVariable( RTL_CONDITION_VARIABLE *variable )
425 variable->Ptr = NULL;
428 /***********************************************************************
429 * RtlWakeConditionVariable (NTDLL.@)
431 * Wakes up one thread waiting on the condition variable.
433 * PARAMS
434 * variable [I/O] condition variable to wake up.
436 * RETURNS
437 * Nothing.
439 * NOTES
440 * The calling thread does not have to own any lock in order to call
441 * this function.
443 void WINAPI RtlWakeConditionVariable( RTL_CONDITION_VARIABLE *variable )
445 if (unix_funcs->fast_RtlWakeConditionVariable( variable, 1 ) == STATUS_NOT_IMPLEMENTED)
447 InterlockedIncrement( (int *)&variable->Ptr );
448 RtlWakeAddressSingle( variable );
452 /***********************************************************************
453 * RtlWakeAllConditionVariable (NTDLL.@)
455 * See WakeConditionVariable, wakes up all waiting threads.
457 void WINAPI RtlWakeAllConditionVariable( RTL_CONDITION_VARIABLE *variable )
459 if (unix_funcs->fast_RtlWakeConditionVariable( variable, INT_MAX ) == STATUS_NOT_IMPLEMENTED)
461 InterlockedIncrement( (int *)&variable->Ptr );
462 RtlWakeAddressAll( variable );
466 /***********************************************************************
467 * RtlSleepConditionVariableCS (NTDLL.@)
469 * Atomically releases the critical section and suspends the thread,
470 * waiting for a Wake(All)ConditionVariable event. Afterwards it enters
471 * the critical section again and returns.
473 * PARAMS
474 * variable [I/O] condition variable
475 * crit [I/O] critical section to leave temporarily
476 * timeout [I] timeout
478 * RETURNS
479 * see NtWaitForKeyedEvent for all possible return values.
481 NTSTATUS WINAPI RtlSleepConditionVariableCS( RTL_CONDITION_VARIABLE *variable, RTL_CRITICAL_SECTION *crit,
482 const LARGE_INTEGER *timeout )
484 NTSTATUS status;
485 int val;
487 if ((status = unix_funcs->fast_RtlSleepConditionVariableCS( variable, crit,
488 timeout )) != STATUS_NOT_IMPLEMENTED)
489 return status;
491 val = *(int *)&variable->Ptr;
492 RtlLeaveCriticalSection( crit );
493 status = RtlWaitOnAddress( &variable->Ptr, &val, sizeof(int), timeout );
494 RtlEnterCriticalSection( crit );
495 return status;
498 /***********************************************************************
499 * RtlSleepConditionVariableSRW (NTDLL.@)
501 * Atomically releases the SRWLock and suspends the thread,
502 * waiting for a Wake(All)ConditionVariable event. Afterwards it enters
503 * the SRWLock again with the same access rights and returns.
505 * PARAMS
506 * variable [I/O] condition variable
507 * lock [I/O] SRWLock to leave temporarily
508 * timeout [I] timeout
509 * flags [I] type of the current lock (exclusive / shared)
511 * RETURNS
512 * see NtWaitForKeyedEvent for all possible return values.
514 * NOTES
515 * the behaviour is undefined if the thread doesn't own the lock.
517 NTSTATUS WINAPI RtlSleepConditionVariableSRW( RTL_CONDITION_VARIABLE *variable, RTL_SRWLOCK *lock,
518 const LARGE_INTEGER *timeout, ULONG flags )
520 NTSTATUS status;
521 int val;
523 if ((status = unix_funcs->fast_RtlSleepConditionVariableSRW( variable, lock, timeout,
524 flags )) != STATUS_NOT_IMPLEMENTED)
525 return status;
527 val = *(int *)&variable->Ptr;
529 if (flags & RTL_CONDITION_VARIABLE_LOCKMODE_SHARED)
530 RtlReleaseSRWLockShared( lock );
531 else
532 RtlReleaseSRWLockExclusive( lock );
534 status = RtlWaitOnAddress( &variable->Ptr, &val, sizeof(int), timeout );
536 if (flags & RTL_CONDITION_VARIABLE_LOCKMODE_SHARED)
537 RtlAcquireSRWLockShared( lock );
538 else
539 RtlAcquireSRWLockExclusive( lock );
540 return status;
543 /***********************************************************************
544 * RtlWaitOnAddress (NTDLL.@)
546 NTSTATUS WINAPI RtlWaitOnAddress( const void *addr, const void *cmp, SIZE_T size,
547 const LARGE_INTEGER *timeout )
549 return unix_funcs->RtlWaitOnAddress( addr, cmp, size, timeout );
552 /***********************************************************************
553 * RtlWakeAddressAll (NTDLL.@)
555 void WINAPI RtlWakeAddressAll( const void *addr )
557 return unix_funcs->RtlWakeAddressAll( addr );
560 /***********************************************************************
561 * RtlWakeAddressSingle (NTDLL.@)
563 void WINAPI RtlWakeAddressSingle( const void *addr )
565 return unix_funcs->RtlWakeAddressSingle( addr );