Updated first example using latest winebuild dll/so procedure.
[wine] / scheduler / critsection.c
1 /*
2  * Win32 critical sections
3  *
4  * Copyright 1998 Alexandre Julliard
5  */
6
7 #include <assert.h>
8 #include <errno.h>
9 #include <stdio.h>
10 #include <sys/types.h>
11
12 #include "config.h"
13 #include "winerror.h"
14 #include "winbase.h"
15 #include "ntddk.h"
16 #include "heap.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.472)
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.515)
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.581)
69  */
70 void WINAPI ReinitializeCriticalSection( CRITICAL_SECTION *crit )
71 {
72     if ( !crit->LockSemaphore )
73         RtlInitializeCriticalSection( crit );
74 }
75
76
77 /***********************************************************************
78  *           UninitializeCriticalSection   (KERNEL32.703)
79  */
80 void WINAPI UninitializeCriticalSection( CRITICAL_SECTION *crit )
81 {
82     RtlDeleteCriticalSection( crit );
83 }
84
85 #ifdef __i386__
86
87 /***********************************************************************
88  *              InterlockCompareExchange (KERNEL32.@)
89  */
90 PVOID WINAPI InterlockedCompareExchange( PVOID *dest, PVOID xchg, PVOID 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  *              InterlockDecrement (KERNEL32.@)
131  */
132 LONG WINAPI InterlockedDecrement( PLONG dest );
133 __ASM_GLOBAL_FUNC(InterlockedDecrement,
134                   "movl 4(%esp),%edx\n\t"
135                   "movl $-1,%eax\n\t"
136                   "lock; xaddl %eax,(%edx)\n\t"
137                   "decl %eax\n\t"
138                   "ret $4");
139
140 #elif defined(__sparc__) && defined(__sun__)
141
142 /*
143  * As the earlier Sparc processors lack necessary atomic instructions,
144  * I'm simply falling back to the library-provided _lwp_mutex routines
145  * to ensure mutual exclusion in a way appropriate for the current 
146  * architecture.  
147  *
148  * FIXME:  If we have the compare-and-swap instruction (Sparc v9 and above)
149  *         we could use this to speed up the Interlocked operations ...
150  */
151
152 #include <synch.h>
153 static lwp_mutex_t interlocked_mutex = DEFAULTMUTEX;
154
155 /***********************************************************************
156  *              InterlockedCompareExchange (KERNEL32.@)
157  */
158 PVOID WINAPI InterlockedCompareExchange( PVOID *dest, PVOID xchg, PVOID compare )
159 {
160     _lwp_mutex_lock( &interlocked_mutex );
161
162     if ( *dest == compare )
163         *dest = xchg;
164     else
165         compare = *dest;
166     
167     _lwp_mutex_unlock( &interlocked_mutex );
168     return compare;
169 }
170
171 /***********************************************************************
172  *              InterlockedExchange (KERNEL32.@)
173  */
174 LONG WINAPI InterlockedExchange( PLONG dest, LONG val )
175 {
176     LONG retv;
177     _lwp_mutex_lock( &interlocked_mutex );
178
179     retv = *dest;
180     *dest = val;
181
182     _lwp_mutex_unlock( &interlocked_mutex );
183     return retv;
184 }
185
186 /***********************************************************************
187  *              InterlockedExchangeAdd (KERNEL32.@)
188  */
189 LONG WINAPI InterlockedExchangeAdd( PLONG dest, LONG incr )
190 {
191     LONG retv;
192     _lwp_mutex_lock( &interlocked_mutex );
193
194     retv = *dest;
195     *dest += incr;
196
197     _lwp_mutex_unlock( &interlocked_mutex );
198     return retv;
199 }
200
201 /***********************************************************************
202  *              InterlockedIncrement (KERNEL32.@)
203  */
204 LONG WINAPI InterlockedIncrement( PLONG dest )
205 {
206     LONG retv;
207     _lwp_mutex_lock( &interlocked_mutex );
208
209     retv = ++*dest;
210
211     _lwp_mutex_unlock( &interlocked_mutex );
212     return retv;
213 }
214
215 /***********************************************************************
216  *              InterlockedDecrement (KERNEL32.@)
217  */
218 LONG WINAPI InterlockedDecrement( PLONG dest )
219 {
220     LONG retv;
221     _lwp_mutex_lock( &interlocked_mutex );
222
223     retv = --*dest;
224
225     _lwp_mutex_unlock( &interlocked_mutex );
226     return retv;
227 }
228
229 #else
230 #error You must implement the Interlocked* functions for your CPU
231 #endif