Do not use the PEB lock as loader lock, use a separate critical
[wine] / scheduler / syslevel.c
1 /*
2  * Win32 'syslevel' routines
3  *
4  * Copyright 1998 Ulrich Weigand
5  */
6
7 #include <unistd.h>
8 #include <sys/types.h>
9 #include "ntddk.h"
10 #include "syslevel.h"
11 #include "stackframe.h"
12 #include "debugtools.h"
13
14 DEFAULT_DEBUG_CHANNEL(win32);
15
16 static SYSLEVEL Win16Mutex = { CRITICAL_SECTION_INIT("Win16Mutex"), 1 };
17
18 /* Global variable to save current TEB while in 16-bit code */
19 WORD SYSLEVEL_Win16CurrentTeb = 0;
20
21
22 /************************************************************************
23  *           GetpWin16Lock    (KERNEL32.93)
24  */
25 VOID WINAPI GetpWin16Lock(SYSLEVEL **lock)
26 {
27     *lock = &Win16Mutex;
28 }
29
30 /************************************************************************
31  *           GetpWin16Lock    (KERNEL.449)
32  */
33 SEGPTR WINAPI GetpWin16Lock16(void)
34 {
35     static SYSLEVEL *w16Mutex;
36     static SEGPTR segpWin16Mutex;
37
38     if (!segpWin16Mutex)
39     {
40         w16Mutex = &Win16Mutex;
41         segpWin16Mutex = MapLS( &w16Mutex );
42     }
43     return segpWin16Mutex;
44 }
45
46 /************************************************************************
47  *           _CreateSysLevel    (KERNEL.438)
48  */
49 VOID WINAPI _CreateSysLevel(SYSLEVEL *lock, INT level)
50 {
51     InitializeCriticalSection( &lock->crst );
52     lock->level = level;
53
54     TRACE("(%p, %d): handle is %d\n", 
55                   lock, level, lock->crst.LockSemaphore );
56 }
57
58 /************************************************************************
59  *           _EnterSysLevel    (KERNEL32.97)
60  *           _EnterSysLevel    (KERNEL.439)
61  */
62 VOID WINAPI _EnterSysLevel(SYSLEVEL *lock)
63 {
64     TEB *teb = NtCurrentTeb();
65     int i;
66
67     TRACE("(%p, level %d): thread %p (fs %04x, pid %ld) count before %ld\n", 
68                   lock, lock->level, teb->tid, teb->teb_sel, (long) getpid(),
69                   teb->sys_count[lock->level] );
70
71     for ( i = 3; i > lock->level; i-- )
72         if ( teb->sys_count[i] > 0 )
73         {
74             ERR("(%p, level %d): Holding %p, level %d. Expect deadlock!\n", 
75                         lock, lock->level, teb->sys_mutex[i], i );
76         }
77
78     EnterCriticalSection( &lock->crst );
79
80     teb->sys_count[lock->level]++;
81     teb->sys_mutex[lock->level] = lock;
82
83     TRACE("(%p, level %d): thread %p (fs %04x, pid %ld) count after  %ld\n",
84                   lock, lock->level, teb->tid, teb->teb_sel, (long) getpid(), 
85                   teb->sys_count[lock->level] );
86
87     if (lock == &Win16Mutex)
88         SYSLEVEL_Win16CurrentTeb = __get_fs();
89 }
90
91 /************************************************************************
92  *           _LeaveSysLevel    (KERNEL32.98)
93  *           _LeaveSysLevel    (KERNEL.440)
94  */
95 VOID WINAPI _LeaveSysLevel(SYSLEVEL *lock)
96 {
97     TEB *teb = NtCurrentTeb();
98
99     TRACE("(%p, level %d): thread %p (fs %04x, pid %ld) count before %ld\n", 
100                   lock, lock->level, teb->tid, teb->teb_sel, (long) getpid(),
101                   teb->sys_count[lock->level] );
102
103     if ( teb->sys_count[lock->level] <= 0 || teb->sys_mutex[lock->level] != lock )
104     {
105         ERR("(%p, level %d): Invalid state: count %ld mutex %p.\n",
106                     lock, lock->level, teb->sys_count[lock->level], 
107                     teb->sys_mutex[lock->level] );
108     }
109     else
110     {
111         if ( --teb->sys_count[lock->level] == 0 )
112             teb->sys_mutex[lock->level] = NULL;
113     }
114
115     LeaveCriticalSection( &lock->crst );
116
117     TRACE("(%p, level %d): thread %p (fs %04x, pid %ld) count after  %ld\n",
118                   lock, lock->level, teb->tid, teb->teb_sel, (long) getpid(), 
119                   teb->sys_count[lock->level] );
120 }
121
122 /************************************************************************
123  *              @ (KERNEL32.86)
124  */
125 VOID WINAPI _KERNEL32_86(SYSLEVEL *lock)
126 {
127     _LeaveSysLevel(lock);
128 }
129
130 /************************************************************************
131  *           _ConfirmSysLevel    (KERNEL32.95)
132  *           _ConfirmSysLevel    (KERNEL.436)
133  */
134 DWORD WINAPI _ConfirmSysLevel(SYSLEVEL *lock)
135 {
136     if ( lock && lock->crst.OwningThread == GetCurrentThreadId() )
137         return lock->crst.RecursionCount;
138     else
139         return 0L;
140 }
141
142 /************************************************************************
143  *           _CheckNotSysLevel    (KERNEL32.94)
144  *           _CheckNotSysLevel    (KERNEL.437)
145  */
146 VOID WINAPI _CheckNotSysLevel(SYSLEVEL *lock)
147 {
148     if (lock && lock->crst.OwningThread == GetCurrentThreadId() && lock->crst.RecursionCount)
149     {
150         ERR( "Holding lock %p level %d\n", lock, lock->level );
151         DbgBreakPoint();
152     }
153 }
154
155
156 /************************************************************************
157  *           _EnterWin16Lock                    [KERNEL.480]
158  */
159 VOID WINAPI _EnterWin16Lock(void)
160 {
161     _EnterSysLevel(&Win16Mutex);
162 }
163
164 /************************************************************************
165  *           _LeaveWin16Lock            [KERNEL.481]
166  */
167 VOID WINAPI _LeaveWin16Lock(void)
168 {
169     _LeaveSysLevel(&Win16Mutex);
170 }
171
172 /************************************************************************
173  *           _ConfirmWin16Lock    (KERNEL32.96)
174  */
175 DWORD WINAPI _ConfirmWin16Lock(void)
176 {
177     return _ConfirmSysLevel(&Win16Mutex);
178 }
179
180 /************************************************************************
181  *           ReleaseThunkLock    (KERNEL32.48)
182  */
183 VOID WINAPI ReleaseThunkLock(DWORD *mutex_count)
184 {
185     DWORD count = _ConfirmSysLevel(&Win16Mutex);
186     *mutex_count = count;
187
188     while (count-- > 0)
189         _LeaveSysLevel(&Win16Mutex);
190 }
191
192 /************************************************************************
193  *           RestoreThunkLock    (KERNEL32.49)
194  */
195 VOID WINAPI RestoreThunkLock(DWORD mutex_count)
196 {
197     while (mutex_count-- > 0)
198         _EnterSysLevel(&Win16Mutex);
199 }
200
201 /************************************************************************
202  *           SYSLEVEL_CheckNotLevel
203  */
204 VOID SYSLEVEL_CheckNotLevel( INT level )
205 {
206     INT i;
207
208     for ( i = 3; i >= level; i-- )
209         if ( NtCurrentTeb()->sys_count[i] > 0 )
210         {
211             ERR("(%d): Holding lock of level %d!\n", 
212                        level, i );
213             DbgBreakPoint();
214             break;
215         }
216 }