Authors: Chris Morgan <cmorgan@wpi.edu>, James Abbatiello <abbeyj@wpi.edu>
[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 <unistd.h>
9 #include <string.h>
10 #include "windef.h"
11 #include "winerror.h"
12
13
14 /*
15  * FIXME: 
16  * The c functions do not protect from non-interlocked accesses
17  * This is no problem as long as we do not have multiple Win32 threads 
18  * or processes. 
19  * The assembly macro's do protect from non-interlocked access,
20  * but they will only work for i386 systems with GCC.  
21  */
22  
23 /************************************************************************
24 *           InterlockedIncrement                        [KERNEL32]      *
25 *                                                                       *
26 * InterlockedIncrement adds 1 to a long variable and returns            *
27 *  -  a negative number if the result < 0                               *
28 *  -  zero if the result == 0                                           *
29 *  -  a positive number if the result > 0                               *
30 *                                                                       *
31 * The returned number need not be equal to the result!!!!               *
32 ************************************************************************/
33
34 LONG WINAPI InterlockedIncrement(LPLONG lpAddend)
35 {
36 #if defined(__i386__)&&defined(__GNUC__)
37         long ret;
38         __asm__
39         (                
40            "\tlock\n"   /* for SMP systems */
41            "\tincl      (%1)\n"
42            "\tje        2f\n"
43            "\tjl        1f\n"
44            "\tincl      %0\n"
45            "\tjmp       2f\n"
46            "1:\tdec     %0\n"             
47            "2:\n"
48            :"=r" (ret):"r" (lpAddend), "0" (0): "memory"
49         );
50         return ret;
51 #else      
52         LONG ret;
53         /* StopAllThreadsAndProcesses() */
54         
55         (*lpAddend)++;
56         ret=*lpAddend;
57
58         /* ResumeAllThreadsAndProcesses() */
59         return ret;
60 #endif   
61 }
62
63 /************************************************************************
64 *           InterlockedDecrement                        [KERNEL32]      *
65 *                                                                       *
66 * InterlockedIncrement adds 1 to a long variable and returns            *
67 *  -  a negative number if the result < 0                               *
68 *  -  zero if the result == 0                                           *
69 *  -  a positive number if the result > 0                               *
70 *                                                                       *
71 * The returned number need not be equal to the result!!!!               *
72 ************************************************************************/
73
74 LONG WINAPI InterlockedDecrement(LPLONG lpAddend)
75 {
76 #if defined(__i386__)&&defined(__GNUC__)        
77         LONG ret;
78         __asm__
79         (                
80            "\tlock\n"   /* for SMP systems */
81            "\tdecl      (%1)\n"
82            "\tje        2f\n"
83            "\tjl        1f\n"
84            "\tincl      %0\n"
85            "\tjmp       2f\n"
86            "1:\tdec     %0\n"             
87            "2:\n"
88            :"=r" (ret):"r" (lpAddend), "0" (0): "memory"          
89         );
90         return ret;
91 #else   
92         LONG ret;
93         /* StopAllThreadsAndProcesses() */
94
95         (*lpAddend)--;
96         ret=*lpAddend;
97
98         /* ResumeAllThreadsAndProcesses() */
99         return ret;
100 #endif  
101 }
102
103 /************************************************************************
104  *           InterlockedExchange                                [KERNEL32.???]
105  *
106  * Atomically exchanges a pair of values.
107  *
108  * RETURNS
109  *      Prior value of value pointed to by Target
110  */
111 LONG WINAPI InterlockedExchange(
112             LPLONG target, /* Address of 32-bit value to exchange */
113             LONG value     /* New value for the value pointed to by target */
114 ) {
115 #if defined(__i386__)&&defined(__GNUC__)        
116         LONG ret;
117         __asm__ ( /* lock for SMP systems */
118                   "lock\n\txchgl %0,(%1)"
119                   :"=r" (ret):"r" (target), "0" (value):"memory" );
120         return ret;
121 #else
122         LONG ret;
123         /* StopAllThreadsAndProcesses() */      
124
125         ret=*target;
126         *target=value;
127
128         /* ResumeAllThreadsAndProcesses() */
129         return ret;
130 #endif  
131 }
132
133 /************************************************************************
134  *           InterlockedCompareExchange         [KERNEL32.879]
135  *
136  * Atomically compares Destination and Comperand, and if found equal exchanges
137  * the value of Destination with Exchange
138  *
139  * RETURNS
140  *      Prior value of value pointed to by Destination
141  */
142 PVOID WINAPI InterlockedCompareExchange(
143             PVOID *Destination, /* Address of 32-bit value to exchange */
144             PVOID Exchange,      /* change value, 32 bits */ 
145             PVOID Comperand      /* value to compare, 32 bits */
146 ) {
147 #if defined(__i386__)&&defined(__GNUC__)        
148         PVOID ret;
149         __asm__ ( /* lock for SMP systems */
150                   "lock\n\t"
151                   "cmpxchgl %2,(%1)"
152                   :"=r" (ret)
153                   :"r" (Destination),"r" (Exchange), "0" (Comperand)
154                   :"memory" );
155         return ret;
156 #else
157         PVOID ret;
158         /* StopAllThreadsAndProcesses() */      
159
160         ret=*Destination;
161         if(*Destination==Comperand) *Destination=Exchange;
162
163         /* ResumeAllThreadsAndProcesses() */
164         return ret;
165 #endif  
166 }
167
168 /************************************************************************
169  *           InterlockedExchangeAdd                     [KERNEL32.880]
170  *
171  * Atomically adds Increment to Addend and returns the previous value of
172  * Addend
173  *
174  * RETURNS
175  *      Prior value of value pointed to by cwAddendTarget
176  */
177 LONG WINAPI InterlockedExchangeAdd(
178             PLONG Addend, /* Address of 32-bit value to exchange */
179             LONG Increment /* Value to add */
180 ) {
181 #if defined(__i386__)&&defined(__GNUC__)        
182         LONG ret;
183         __asm__ ( /* lock for SMP systems */
184                   "lock\n\t"
185                   "xaddl %0,(%1)"
186                   :"=r" (ret)
187                   :"r" (Addend), "0" (Increment)
188                   :"memory" );
189         return ret;
190 #else
191         LONG ret;
192         /* StopAllThreadsAndProcesses() */      
193
194         ret = *Addend;
195         *Addend += Increment;
196
197         /* ResumeAllThreadsAndProcesses() */
198         return ret;
199 #endif  
200 }