- implementation of RtlReg* (read access), RtlEvent*, RtlSemaphore*,
[wine] / scheduler / critsection.c
1 /*
2  * Win32 critical sections
3  *
4  * Copyright 1998 Alexandre Julliard
5  */
6
7 #include <assert.h>
8 #include <errno.h>
9 #include <stdio.h>
10 #include <sys/types.h>
11 #include "winerror.h"
12 #include "winbase.h"
13 #include "ntddk.h"
14 #include "heap.h"
15 #include "debugtools.h"
16 #include "thread.h"
17
18 DEFAULT_DEBUG_CHANNEL(win32)
19 DECLARE_DEBUG_CHANNEL(relay)
20
21
22 /***********************************************************************
23  *           InitializeCriticalSection   (KERNEL32.472) (NTDLL.406)
24  */
25 void WINAPI InitializeCriticalSection( CRITICAL_SECTION *crit )
26 {
27     crit->LockCount      = -1;
28     crit->RecursionCount = 0;
29     crit->OwningThread   = 0;
30     crit->LockSemaphore  = CreateSemaphoreA( NULL, 0, 1, NULL );
31     crit->Reserved       = GetCurrentProcessId();
32 }
33
34
35 /***********************************************************************
36  *           DeleteCriticalSection   (KERNEL32.185) (NTDLL.327)
37  */
38 void WINAPI DeleteCriticalSection( CRITICAL_SECTION *crit )
39 {
40     if (crit->LockSemaphore)
41     {
42         if (crit->RecursionCount)  /* Should not happen */
43             ERR("Deleting owned critical section (%p)\n", crit );
44
45         crit->LockCount      = -1;
46         crit->RecursionCount = 0;
47         crit->OwningThread   = 0;
48         CloseHandle( crit->LockSemaphore );
49         crit->LockSemaphore  = 0;
50         crit->Reserved       = (DWORD)-1;
51     }
52 }
53
54
55 /***********************************************************************
56  *           EnterCriticalSection   (KERNEL32.195) (NTDLL.344)
57  */
58 void WINAPI EnterCriticalSection( CRITICAL_SECTION *crit )
59 {
60     DWORD res;
61
62     if (!crit->LockSemaphore)
63     {
64         FIXME("entering uninitialized section(%p)?\n",crit);
65         InitializeCriticalSection(crit);
66     }
67     if ( crit->Reserved && crit->Reserved != GetCurrentProcessId() )
68     {
69         FIXME("Crst %p belongs to process %ld, current is %ld!\n", 
70               crit, crit->Reserved, GetCurrentProcessId() );
71         return;
72     }
73     if (InterlockedIncrement( &crit->LockCount ))
74     {
75         if (crit->OwningThread == GetCurrentThreadId())
76         {
77             crit->RecursionCount++;
78             return;
79         }
80
81         /* Now wait for it */
82         for (;;)
83         {
84             EXCEPTION_RECORD rec;
85
86             res = WaitForSingleObject( crit->LockSemaphore, 5000L );
87             if ( res == WAIT_TIMEOUT )
88             {
89                 ERR("Critical section %p wait timed out, retrying (60 sec)\n", crit );
90                 res = WaitForSingleObject( crit->LockSemaphore, 60000L );
91                 if ( res == WAIT_TIMEOUT && TRACE_ON(relay) )
92                 {
93                     ERR("Critical section %p wait timed out, retrying (5 min)\n", crit );
94                     res = WaitForSingleObject( crit->LockSemaphore, 300000L );
95                 }
96             }
97             if (res == STATUS_WAIT_0) break;
98
99             rec.ExceptionCode    = EXCEPTION_CRITICAL_SECTION_WAIT;
100             rec.ExceptionFlags   = 0;
101             rec.ExceptionRecord  = NULL;
102             rec.ExceptionAddress = RtlRaiseException;  /* sic */
103             rec.NumberParameters = 1;
104             rec.ExceptionInformation[0] = (DWORD)crit;
105             RtlRaiseException( &rec );
106         }
107     }
108     crit->OwningThread   = GetCurrentThreadId();
109     crit->RecursionCount = 1;
110 }
111
112
113 /***********************************************************************
114  *           TryEnterCriticalSection   (KERNEL32.898) (NTDLL.969)
115  */
116 BOOL WINAPI TryEnterCriticalSection( CRITICAL_SECTION *crit )
117 {
118     if (InterlockedIncrement( &crit->LockCount ))
119     {
120         if (crit->OwningThread == GetCurrentThreadId())
121         {
122             crit->RecursionCount++;
123             return TRUE;
124         }
125         /* FIXME: this doesn't work */
126         InterlockedDecrement( &crit->LockCount );
127         return FALSE;
128     }
129     crit->OwningThread   = GetCurrentThreadId();
130     crit->RecursionCount = 1;
131     return TRUE;
132 }
133
134
135 /***********************************************************************
136  *           LeaveCriticalSection   (KERNEL32.494) (NTDLL.426)
137  */
138 void WINAPI LeaveCriticalSection( CRITICAL_SECTION *crit )
139 {
140     if (crit->OwningThread != GetCurrentThreadId()) return;
141        
142     if (--crit->RecursionCount)
143     {
144         InterlockedDecrement( &crit->LockCount );
145         return;
146     }
147     crit->OwningThread = 0;
148     if (InterlockedDecrement( &crit->LockCount ) >= 0)
149     {
150         /* Someone is waiting */
151         ReleaseSemaphore( crit->LockSemaphore, 1, NULL );
152     }
153 }
154
155
156 /***********************************************************************
157  *           MakeCriticalSectionGlobal   (KERNEL32.515)
158  */
159 void WINAPI MakeCriticalSectionGlobal( CRITICAL_SECTION *crit )
160 {
161     crit->LockSemaphore = ConvertToGlobalHandle( crit->LockSemaphore );
162     crit->Reserved      = 0L;
163 }
164
165
166 /***********************************************************************
167  *           ReinitializeCriticalSection   (KERNEL32.581)
168  */
169 void WINAPI ReinitializeCriticalSection( CRITICAL_SECTION *crit )
170 {
171     if ( !crit->LockSemaphore )
172         InitializeCriticalSection( crit );
173
174     else if ( crit->Reserved && crit->Reserved != GetCurrentProcessId() )
175     {
176         FIXME("(%p) called for %08lx first, %08lx now: making global\n", 
177               crit, crit->Reserved, GetCurrentProcessId() );
178
179         MakeCriticalSectionGlobal( crit );
180     }
181 }
182
183
184 /***********************************************************************
185  *           UninitializeCriticalSection   (KERNEL32.703)
186  */
187 void WINAPI UninitializeCriticalSection( CRITICAL_SECTION *crit )
188 {
189     if ( crit->LockSemaphore )
190     {
191         if ( crit->Reserved )  /* not global */
192             DeleteCriticalSection( crit );
193         else
194             FIXME("(%p) for %08lx: Crst is global, don't know whether to delete\n", 
195                   crit, GetCurrentProcessId() );
196     }
197 }
198