wined3d: Correctly destroy the adapter on format initialization failure in no3d mode.
[wine/zf.git] / dlls / ntdll / critsection.c
blob232d6aa06c13906bd778fb819c64b4fdeec7f40f
1 /*
2 * Win32 critical sections
4 * Copyright 1998 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <assert.h>
22 #include <errno.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <sys/types.h>
26 #include <time.h>
27 #include "ntstatus.h"
28 #define WIN32_NO_STATUS
29 #include "windef.h"
30 #include "winternl.h"
31 #include "wine/debug.h"
32 #include "ntdll_misc.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
35 WINE_DECLARE_DEBUG_CHANNEL(relay);
37 static inline void small_pause(void)
39 #ifdef __i386__
40 __asm__ __volatile__( "rep;nop" : : : "memory" );
41 #else
42 __asm__ __volatile__( "" : : : "memory" );
43 #endif
46 static void *no_debug_info_marker = (void *)(ULONG_PTR)-1;
48 static BOOL crit_section_has_debuginfo(const RTL_CRITICAL_SECTION *crit)
50 return crit->DebugInfo != NULL && crit->DebugInfo != no_debug_info_marker;
53 /***********************************************************************
54 * RtlInitializeCriticalSection (NTDLL.@)
56 * Initialises a new critical section.
58 * PARAMS
59 * crit [O] Critical section to initialise
61 * RETURNS
62 * STATUS_SUCCESS.
64 * SEE
65 * RtlInitializeCriticalSectionEx(),
66 * RtlInitializeCriticalSectionAndSpinCount(), RtlDeleteCriticalSection(),
67 * RtlEnterCriticalSection(), RtlLeaveCriticalSection(),
68 * RtlTryEnterCriticalSection(), RtlSetCriticalSectionSpinCount()
70 NTSTATUS WINAPI RtlInitializeCriticalSection( RTL_CRITICAL_SECTION *crit )
72 return RtlInitializeCriticalSectionEx( crit, 0, 0 );
75 /***********************************************************************
76 * RtlInitializeCriticalSectionAndSpinCount (NTDLL.@)
78 * Initialises a new critical section with a given spin count.
80 * PARAMS
81 * crit [O] Critical section to initialise
82 * spincount [I] Spin count for crit
84 * RETURNS
85 * STATUS_SUCCESS.
87 * NOTES
88 * Available on NT4 SP3 or later.
90 * SEE
91 * RtlInitializeCriticalSectionEx(),
92 * RtlInitializeCriticalSection(), RtlDeleteCriticalSection(),
93 * RtlEnterCriticalSection(), RtlLeaveCriticalSection(),
94 * RtlTryEnterCriticalSection(), RtlSetCriticalSectionSpinCount()
96 NTSTATUS WINAPI RtlInitializeCriticalSectionAndSpinCount( RTL_CRITICAL_SECTION *crit, ULONG spincount )
98 return RtlInitializeCriticalSectionEx( crit, spincount, 0 );
101 /***********************************************************************
102 * RtlInitializeCriticalSectionEx (NTDLL.@)
104 * Initialises a new critical section with a given spin count and flags.
106 * PARAMS
107 * crit [O] Critical section to initialise.
108 * spincount [I] Number of times to spin upon contention.
109 * flags [I] RTL_CRITICAL_SECTION_FLAG_ flags from winnt.h.
111 * RETURNS
112 * STATUS_SUCCESS.
114 * NOTES
115 * Available on Vista or later.
117 * SEE
118 * RtlInitializeCriticalSection(), RtlDeleteCriticalSection(),
119 * RtlEnterCriticalSection(), RtlLeaveCriticalSection(),
120 * RtlTryEnterCriticalSection(), RtlSetCriticalSectionSpinCount()
122 NTSTATUS WINAPI RtlInitializeCriticalSectionEx( RTL_CRITICAL_SECTION *crit, ULONG spincount, ULONG flags )
124 if (flags & (RTL_CRITICAL_SECTION_FLAG_DYNAMIC_SPIN|RTL_CRITICAL_SECTION_FLAG_STATIC_INIT))
125 FIXME("(%p,%u,0x%08x) semi-stub\n", crit, spincount, flags);
127 /* FIXME: if RTL_CRITICAL_SECTION_FLAG_STATIC_INIT is given, we should use
128 * memory from a static pool to hold the debug info. Then heap.c could pass
129 * this flag rather than initialising the process heap CS by hand. If this
130 * is done, then debug info should be managed through Rtlp[Allocate|Free]DebugInfo
131 * so (e.g.) MakeCriticalSectionGlobal() doesn't free it using HeapFree().
133 if (flags & RTL_CRITICAL_SECTION_FLAG_NO_DEBUG_INFO)
134 crit->DebugInfo = no_debug_info_marker;
135 else
137 crit->DebugInfo = RtlAllocateHeap(GetProcessHeap(), 0, sizeof(RTL_CRITICAL_SECTION_DEBUG));
138 if (crit->DebugInfo)
140 crit->DebugInfo->Type = 0;
141 crit->DebugInfo->CreatorBackTraceIndex = 0;
142 crit->DebugInfo->CriticalSection = crit;
143 crit->DebugInfo->ProcessLocksList.Blink = &(crit->DebugInfo->ProcessLocksList);
144 crit->DebugInfo->ProcessLocksList.Flink = &(crit->DebugInfo->ProcessLocksList);
145 crit->DebugInfo->EntryCount = 0;
146 crit->DebugInfo->ContentionCount = 0;
147 memset( crit->DebugInfo->Spare, 0, sizeof(crit->DebugInfo->Spare) );
150 crit->LockCount = -1;
151 crit->RecursionCount = 0;
152 crit->OwningThread = 0;
153 crit->LockSemaphore = 0;
154 if (NtCurrentTeb()->Peb->NumberOfProcessors <= 1) spincount = 0;
155 crit->SpinCount = spincount & ~0x80000000;
156 return STATUS_SUCCESS;
159 /***********************************************************************
160 * RtlSetCriticalSectionSpinCount (NTDLL.@)
162 * Sets the spin count of a critical section.
164 * PARAMS
165 * crit [I/O] Critical section
166 * spincount [I] Spin count for crit
168 * RETURNS
169 * The previous spin count.
171 * NOTES
172 * If the system is not SMP, spincount is ignored and set to 0.
174 * SEE
175 * RtlInitializeCriticalSectionEx(),
176 * RtlInitializeCriticalSection(), RtlInitializeCriticalSectionAndSpinCount(),
177 * RtlDeleteCriticalSection(), RtlEnterCriticalSection(),
178 * RtlLeaveCriticalSection(), RtlTryEnterCriticalSection()
180 ULONG WINAPI RtlSetCriticalSectionSpinCount( RTL_CRITICAL_SECTION *crit, ULONG spincount )
182 ULONG oldspincount = crit->SpinCount;
183 if (NtCurrentTeb()->Peb->NumberOfProcessors <= 1) spincount = 0;
184 crit->SpinCount = spincount;
185 return oldspincount;
188 /***********************************************************************
189 * RtlDeleteCriticalSection (NTDLL.@)
191 * Frees the resources used by a critical section.
193 * PARAMS
194 * crit [I/O] Critical section to free
196 * RETURNS
197 * STATUS_SUCCESS.
199 * SEE
200 * RtlInitializeCriticalSectionEx(),
201 * RtlInitializeCriticalSection(), RtlInitializeCriticalSectionAndSpinCount(),
202 * RtlDeleteCriticalSection(), RtlEnterCriticalSection(),
203 * RtlLeaveCriticalSection(), RtlTryEnterCriticalSection()
205 NTSTATUS WINAPI RtlDeleteCriticalSection( RTL_CRITICAL_SECTION *crit )
207 crit->LockCount = -1;
208 crit->RecursionCount = 0;
209 crit->OwningThread = 0;
210 if (crit_section_has_debuginfo( crit ))
212 /* only free the ones we made in here */
213 if (!crit->DebugInfo->Spare[0])
215 RtlFreeHeap( GetProcessHeap(), 0, crit->DebugInfo );
216 crit->DebugInfo = NULL;
218 if (unix_funcs->fast_RtlDeleteCriticalSection( crit ) == STATUS_NOT_IMPLEMENTED)
219 NtClose( crit->LockSemaphore );
221 else NtClose( crit->LockSemaphore );
222 crit->LockSemaphore = 0;
223 return STATUS_SUCCESS;
227 /***********************************************************************
228 * RtlpWaitForCriticalSection (NTDLL.@)
230 * Waits for a busy critical section to become free.
232 * PARAMS
233 * crit [I/O] Critical section to wait for
235 * RETURNS
236 * STATUS_SUCCESS.
238 * NOTES
239 * Use RtlEnterCriticalSection() instead of this function as it is often much
240 * faster.
242 * SEE
243 * RtlInitializeCriticalSectionEx(),
244 * RtlInitializeCriticalSection(), RtlInitializeCriticalSectionAndSpinCount(),
245 * RtlDeleteCriticalSection(), RtlEnterCriticalSection(),
246 * RtlLeaveCriticalSection(), RtlTryEnterCriticalSection()
248 NTSTATUS WINAPI RtlpWaitForCriticalSection( RTL_CRITICAL_SECTION *crit )
250 LONGLONG timeout = NtCurrentTeb()->Peb->CriticalSectionTimeout.QuadPart / -10000000;
252 /* Don't allow blocking on a critical section during process termination */
253 if (RtlDllShutdownInProgress())
255 WARN( "process %s is shutting down, returning STATUS_SUCCESS\n",
256 debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer) );
257 return STATUS_SUCCESS;
260 for (;;)
262 EXCEPTION_RECORD rec;
263 NTSTATUS status = unix_funcs->fast_RtlpWaitForCriticalSection( crit, 5 );
264 timeout -= 5;
266 if ( status == STATUS_TIMEOUT )
268 const char *name = NULL;
269 if (crit_section_has_debuginfo( crit )) name = (char *)crit->DebugInfo->Spare[0];
270 if (!name) name = "?";
271 ERR( "section %p %s wait timed out in thread %04x, blocked by %04x, retrying (60 sec)\n",
272 crit, debugstr_a(name), GetCurrentThreadId(), HandleToULong(crit->OwningThread) );
273 status = unix_funcs->fast_RtlpWaitForCriticalSection( crit, 60 );
274 timeout -= 60;
276 if ( status == STATUS_TIMEOUT && TRACE_ON(relay) )
278 ERR( "section %p %s wait timed out in thread %04x, blocked by %04x, retrying (5 min)\n",
279 crit, debugstr_a(name), GetCurrentThreadId(), HandleToULong(crit->OwningThread) );
280 status = unix_funcs->fast_RtlpWaitForCriticalSection( crit, 300 );
281 timeout -= 300;
284 if (status == STATUS_WAIT_0) break;
286 /* Throw exception only for Wine internal locks */
287 if (!crit_section_has_debuginfo( crit ) || !crit->DebugInfo->Spare[0]) continue;
289 /* only throw deadlock exception if configured timeout is reached */
290 if (timeout > 0) continue;
292 rec.ExceptionCode = STATUS_POSSIBLE_DEADLOCK;
293 rec.ExceptionFlags = 0;
294 rec.ExceptionRecord = NULL;
295 rec.ExceptionAddress = RtlRaiseException; /* sic */
296 rec.NumberParameters = 1;
297 rec.ExceptionInformation[0] = (ULONG_PTR)crit;
298 RtlRaiseException( &rec );
300 if (crit_section_has_debuginfo( crit )) crit->DebugInfo->ContentionCount++;
301 return STATUS_SUCCESS;
305 /***********************************************************************
306 * RtlpUnWaitCriticalSection (NTDLL.@)
308 * Notifies other threads waiting on the busy critical section that it has
309 * become free.
311 * PARAMS
312 * crit [I/O] Critical section
314 * RETURNS
315 * Success: STATUS_SUCCESS.
316 * Failure: Any error returned by NtReleaseSemaphore()
318 * NOTES
319 * Use RtlLeaveCriticalSection() instead of this function as it is often much
320 * faster.
322 * SEE
323 * RtlInitializeCriticalSectionEx(),
324 * RtlInitializeCriticalSection(), RtlInitializeCriticalSectionAndSpinCount(),
325 * RtlDeleteCriticalSection(), RtlEnterCriticalSection(),
326 * RtlLeaveCriticalSection(), RtlTryEnterCriticalSection()
328 NTSTATUS WINAPI RtlpUnWaitCriticalSection( RTL_CRITICAL_SECTION *crit )
330 NTSTATUS ret = unix_funcs->fast_RtlpUnWaitCriticalSection( crit );
332 if (ret) RtlRaiseStatus( ret );
333 return ret;
337 /***********************************************************************
338 * RtlEnterCriticalSection (NTDLL.@)
340 * Enters a critical section, waiting for it to become available if necessary.
342 * PARAMS
343 * crit [I/O] Critical section to enter
345 * RETURNS
346 * STATUS_SUCCESS. The critical section is held by the caller.
348 * SEE
349 * RtlInitializeCriticalSectionEx(),
350 * RtlInitializeCriticalSection(), RtlInitializeCriticalSectionAndSpinCount(),
351 * RtlDeleteCriticalSection(), RtlSetCriticalSectionSpinCount(),
352 * RtlLeaveCriticalSection(), RtlTryEnterCriticalSection()
354 NTSTATUS WINAPI RtlEnterCriticalSection( RTL_CRITICAL_SECTION *crit )
356 if (crit->SpinCount)
358 ULONG count;
360 if (RtlTryEnterCriticalSection( crit )) return STATUS_SUCCESS;
361 for (count = crit->SpinCount; count > 0; count--)
363 if (crit->LockCount > 0) break; /* more than one waiter, don't bother spinning */
364 if (crit->LockCount == -1) /* try again */
366 if (InterlockedCompareExchange( &crit->LockCount, 0, -1 ) == -1) goto done;
368 small_pause();
372 if (InterlockedIncrement( &crit->LockCount ))
374 if (crit->OwningThread == ULongToHandle(GetCurrentThreadId()))
376 crit->RecursionCount++;
377 return STATUS_SUCCESS;
380 /* Now wait for it */
381 RtlpWaitForCriticalSection( crit );
383 done:
384 crit->OwningThread = ULongToHandle(GetCurrentThreadId());
385 crit->RecursionCount = 1;
386 return STATUS_SUCCESS;
390 /***********************************************************************
391 * RtlTryEnterCriticalSection (NTDLL.@)
393 * Tries to enter a critical section without waiting.
395 * PARAMS
396 * crit [I/O] Critical section to enter
398 * RETURNS
399 * Success: TRUE. The critical section is held by the caller.
400 * Failure: FALSE. The critical section is currently held by another thread.
402 * SEE
403 * RtlInitializeCriticalSectionEx(),
404 * RtlInitializeCriticalSection(), RtlInitializeCriticalSectionAndSpinCount(),
405 * RtlDeleteCriticalSection(), RtlEnterCriticalSection(),
406 * RtlLeaveCriticalSection(), RtlSetCriticalSectionSpinCount()
408 BOOL WINAPI RtlTryEnterCriticalSection( RTL_CRITICAL_SECTION *crit )
410 BOOL ret = FALSE;
411 if (InterlockedCompareExchange( &crit->LockCount, 0, -1 ) == -1)
413 crit->OwningThread = ULongToHandle(GetCurrentThreadId());
414 crit->RecursionCount = 1;
415 ret = TRUE;
417 else if (crit->OwningThread == ULongToHandle(GetCurrentThreadId()))
419 InterlockedIncrement( &crit->LockCount );
420 crit->RecursionCount++;
421 ret = TRUE;
423 return ret;
427 /***********************************************************************
428 * RtlIsCriticalSectionLocked (NTDLL.@)
430 * Checks if the critical section is locked by any thread.
432 * PARAMS
433 * crit [I/O] Critical section to check.
435 * RETURNS
436 * Success: TRUE. The critical section is locked.
437 * Failure: FALSE. The critical section is not locked.
439 BOOL WINAPI RtlIsCriticalSectionLocked( RTL_CRITICAL_SECTION *crit )
441 return crit->RecursionCount != 0;
445 /***********************************************************************
446 * RtlIsCriticalSectionLockedByThread (NTDLL.@)
448 * Checks if the critical section is locked by the current thread.
450 * PARAMS
451 * crit [I/O] Critical section to check.
453 * RETURNS
454 * Success: TRUE. The critical section is locked.
455 * Failure: FALSE. The critical section is not locked.
457 BOOL WINAPI RtlIsCriticalSectionLockedByThread( RTL_CRITICAL_SECTION *crit )
459 return crit->OwningThread == ULongToHandle(GetCurrentThreadId()) &&
460 crit->RecursionCount;
464 /***********************************************************************
465 * RtlLeaveCriticalSection (NTDLL.@)
467 * Leaves a critical section.
469 * PARAMS
470 * crit [I/O] Critical section to leave.
472 * RETURNS
473 * STATUS_SUCCESS.
475 * SEE
476 * RtlInitializeCriticalSectionEx(),
477 * RtlInitializeCriticalSection(), RtlInitializeCriticalSectionAndSpinCount(),
478 * RtlDeleteCriticalSection(), RtlEnterCriticalSection(),
479 * RtlSetCriticalSectionSpinCount(), RtlTryEnterCriticalSection()
481 NTSTATUS WINAPI RtlLeaveCriticalSection( RTL_CRITICAL_SECTION *crit )
483 if (--crit->RecursionCount)
485 if (crit->RecursionCount > 0) InterlockedDecrement( &crit->LockCount );
486 else ERR( "section %p is not acquired\n", crit );
488 else
490 crit->OwningThread = 0;
491 if (InterlockedDecrement( &crit->LockCount ) >= 0)
493 /* someone is waiting */
494 RtlpUnWaitCriticalSection( crit );
497 return STATUS_SUCCESS;