Release 970914
[wine] / win32 / thread.c
1 /*
2  * Win32 kernel functions
3  *
4  * Copyright 1995 Martin von Loewis
5  * Copyright 1997 Onno Hovers
6  */
7
8 #include <stdio.h>
9 #include <unistd.h>
10 #include <string.h>
11 #include <sys/ipc.h>
12 #include <sys/sem.h>
13 #include "windows.h"
14 #include "winbase.h"
15 #include "winerror.h"
16 #include "stddebug.h"
17 #include "debug.h"
18 #include "xmalloc.h"
19
20
21 /*
22  * FIXME: 
23  * The c functions do not protect from non-interlocked accesses
24  * This is no problem as long as we do not have multiple Win32 threads 
25  * or processes. 
26  * The assembly macro's do protect from non-interlocked access,
27  * but they will only work for i386 systems with GCC.  
28  */
29  
30 /************************************************************************
31 *           InterlockedIncrement                        [KERNEL32]      *
32 *                                                                       *
33 * InterlockedIncrement adds 1 to a long variable and returns            *
34 *  -  a negative number if the result < 0                               *
35 *  -  zero if the result == 0                                           *
36 *  -  a positive number if the result > 0                               *
37 *                                                                       *
38 * The returned number need not be equal to the result!!!!               *
39 ************************************************************************/
40
41 LONG WINAPI InterlockedIncrement(LPLONG lpAddend)
42 {
43 #if defined(__i386__)&&defined(__GNUC__)
44         long ret;
45         __asm__
46         (                
47            "\tlock\n"   /* for SMP systems */
48            "\tincl      (%1)\n"
49            "\tje        2f\n"
50            "\tjl        1f\n"
51            "\tincl      %0\n"
52            "\tjmp       2f\n"
53            "1:\tdec     %0\n"             
54            "2:\n"
55            :"=r" (ret):"r" (lpAddend), "0" (0): "memory"
56         );
57         return ret;
58 #else      
59         LONG ret;
60         /* StopAllThreadsAndProcesses() */
61         
62         (*lpAddend)++;
63         ret=*lpAddend;
64
65         /* ResumeAllThreadsAndProcesses() */
66         return ret;
67 #endif   
68 }
69
70 /************************************************************************
71 *           InterlockedDecrement                        [KERNEL32]      *
72 *                                                                       *
73 * InterlockedIncrement adds 1 to a long variable and returns            *
74 *  -  a negative number if the result < 0                               *
75 *  -  zero if the result == 0                                           *
76 *  -  a positive number if the result > 0                               *
77 *                                                                       *
78 * The returned number need not be equal to the result!!!!               *
79 ************************************************************************/
80
81 LONG WINAPI InterlockedDecrement(LPLONG lpAddend)
82 {
83 #if defined(__i386__)&&defined(__GNUC__)        
84         LONG ret;
85         __asm__
86         (                
87            "\tlock\n"   /* for SMP systems */
88            "\tdecl      (%1)\n"
89            "\tje        2f\n"
90            "\tjl        1f\n"
91            "\tincl      %0\n"
92            "\tjmp       2f\n"
93            "1:\tdec     %0\n"             
94            "2:\n"
95            :"=r" (ret):"r" (lpAddend), "0" (0): "memory"          
96         );
97         return ret;
98 #else   
99         LONG ret;
100         /* StopAllThreadsAndProcesses() */
101
102         (*lpAddend)--;
103         ret=*lpAddend;
104
105         /* ResumeAllThreadsAndProcesses() */
106         return ret;
107 #endif  
108 }
109
110 /************************************************************************
111 *           InterlockedExchange                         [KERNEL32]      *
112 ************************************************************************/
113
114 LONG WINAPI InterlockedExchange(LPLONG target, LONG value)
115 {
116 #if defined(__i386__)&&defined(__GNUC__)        
117         LONG ret;
118         __asm__
119         (                
120
121            "\tlock\n"   /* for SMP systems */
122            "\txchgl     %0,(%1)\n"                
123            :"=r" (ret):"r" (target), "0" (value):"memory"
124         );
125         return ret;
126 #else
127         LONG ret;
128         /* StopAllThreadsAndProcesses() */      
129
130         ret=*target;
131         *target=value;
132
133         /* ResumeAllThreadsAndProcesses() */
134         return ret;
135 #endif  
136 }
137
138 /* AAARGHH some CriticalSection functions get called before we 
139  * have a threadid
140  */
141  
142 #define GetCurrentThreadId()    (-1)
143
144 /************************************************************************
145 *           InitializeCriticalSection                   [KERNEL32]      *
146 ************************************************************************/
147
148 void WINAPI InitializeCriticalSection(CRITICAL_SECTION *pcritical)
149 {
150    pcritical->LockCount=-1;
151    pcritical->RecursionCount=0;
152    pcritical->LockSemaphore=(HANDLE32) semget(IPC_PRIVATE,1,IPC_CREAT);
153    pcritical->OwningThread=(HANDLE32) -1;
154    pcritical->Reserved=0;
155 }
156
157 /************************************************************************
158 *           DeleteCriticalSection                       [KERNEL32]      *
159 ************************************************************************/
160
161 void WINAPI DeleteCriticalSection(CRITICAL_SECTION *pcritical)
162 {
163    semctl((int) pcritical->LockSemaphore,0,IPC_RMID,(union semun)NULL);
164    pcritical->Reserved=-1;
165 }
166
167 /************************************************************************
168 *           EnterCriticalSection                        [KERNEL32]      *
169 ************************************************************************/
170
171 void WINAPI EnterCriticalSection (CRITICAL_SECTION *pcritical)
172 {
173    if( InterlockedIncrement(&(pcritical->LockCount)))
174    {   
175       if( pcritical->OwningThread!= (HANDLE32) GetCurrentThreadId() )
176       {                 
177          struct sembuf sop;
178                                              
179          sop.sem_num=0;
180          sop.sem_op=0;
181          sop.sem_flg=0;            
182          semop((int) pcritical->LockSemaphore,&sop,0);
183             
184          pcritical->OwningThread = (HANDLE32) GetCurrentThreadId();                
185       }
186    }
187    else
188    {      
189       pcritical->OwningThread =(HANDLE32) GetCurrentThreadId();
190    }
191    pcritical->RecursionCount++;             
192 }
193
194 /************************************************************************
195 *           TryEnterCriticalSection                     [KERNEL32]      *
196 ************************************************************************/
197
198 BOOL32 WINAPI TryEnterCriticalSection (CRITICAL_SECTION *pcritical)
199 {
200    if( InterlockedIncrement(&(pcritical->LockCount)))
201    {
202       if( pcritical->OwningThread!= (HANDLE32) GetCurrentThreadId() )
203          return FALSE;
204    }
205    else
206    {      
207       pcritical->OwningThread =(HANDLE32) GetCurrentThreadId();
208    }
209    pcritical->RecursionCount++;             
210    
211    return TRUE;
212 }
213
214 /************************************************************************
215 *           LeaveCriticalSection                        [KERNEL32]      *
216 ************************************************************************/
217
218 void WINAPI LeaveCriticalSection(CRITICAL_SECTION *pcritical)
219 {
220    /* do we actually own this critical section ??? */
221    if( pcritical->OwningThread!= (HANDLE32) GetCurrentThreadId())
222       return;
223        
224    pcritical->RecursionCount--;
225    if( pcritical->RecursionCount==0)
226    {
227       pcritical->OwningThread=(HANDLE32)-1;
228       if(InterlockedDecrement(&(pcritical->LockCount))>=0)
229       {         
230          struct sembuf sop;
231          
232          sop.sem_num=0;
233          sop.sem_op=1;
234          sop.sem_flg=0;
235          semop((int) pcritical->LockSemaphore,&sop,0);
236       }
237    }
238    else
239    {
240        InterlockedDecrement(&(pcritical->LockCount));
241    }  
242 }
243
244 /************************************************************************
245 *           ReinitializeCriticalSection                 [KERNEL32]      *
246 ************************************************************************/
247
248 void WINAPI ReinitializeCriticalSection(CRITICAL_SECTION *lpCrit)
249 {
250    /* hmm ?????? */     
251 }
252
253 /************************************************************************
254 *           MakeCriticalSectionGlobal                   [KERNEL32]      *
255 ************************************************************************/
256
257 void WINAPI MakeCriticalSectionGlobal(CRITICAL_SECTION *lpCrit)
258 {
259    /* nothing (SysV Semaphores are already global) */
260    return;      
261 }
262