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