kernel32/tests: Fix a test failure on Win9x/WinMe.
[wine] / dlls / kernel32 / syslevel.c
1 /*
2  * Win32 'syslevel' routines
3  *
4  * Copyright 1998 Ulrich Weigand
5  *
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.
10  *
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.
15  *
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22
23 #include <stdarg.h>
24 #ifdef HAVE_UNISTD_H
25 # include <unistd.h>
26 #endif
27 #include <sys/types.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winternl.h"
31 #include "wine/winbase16.h"
32 #include "kernel_private.h"
33 #include "kernel16_private.h"
34 #include "wine/library.h"
35 #include "wine/debug.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(syslevel);
38
39 static SYSLEVEL Win16Mutex;
40 static CRITICAL_SECTION_DEBUG critsect_debug =
41 {
42     0, 0, &Win16Mutex.crst,
43     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
44       0, 0, { (DWORD_PTR)(__FILE__ ": Win16Mutex") }
45 };
46 static SYSLEVEL Win16Mutex = { { &critsect_debug, -1, 0, 0, 0, 0 }, 1 };
47
48
49 /************************************************************************
50  *           GetpWin16Lock    (KERNEL32.93)
51  */
52 VOID WINAPI GetpWin16Lock(SYSLEVEL **lock)
53 {
54     *lock = &Win16Mutex;
55 }
56
57 /************************************************************************
58  *           GetpWin16Lock    (KERNEL.449)
59  */
60 SEGPTR WINAPI GetpWin16Lock16(void)
61 {
62     static SYSLEVEL *w16Mutex;
63     static SEGPTR segpWin16Mutex;
64
65     if (!segpWin16Mutex)
66     {
67         w16Mutex = &Win16Mutex;
68         segpWin16Mutex = MapLS( &w16Mutex );
69     }
70     return segpWin16Mutex;
71 }
72
73 /************************************************************************
74  *           _CreateSysLevel    (KERNEL.438)
75  */
76 VOID WINAPI _CreateSysLevel(SYSLEVEL *lock, INT level)
77 {
78     RtlInitializeCriticalSection( &lock->crst );
79     lock->level = level;
80
81     TRACE("(%p, %d): handle is %p\n",
82                   lock, level, lock->crst.LockSemaphore );
83 }
84
85 /************************************************************************
86  *           _EnterSysLevel    (KERNEL32.97)
87  *           _EnterSysLevel    (KERNEL.439)
88  */
89 VOID WINAPI _EnterSysLevel(SYSLEVEL *lock)
90 {
91     struct kernel_thread_data *thread_data = kernel_get_thread_data();
92     int i;
93
94     TRACE("(%p, level %d): thread %x count before %d\n",
95           lock, lock->level, GetCurrentThreadId(), thread_data->sys_count[lock->level] );
96
97     for ( i = 3; i > lock->level; i-- )
98         if ( thread_data->sys_count[i] > 0 )
99         {
100             ERR("(%p, level %d): Holding %p, level %d. Expect deadlock!\n",
101                         lock, lock->level, thread_data->sys_mutex[i], i );
102         }
103
104     RtlEnterCriticalSection( &lock->crst );
105
106     thread_data->sys_count[lock->level]++;
107     thread_data->sys_mutex[lock->level] = lock;
108
109     TRACE("(%p, level %d): thread %x count after  %d\n",
110           lock, lock->level, GetCurrentThreadId(), thread_data->sys_count[lock->level] );
111
112 #ifdef __i386__
113     if (lock == &Win16Mutex) CallTo16_TebSelector = wine_get_fs();
114 #endif
115 }
116
117 /************************************************************************
118  *           _LeaveSysLevel    (KERNEL32.98)
119  *           _LeaveSysLevel    (KERNEL.440)
120  */
121 VOID WINAPI _LeaveSysLevel(SYSLEVEL *lock)
122 {
123     struct kernel_thread_data *thread_data = kernel_get_thread_data();
124
125     TRACE("(%p, level %d): thread %x count before %d\n",
126           lock, lock->level, GetCurrentThreadId(), thread_data->sys_count[lock->level] );
127
128     if ( thread_data->sys_count[lock->level] <= 0 || thread_data->sys_mutex[lock->level] != lock )
129     {
130         ERR("(%p, level %d): Invalid state: count %d mutex %p.\n",
131                     lock, lock->level, thread_data->sys_count[lock->level],
132                     thread_data->sys_mutex[lock->level] );
133     }
134     else
135     {
136         if ( --thread_data->sys_count[lock->level] == 0 )
137             thread_data->sys_mutex[lock->level] = NULL;
138     }
139
140     RtlLeaveCriticalSection( &lock->crst );
141
142     TRACE("(%p, level %d): thread %x count after  %d\n",
143           lock, lock->level, GetCurrentThreadId(), thread_data->sys_count[lock->level] );
144 }
145
146 /************************************************************************
147  *              @ (KERNEL32.86)
148  */
149 VOID WINAPI _KERNEL32_86(SYSLEVEL *lock)
150 {
151     _LeaveSysLevel(lock);
152 }
153
154 /************************************************************************
155  *           _ConfirmSysLevel    (KERNEL32.95)
156  *           _ConfirmSysLevel    (KERNEL.436)
157  */
158 DWORD WINAPI _ConfirmSysLevel(SYSLEVEL *lock)
159 {
160     if ( lock && lock->crst.OwningThread == ULongToHandle(GetCurrentThreadId()) )
161         return lock->crst.RecursionCount;
162     else
163         return 0L;
164 }
165
166 /************************************************************************
167  *           _CheckNotSysLevel    (KERNEL32.94)
168  *           _CheckNotSysLevel    (KERNEL.437)
169  */
170 VOID WINAPI _CheckNotSysLevel(SYSLEVEL *lock)
171 {
172     if (lock && lock->crst.OwningThread == ULongToHandle(GetCurrentThreadId()) &&
173         lock->crst.RecursionCount)
174     {
175         ERR( "Holding lock %p level %d\n", lock, lock->level );
176         DbgBreakPoint();
177     }
178 }
179
180
181 /************************************************************************
182  *           _EnterWin16Lock                    [KERNEL.480]
183  */
184 VOID WINAPI _EnterWin16Lock(void)
185 {
186     _EnterSysLevel(&Win16Mutex);
187 }
188
189 /************************************************************************
190  *           _LeaveWin16Lock            [KERNEL.481]
191  */
192 VOID WINAPI _LeaveWin16Lock(void)
193 {
194     _LeaveSysLevel(&Win16Mutex);
195 }
196
197 /************************************************************************
198  *           _ConfirmWin16Lock    (KERNEL32.96)
199  */
200 DWORD WINAPI _ConfirmWin16Lock(void)
201 {
202     return _ConfirmSysLevel(&Win16Mutex);
203 }
204
205 /************************************************************************
206  *           ReleaseThunkLock    (KERNEL32.48)
207  */
208 VOID WINAPI ReleaseThunkLock(DWORD *mutex_count)
209 {
210     DWORD count = _ConfirmSysLevel(&Win16Mutex);
211     *mutex_count = count;
212
213     while (count-- > 0)
214         _LeaveSysLevel(&Win16Mutex);
215 }
216
217 /************************************************************************
218  *           RestoreThunkLock    (KERNEL32.49)
219  */
220 VOID WINAPI RestoreThunkLock(DWORD mutex_count)
221 {
222     while (mutex_count-- > 0)
223         _EnterSysLevel(&Win16Mutex);
224 }
225
226 /************************************************************************
227  *           SYSLEVEL_CheckNotLevel
228  */
229 VOID SYSLEVEL_CheckNotLevel( INT level )
230 {
231     INT i;
232
233     for ( i = 3; i >= level; i-- )
234         if ( kernel_get_thread_data()->sys_count[i] > 0 )
235         {
236             ERR("(%d): Holding lock of level %d!\n",
237                        level, i );
238             DbgBreakPoint();
239             break;
240         }
241 }