Changed the GDI driver interface to pass an opaque PHYSDEV pointer
[wine] / scheduler / critsection.c
1 /*
2  * Win32 critical sections
3  *
4  * Copyright 1998 Alexandre Julliard
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 <assert.h>
24 #include <errno.h>
25 #include <stdio.h>
26 #include <sys/types.h>
27
28 #include "winerror.h"
29 #include "winbase.h"
30 #include "ntddk.h"
31 #include "wine/debug.h"
32 #include "thread.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(win32);
35 WINE_DECLARE_DEBUG_CHANNEL(relay);
36
37 /***********************************************************************
38  *           InitializeCriticalSection   (KERNEL32.@)
39  */
40 void WINAPI InitializeCriticalSection( CRITICAL_SECTION *crit )
41 {
42     NTSTATUS ret = RtlInitializeCriticalSection( crit );
43     if (ret) RtlRaiseStatus( ret );
44 }
45
46 /***********************************************************************
47  *           InitializeCriticalSectionAndSpinCount   (KERNEL32.@)
48  */
49 BOOL WINAPI InitializeCriticalSectionAndSpinCount( CRITICAL_SECTION *crit, DWORD spincount )
50 {
51     NTSTATUS ret = RtlInitializeCriticalSectionAndSpinCount( crit, spincount );
52     if (ret) RtlRaiseStatus( ret );
53     return !ret;
54 }
55
56 /***********************************************************************
57  *           SetCriticalSectionSpinCount   (KERNEL32.@)
58  * This function is available on NT4SP3 or later, but not Win98
59  * It is SMP related
60  */
61 DWORD WINAPI SetCriticalSectionSpinCount( CRITICAL_SECTION *crit, DWORD spincount )
62 {
63     ULONG_PTR oldspincount = crit->SpinCount;
64     if(spincount) FIXME("critsection=%p: spincount=%ld not supported\n", crit, spincount);
65     crit->SpinCount = spincount;
66     return oldspincount;
67 }
68
69 /***********************************************************************
70  *           MakeCriticalSectionGlobal   (KERNEL32.@)
71  */
72 void WINAPI MakeCriticalSectionGlobal( CRITICAL_SECTION *crit )
73 {
74     /* let's assume that only one thread at a time will try to do this */
75     HANDLE sem = crit->LockSemaphore;
76     if (!sem) NtCreateSemaphore( &sem, SEMAPHORE_ALL_ACCESS, NULL, 0, 1 );
77     crit->LockSemaphore = ConvertToGlobalHandle( sem );
78 }
79
80
81 /***********************************************************************
82  *           ReinitializeCriticalSection   (KERNEL32.@)
83  */
84 void WINAPI ReinitializeCriticalSection( CRITICAL_SECTION *crit )
85 {
86     if ( !crit->LockSemaphore )
87         RtlInitializeCriticalSection( crit );
88 }
89
90
91 /***********************************************************************
92  *           UninitializeCriticalSection   (KERNEL32.@)
93  */
94 void WINAPI UninitializeCriticalSection( CRITICAL_SECTION *crit )
95 {
96     RtlDeleteCriticalSection( crit );
97 }
98
99 #ifdef __i386__
100
101 /***********************************************************************
102  *              InterlockedCompareExchange (KERNEL32.@)
103  */
104 /* LONG WINAPI InterlockedCompareExchange( PLONG dest, LONG xchg, LONG compare ); */
105 __ASM_GLOBAL_FUNC(InterlockedCompareExchange,
106                   "movl 12(%esp),%eax\n\t"
107                   "movl 8(%esp),%ecx\n\t"
108                   "movl 4(%esp),%edx\n\t"
109                   "lock; cmpxchgl %ecx,(%edx)\n\t"
110                   "ret $12");
111
112 /***********************************************************************
113  *              InterlockedExchange (KERNEL32.@)
114  */
115 /* LONG WINAPI InterlockedExchange( PLONG dest, LONG val ); */
116 __ASM_GLOBAL_FUNC(InterlockedExchange,
117                   "movl 8(%esp),%eax\n\t"
118                   "movl 4(%esp),%edx\n\t"
119                   "lock; xchgl %eax,(%edx)\n\t"
120                   "ret $8");
121
122 /***********************************************************************
123  *              InterlockedExchangeAdd (KERNEL32.@)
124  */
125 /* LONG WINAPI InterlockedExchangeAdd( PLONG dest, LONG incr ); */
126 __ASM_GLOBAL_FUNC(InterlockedExchangeAdd,
127                   "movl 8(%esp),%eax\n\t"
128                   "movl 4(%esp),%edx\n\t"
129                   "lock; xaddl %eax,(%edx)\n\t"
130                   "ret $8");
131
132 /***********************************************************************
133  *              InterlockedIncrement (KERNEL32.@)
134  */
135 /* LONG WINAPI InterlockedIncrement( PLONG dest ); */
136 __ASM_GLOBAL_FUNC(InterlockedIncrement,
137                   "movl 4(%esp),%edx\n\t"
138                   "movl $1,%eax\n\t"
139                   "lock; xaddl %eax,(%edx)\n\t"
140                   "incl %eax\n\t"
141                   "ret $4");
142
143 /***********************************************************************
144  *              InterlockedDecrement (KERNEL32.@)
145  */
146 __ASM_GLOBAL_FUNC(InterlockedDecrement,
147                   "movl 4(%esp),%edx\n\t"
148                   "movl $-1,%eax\n\t"
149                   "lock; xaddl %eax,(%edx)\n\t"
150                   "decl %eax\n\t"
151                   "ret $4");
152
153 #elif defined(__sparc__) && defined(__sun__)
154
155 /*
156  * As the earlier Sparc processors lack necessary atomic instructions,
157  * I'm simply falling back to the library-provided _lwp_mutex routines
158  * to ensure mutual exclusion in a way appropriate for the current 
159  * architecture.  
160  *
161  * FIXME:  If we have the compare-and-swap instruction (Sparc v9 and above)
162  *         we could use this to speed up the Interlocked operations ...
163  */
164
165 #include <synch.h>
166 static lwp_mutex_t interlocked_mutex = DEFAULTMUTEX;
167
168 /***********************************************************************
169  *              InterlockedCompareExchange (KERNEL32.@)
170  */
171 LONG WINAPI InterlockedCompareExchange( PLONG dest, LONG xchg, LONG compare )
172 {
173     _lwp_mutex_lock( &interlocked_mutex );
174
175     if ( *dest == compare )
176         *dest = xchg;
177     else
178         compare = *dest;
179     
180     _lwp_mutex_unlock( &interlocked_mutex );
181     return compare;
182 }
183
184 /***********************************************************************
185  *              InterlockedExchange (KERNEL32.@)
186  */
187 LONG WINAPI InterlockedExchange( PLONG dest, LONG val )
188 {
189     LONG retv;
190     _lwp_mutex_lock( &interlocked_mutex );
191
192     retv = *dest;
193     *dest = val;
194
195     _lwp_mutex_unlock( &interlocked_mutex );
196     return retv;
197 }
198
199 /***********************************************************************
200  *              InterlockedExchangeAdd (KERNEL32.@)
201  */
202 LONG WINAPI InterlockedExchangeAdd( PLONG dest, LONG incr )
203 {
204     LONG retv;
205     _lwp_mutex_lock( &interlocked_mutex );
206
207     retv = *dest;
208     *dest += incr;
209
210     _lwp_mutex_unlock( &interlocked_mutex );
211     return retv;
212 }
213
214 /***********************************************************************
215  *              InterlockedIncrement (KERNEL32.@)
216  */
217 LONG WINAPI InterlockedIncrement( PLONG dest )
218 {
219     LONG retv;
220     _lwp_mutex_lock( &interlocked_mutex );
221
222     retv = ++*dest;
223
224     _lwp_mutex_unlock( &interlocked_mutex );
225     return retv;
226 }
227
228 /***********************************************************************
229  *              InterlockedDecrement (KERNEL32.@)
230  */
231 LONG WINAPI InterlockedDecrement( PLONG dest )
232 {
233     LONG retv;
234     _lwp_mutex_lock( &interlocked_mutex );
235
236     retv = --*dest;
237
238     _lwp_mutex_unlock( &interlocked_mutex );
239     return retv;
240 }
241
242 #else
243 #error You must implement the Interlocked* functions for your CPU
244 #endif