2 * Win32 critical sections
4 * Copyright 1998 Alexandre Julliard
10 #include <sys/types.h>
13 #include "debugtools.h"
15 DEFAULT_DEBUG_CHANNEL(ntdll);
16 DECLARE_DEBUG_CHANNEL(relay);
18 /* Define the atomic exchange/inc/dec functions.
19 * These are available in kernel32.dll already,
20 * but we don't want to import kernel32 from ntdll.
27 inline static PVOID interlocked_cmpxchg( PVOID *dest, PVOID xchg, PVOID compare )
30 __asm__ __volatile__( "lock; cmpxchgl %2,(%1)"
31 : "=a" (ret) : "r" (dest), "r" (xchg), "0" (compare) : "memory" );
34 inline static LONG interlocked_inc( PLONG dest )
37 __asm__ __volatile__( "lock; xaddl %0,(%1)"
38 : "=r" (ret) : "r" (dest), "0" (1) : "memory" );
41 inline static LONG interlocked_dec( PLONG dest )
44 __asm__ __volatile__( "lock; xaddl %0,(%1)"
45 : "=r" (ret) : "r" (dest), "0" (-1) : "memory" );
51 PVOID WINAPI interlocked_cmpxchg( PVOID *dest, PVOID xchg, PVOID compare );
52 __ASM_GLOBAL_FUNC(interlocked_cmpxchg,
53 "movl 12(%esp),%eax\n\t"
54 "movl 8(%esp),%ecx\n\t"
55 "movl 4(%esp),%edx\n\t"
56 "lock; cmpxchgl %ecx,(%edx)\n\t"
58 LONG WINAPI interlocked_inc( PLONG dest );
59 __ASM_GLOBAL_FUNC(interlocked_inc,
60 "movl 4(%esp),%edx\n\t"
62 "lock; xaddl %eax,(%edx)\n\t"
65 LONG WINAPI interlocked_dec( PLONG dest );
66 __ASM_GLOBAL_FUNC(interlocked_dec,
67 "movl 4(%esp),%edx\n\t"
69 "lock; xaddl %eax,(%edx)\n\t"
72 # endif /* __GNUC__ */
74 #elif defined(__sparc__) && defined(__sun__)
76 * As the earlier Sparc processors lack necessary atomic instructions,
77 * I'm simply falling back to the library-provided _lwp_mutex routines
78 * to ensure mutual exclusion in a way appropriate for the current
81 * FIXME: If we have the compare-and-swap instruction (Sparc v9 and above)
82 * we could use this to speed up the Interlocked operations ...
85 static lwp_mutex_t interlocked_mutex = DEFAULTMUTEX;
87 static PVOID interlocked_cmpxchg( PVOID *dest, PVOID xchg, PVOID compare )
89 _lwp_mutex_lock( &interlocked_mutex );
90 if ( *dest == compare )
94 _lwp_mutex_unlock( &interlocked_mutex );
98 static LONG interlocked_inc( PLONG dest )
101 _lwp_mutex_lock( &interlocked_mutex );
103 _lwp_mutex_unlock( &interlocked_mutex );
107 static LONG interlocked_dec( PLONG dest )
110 _lwp_mutex_lock( &interlocked_mutex );
112 _lwp_mutex_unlock( &interlocked_mutex );
116 # error You must implement the interlocked* functions for your CPU
120 /***********************************************************************
123 static inline HANDLE get_semaphore( RTL_CRITICAL_SECTION *crit )
125 HANDLE ret = crit->LockSemaphore;
129 if (NtCreateSemaphore( &sem, SEMAPHORE_ALL_ACCESS, NULL, 0, 1 )) return 0;
130 if (!(ret = (HANDLE)InterlockedCompareExchange( (PVOID *)&crit->LockSemaphore,
134 NtClose(sem); /* somebody beat us to it */
139 /***********************************************************************
140 * RtlInitializeCriticalSection (NTDLL.@)
142 NTSTATUS WINAPI RtlInitializeCriticalSection( RTL_CRITICAL_SECTION *crit )
144 crit->LockCount = -1;
145 crit->RecursionCount = 0;
146 crit->OwningThread = 0;
147 crit->LockSemaphore = 0;
148 return STATUS_SUCCESS;
151 /***********************************************************************
152 * RtlInitializeCriticalSectionAndSpinCount (NTDLL.@)
153 * The InitializeCriticalSectionAndSpinCount (KERNEL32) function is
154 * available on NT4SP3 or later, and Win98 or later.
155 * I am assuming that this is the correct definition given the MSDN
156 * docs for the kernel32 functions.
158 NTSTATUS WINAPI RtlInitializeCriticalSectionAndSpinCount( RTL_CRITICAL_SECTION *crit, DWORD spincount )
160 if(spincount) TRACE("critsection=%p: spincount=%ld not supported\n", crit, spincount);
161 crit->SpinCount = spincount;
162 return RtlInitializeCriticalSection( crit );
166 /***********************************************************************
167 * RtlDeleteCriticalSection (NTDLL.@)
169 NTSTATUS WINAPI RtlDeleteCriticalSection( RTL_CRITICAL_SECTION *crit )
171 crit->LockCount = -1;
172 crit->RecursionCount = 0;
173 crit->OwningThread = 0;
174 if (crit->LockSemaphore) NtClose( crit->LockSemaphore );
175 crit->LockSemaphore = 0;
176 return STATUS_SUCCESS;
180 /***********************************************************************
181 * RtlpWaitForCriticalSection (NTDLL.@)
183 NTSTATUS WINAPI RtlpWaitForCriticalSection( RTL_CRITICAL_SECTION *crit )
187 EXCEPTION_RECORD rec;
188 HANDLE sem = get_semaphore( crit );
190 DWORD res = WaitForSingleObject( sem, 5000L );
191 if ( res == WAIT_TIMEOUT )
193 ERR("Critical section %p wait timed out, retrying (60 sec) fs=%04x\n", crit, __get_fs() );
194 res = WaitForSingleObject( sem, 60000L );
195 if ( res == WAIT_TIMEOUT && TRACE_ON(relay) )
197 ERR("Critical section %p wait timed out, retrying (5 min) fs=%04x\n", crit, __get_fs() );
198 res = WaitForSingleObject( sem, 300000L );
201 if (res == STATUS_WAIT_0) return STATUS_SUCCESS;
203 rec.ExceptionCode = EXCEPTION_CRITICAL_SECTION_WAIT;
204 rec.ExceptionFlags = 0;
205 rec.ExceptionRecord = NULL;
206 rec.ExceptionAddress = RtlRaiseException; /* sic */
207 rec.NumberParameters = 1;
208 rec.ExceptionInformation[0] = (DWORD)crit;
209 RtlRaiseException( &rec );
214 /***********************************************************************
215 * RtlpUnWaitCriticalSection (NTDLL.@)
217 NTSTATUS WINAPI RtlpUnWaitCriticalSection( RTL_CRITICAL_SECTION *crit )
219 HANDLE sem = get_semaphore( crit );
220 NTSTATUS res = NtReleaseSemaphore( sem, 1, NULL );
221 if (res) RtlRaiseStatus( res );
226 /***********************************************************************
227 * RtlEnterCriticalSection (NTDLL.@)
229 NTSTATUS WINAPI RtlEnterCriticalSection( RTL_CRITICAL_SECTION *crit )
231 if (interlocked_inc( &crit->LockCount ))
233 if (crit->OwningThread == GetCurrentThreadId())
235 crit->RecursionCount++;
236 return STATUS_SUCCESS;
239 /* Now wait for it */
240 RtlpWaitForCriticalSection( crit );
242 crit->OwningThread = GetCurrentThreadId();
243 crit->RecursionCount = 1;
244 return STATUS_SUCCESS;
248 /***********************************************************************
249 * RtlTryEnterCriticalSection (NTDLL.@)
251 BOOL WINAPI RtlTryEnterCriticalSection( RTL_CRITICAL_SECTION *crit )
254 if (interlocked_cmpxchg( (PVOID *)&crit->LockCount, (PVOID)0L, (PVOID)-1L ) == (PVOID)-1L)
256 crit->OwningThread = GetCurrentThreadId();
257 crit->RecursionCount = 1;
260 else if (crit->OwningThread == GetCurrentThreadId())
262 interlocked_inc( &crit->LockCount );
263 crit->RecursionCount++;
270 /***********************************************************************
271 * RtlLeaveCriticalSection (NTDLL.@)
273 NTSTATUS WINAPI RtlLeaveCriticalSection( RTL_CRITICAL_SECTION *crit )
275 if (--crit->RecursionCount) interlocked_dec( &crit->LockCount );
278 crit->OwningThread = 0;
279 if (interlocked_dec( &crit->LockCount ) >= 0)
281 /* someone is waiting */
282 RtlpUnWaitCriticalSection( crit );
285 return STATUS_SUCCESS;