Set %fs and %gs in the register context to their current value when
[wine] / dlls / kernel / 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 "winreg.h"
31 #include "winternl.h"
32 #include "wine/winbase16.h"
33 #include "thread.h"
34 #include "kernel_private.h"
35 #include "wine/library.h"
36 #include "wine/debug.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(win32);
39
40 static SYSLEVEL Win16Mutex;
41 static CRITICAL_SECTION_DEBUG critsect_debug =
42 {
43     0, 0, &Win16Mutex.crst,
44     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
45       0, 0, { 0, (DWORD)(__FILE__ ": Win16Mutex") }
46 };
47 static SYSLEVEL Win16Mutex = { { &critsect_debug, -1, 0, 0, 0, 0 }, 1 };
48
49 #ifdef __i386__
50 extern unsigned int CallTo16_TebSelector;
51 extern void __wine_set_signal_fs( unsigned int fs );
52 #endif
53
54
55 /************************************************************************
56  *           GetpWin16Lock    (KERNEL32.93)
57  */
58 VOID WINAPI GetpWin16Lock(SYSLEVEL **lock)
59 {
60     *lock = &Win16Mutex;
61 }
62
63 /************************************************************************
64  *           GetpWin16Lock    (KERNEL.449)
65  */
66 SEGPTR WINAPI GetpWin16Lock16(void)
67 {
68     static SYSLEVEL *w16Mutex;
69     static SEGPTR segpWin16Mutex;
70
71     if (!segpWin16Mutex)
72     {
73         w16Mutex = &Win16Mutex;
74         segpWin16Mutex = MapLS( &w16Mutex );
75     }
76     return segpWin16Mutex;
77 }
78
79 /************************************************************************
80  *           _CreateSysLevel    (KERNEL.438)
81  */
82 VOID WINAPI _CreateSysLevel(SYSLEVEL *lock, INT level)
83 {
84     RtlInitializeCriticalSection( &lock->crst );
85     lock->level = level;
86
87     TRACE("(%p, %d): handle is %p\n",
88                   lock, level, lock->crst.LockSemaphore );
89 }
90
91 /************************************************************************
92  *           _EnterSysLevel    (KERNEL32.97)
93  *           _EnterSysLevel    (KERNEL.439)
94  */
95 VOID WINAPI _EnterSysLevel(SYSLEVEL *lock)
96 {
97     TEB *teb = NtCurrentTeb();
98     int i;
99
100     TRACE("(%p, level %d): thread %lx count before %ld\n",
101           lock, lock->level, GetCurrentThreadId(), teb->sys_count[lock->level] );
102
103     for ( i = 3; i > lock->level; i-- )
104         if ( teb->sys_count[i] > 0 )
105         {
106             ERR("(%p, level %d): Holding %p, level %d. Expect deadlock!\n",
107                         lock, lock->level, teb->sys_mutex[i], i );
108         }
109
110     RtlEnterCriticalSection( &lock->crst );
111
112     teb->sys_count[lock->level]++;
113     teb->sys_mutex[lock->level] = lock;
114
115     TRACE("(%p, level %d): thread %lx count after  %ld\n",
116           lock, lock->level, GetCurrentThreadId(), teb->sys_count[lock->level] );
117
118 #ifdef __i386__
119     if (lock == &Win16Mutex)
120     {
121         __wine_set_signal_fs( wine_get_fs() );
122         CallTo16_TebSelector = wine_get_fs();
123     }
124 #endif
125 }
126
127 /************************************************************************
128  *           _LeaveSysLevel    (KERNEL32.98)
129  *           _LeaveSysLevel    (KERNEL.440)
130  */
131 VOID WINAPI _LeaveSysLevel(SYSLEVEL *lock)
132 {
133     TEB *teb = NtCurrentTeb();
134
135     TRACE("(%p, level %d): thread %lx count before %ld\n",
136           lock, lock->level, GetCurrentThreadId(), teb->sys_count[lock->level] );
137
138     if ( teb->sys_count[lock->level] <= 0 || teb->sys_mutex[lock->level] != lock )
139     {
140         ERR("(%p, level %d): Invalid state: count %ld mutex %p.\n",
141                     lock, lock->level, teb->sys_count[lock->level],
142                     teb->sys_mutex[lock->level] );
143     }
144     else
145     {
146         if ( --teb->sys_count[lock->level] == 0 )
147             teb->sys_mutex[lock->level] = NULL;
148     }
149
150     RtlLeaveCriticalSection( &lock->crst );
151
152     TRACE("(%p, level %d): thread %lx count after  %ld\n",
153           lock, lock->level, GetCurrentThreadId(), teb->sys_count[lock->level] );
154 }
155
156 /************************************************************************
157  *              @ (KERNEL32.86)
158  */
159 VOID WINAPI _KERNEL32_86(SYSLEVEL *lock)
160 {
161     _LeaveSysLevel(lock);
162 }
163
164 /************************************************************************
165  *           _ConfirmSysLevel    (KERNEL32.95)
166  *           _ConfirmSysLevel    (KERNEL.436)
167  */
168 DWORD WINAPI _ConfirmSysLevel(SYSLEVEL *lock)
169 {
170     if ( lock && lock->crst.OwningThread == (HANDLE)GetCurrentThreadId() )
171         return lock->crst.RecursionCount;
172     else
173         return 0L;
174 }
175
176 /************************************************************************
177  *           _CheckNotSysLevel    (KERNEL32.94)
178  *           _CheckNotSysLevel    (KERNEL.437)
179  */
180 VOID WINAPI _CheckNotSysLevel(SYSLEVEL *lock)
181 {
182     if (lock && lock->crst.OwningThread == (HANDLE)GetCurrentThreadId() &&
183         lock->crst.RecursionCount)
184     {
185         ERR( "Holding lock %p level %d\n", lock, lock->level );
186         DbgBreakPoint();
187     }
188 }
189
190
191 /************************************************************************
192  *           _EnterWin16Lock                    [KERNEL.480]
193  */
194 VOID WINAPI _EnterWin16Lock(void)
195 {
196     _EnterSysLevel(&Win16Mutex);
197 }
198
199 /************************************************************************
200  *           _LeaveWin16Lock            [KERNEL.481]
201  */
202 VOID WINAPI _LeaveWin16Lock(void)
203 {
204     _LeaveSysLevel(&Win16Mutex);
205 }
206
207 /************************************************************************
208  *           _ConfirmWin16Lock    (KERNEL32.96)
209  */
210 DWORD WINAPI _ConfirmWin16Lock(void)
211 {
212     return _ConfirmSysLevel(&Win16Mutex);
213 }
214
215 /************************************************************************
216  *           ReleaseThunkLock    (KERNEL32.48)
217  */
218 VOID WINAPI ReleaseThunkLock(DWORD *mutex_count)
219 {
220     DWORD count = _ConfirmSysLevel(&Win16Mutex);
221     *mutex_count = count;
222
223     while (count-- > 0)
224         _LeaveSysLevel(&Win16Mutex);
225 }
226
227 /************************************************************************
228  *           RestoreThunkLock    (KERNEL32.49)
229  */
230 VOID WINAPI RestoreThunkLock(DWORD mutex_count)
231 {
232     while (mutex_count-- > 0)
233         _EnterSysLevel(&Win16Mutex);
234 }
235
236 /************************************************************************
237  *           SYSLEVEL_CheckNotLevel
238  */
239 VOID SYSLEVEL_CheckNotLevel( INT level )
240 {
241     INT i;
242
243     for ( i = 3; i >= level; i-- )
244         if ( NtCurrentTeb()->sys_count[i] > 0 )
245         {
246             ERR("(%d): Holding lock of level %d!\n",
247                        level, i );
248             DbgBreakPoint();
249             break;
250         }
251 }