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