Added stubs for HttpEndRequestA/W, InternetReadFileExA/W,
[wine/gsoc_dplay.git] / dlls / ntdll / critsection.c
blobe291e59730624c30778b112d05cccbfd8ce94108
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 "winternl.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) 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 /* Throw exception only for Wine internal locks */
134 if (!crit->DebugInfo) continue;
136 rec.ExceptionCode = EXCEPTION_CRITICAL_SECTION_WAIT;
137 rec.ExceptionFlags = 0;
138 rec.ExceptionRecord = NULL;
139 rec.ExceptionAddress = RtlRaiseException; /* sic */
140 rec.NumberParameters = 1;
141 rec.ExceptionInformation[0] = (DWORD)crit;
142 RtlRaiseException( &rec );
147 /***********************************************************************
148 * RtlpUnWaitCriticalSection (NTDLL.@)
150 NTSTATUS WINAPI RtlpUnWaitCriticalSection( RTL_CRITICAL_SECTION *crit )
152 HANDLE sem = get_semaphore( crit );
153 NTSTATUS res = NtReleaseSemaphore( sem, 1, NULL );
154 if (res) RtlRaiseStatus( res );
155 return res;
159 /***********************************************************************
160 * RtlEnterCriticalSection (NTDLL.@)
162 NTSTATUS WINAPI RtlEnterCriticalSection( RTL_CRITICAL_SECTION *crit )
164 if (interlocked_inc( &crit->LockCount ))
166 if (crit->OwningThread == (HANDLE)GetCurrentThreadId())
168 crit->RecursionCount++;
169 return STATUS_SUCCESS;
172 /* Now wait for it */
173 RtlpWaitForCriticalSection( crit );
175 crit->OwningThread = (HANDLE)GetCurrentThreadId();
176 crit->RecursionCount = 1;
177 return STATUS_SUCCESS;
181 /***********************************************************************
182 * RtlTryEnterCriticalSection (NTDLL.@)
184 BOOL WINAPI RtlTryEnterCriticalSection( RTL_CRITICAL_SECTION *crit )
186 BOOL ret = FALSE;
187 if (interlocked_cmpxchg( &crit->LockCount, 0L, -1 ) == -1)
189 crit->OwningThread = (HANDLE)GetCurrentThreadId();
190 crit->RecursionCount = 1;
191 ret = TRUE;
193 else if (crit->OwningThread == (HANDLE)GetCurrentThreadId())
195 interlocked_inc( &crit->LockCount );
196 crit->RecursionCount++;
197 ret = TRUE;
199 return ret;
203 /***********************************************************************
204 * RtlLeaveCriticalSection (NTDLL.@)
206 NTSTATUS WINAPI RtlLeaveCriticalSection( RTL_CRITICAL_SECTION *crit )
208 if (--crit->RecursionCount) interlocked_dec( &crit->LockCount );
209 else
211 crit->OwningThread = 0;
212 if (interlocked_dec( &crit->LockCount ) >= 0)
214 /* someone is waiting */
215 RtlpUnWaitCriticalSection( crit );
218 return STATUS_SUCCESS;