Added version info to 16-bit shell.dll.
[wine/multimedia.git] / dlls / ntdll / critsection.c
blobb1df076a7d3225ac3f970a4df41b231bbf78736f
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "config.h"
22 #include "wine/port.h"
24 #include <assert.h>
25 #include <errno.h>
26 #include <stdio.h>
27 #include <sys/types.h>
28 #include "winerror.h"
29 #include "ntddk.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
33 WINE_DECLARE_DEBUG_CHANNEL(relay);
35 inline static LONG interlocked_inc( PLONG dest )
37 return interlocked_xchg_add( dest, 1 ) + 1;
40 inline static LONG interlocked_dec( PLONG dest )
42 return interlocked_xchg_add( dest, -1 ) - 1;
45 /***********************************************************************
46 * get_semaphore
48 static inline HANDLE get_semaphore( RTL_CRITICAL_SECTION *crit )
50 HANDLE ret = crit->LockSemaphore;
51 if (!ret)
53 HANDLE sem;
54 if (NtCreateSemaphore( &sem, SEMAPHORE_ALL_ACCESS, NULL, 0, 1 )) return 0;
55 if (!(ret = (HANDLE)interlocked_cmpxchg_ptr( (PVOID *)&crit->LockSemaphore,
56 (PVOID)sem, 0 )))
57 ret = sem;
58 else
59 NtClose(sem); /* somebody beat us to it */
61 return ret;
64 /***********************************************************************
65 * RtlInitializeCriticalSection (NTDLL.@)
67 NTSTATUS WINAPI RtlInitializeCriticalSection( RTL_CRITICAL_SECTION *crit )
69 crit->DebugInfo = NULL;
70 crit->LockCount = -1;
71 crit->RecursionCount = 0;
72 crit->OwningThread = 0;
73 crit->LockSemaphore = 0;
74 return STATUS_SUCCESS;
77 /***********************************************************************
78 * RtlInitializeCriticalSectionAndSpinCount (NTDLL.@)
79 * The InitializeCriticalSectionAndSpinCount (KERNEL32) function is
80 * available on NT4SP3 or later, and Win98 or later.
81 * I am assuming that this is the correct definition given the MSDN
82 * docs for the kernel32 functions.
84 NTSTATUS WINAPI RtlInitializeCriticalSectionAndSpinCount( RTL_CRITICAL_SECTION *crit, DWORD spincount )
86 if(spincount) TRACE("critsection=%p: spincount=%ld not supported\n", crit, spincount);
87 crit->SpinCount = spincount;
88 return RtlInitializeCriticalSection( crit );
92 /***********************************************************************
93 * RtlDeleteCriticalSection (NTDLL.@)
95 NTSTATUS WINAPI RtlDeleteCriticalSection( RTL_CRITICAL_SECTION *crit )
97 crit->LockCount = -1;
98 crit->RecursionCount = 0;
99 crit->OwningThread = 0;
100 if (crit->LockSemaphore) NtClose( crit->LockSemaphore );
101 crit->LockSemaphore = 0;
102 return STATUS_SUCCESS;
106 /***********************************************************************
107 * RtlpWaitForCriticalSection (NTDLL.@)
109 NTSTATUS WINAPI RtlpWaitForCriticalSection( RTL_CRITICAL_SECTION *crit )
111 for (;;)
113 EXCEPTION_RECORD rec;
114 HANDLE sem = get_semaphore( crit );
116 DWORD res = WaitForSingleObject( sem, 5000L );
117 if ( res == WAIT_TIMEOUT )
119 const char *name = (char *)crit->DebugInfo;
120 if (!name || IsBadStringPtrA(name,80)) name = "?";
121 ERR( "section %p %s wait timed out, retrying (60 sec) tid=%08lx\n",
122 crit, debugstr_a(name), GetCurrentThreadId() );
123 res = WaitForSingleObject( sem, 60000L );
124 if ( res == WAIT_TIMEOUT && TRACE_ON(relay) )
126 ERR( "section %p %s wait timed out, retrying (5 min) tid=%08lx\n",
127 crit, debugstr_a(name), GetCurrentThreadId() );
128 res = WaitForSingleObject( sem, 300000L );
131 if (res == STATUS_WAIT_0) return STATUS_SUCCESS;
133 rec.ExceptionCode = EXCEPTION_CRITICAL_SECTION_WAIT;
134 rec.ExceptionFlags = 0;
135 rec.ExceptionRecord = NULL;
136 rec.ExceptionAddress = RtlRaiseException; /* sic */
137 rec.NumberParameters = 1;
138 rec.ExceptionInformation[0] = (DWORD)crit;
139 RtlRaiseException( &rec );
144 /***********************************************************************
145 * RtlpUnWaitCriticalSection (NTDLL.@)
147 NTSTATUS WINAPI RtlpUnWaitCriticalSection( RTL_CRITICAL_SECTION *crit )
149 HANDLE sem = get_semaphore( crit );
150 NTSTATUS res = NtReleaseSemaphore( sem, 1, NULL );
151 if (res) RtlRaiseStatus( res );
152 return res;
156 /***********************************************************************
157 * RtlEnterCriticalSection (NTDLL.@)
159 NTSTATUS WINAPI RtlEnterCriticalSection( RTL_CRITICAL_SECTION *crit )
161 if (interlocked_inc( &crit->LockCount ))
163 if (crit->OwningThread == GetCurrentThreadId())
165 crit->RecursionCount++;
166 return STATUS_SUCCESS;
169 /* Now wait for it */
170 RtlpWaitForCriticalSection( crit );
172 crit->OwningThread = GetCurrentThreadId();
173 crit->RecursionCount = 1;
174 return STATUS_SUCCESS;
178 /***********************************************************************
179 * RtlTryEnterCriticalSection (NTDLL.@)
181 BOOL WINAPI RtlTryEnterCriticalSection( RTL_CRITICAL_SECTION *crit )
183 BOOL ret = FALSE;
184 if (interlocked_cmpxchg( &crit->LockCount, 0L, -1 ) == -1)
186 crit->OwningThread = GetCurrentThreadId();
187 crit->RecursionCount = 1;
188 ret = TRUE;
190 else if (crit->OwningThread == GetCurrentThreadId())
192 interlocked_inc( &crit->LockCount );
193 crit->RecursionCount++;
194 ret = TRUE;
196 return ret;
200 /***********************************************************************
201 * RtlLeaveCriticalSection (NTDLL.@)
203 NTSTATUS WINAPI RtlLeaveCriticalSection( RTL_CRITICAL_SECTION *crit )
205 if (--crit->RecursionCount) interlocked_dec( &crit->LockCount );
206 else
208 crit->OwningThread = 0;
209 if (interlocked_dec( &crit->LockCount ) >= 0)
211 /* someone is waiting */
212 RtlpUnWaitCriticalSection( crit );
215 return STATUS_SUCCESS;