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
;