2002-04-16 Dick Porter <dick@ximian.com>
[mono.git] / mono / io-layer / atomic.h
1 #ifndef _WAPI_ATOMIC_H_
2 #define _WAPI_ATOMIC_H_
3
4 #include <glib.h>
5
6 #include "mono/io-layer/wapi.h"
7
8 #ifdef __i386__
9 #define WAPI_ATOMIC_ASM
10
11 /*
12  * NB: The *Pointer() functions here assume that
13  * sizeof(pointer)==sizeof(gint32)
14  *
15  * NB2: These asm functions assume 486+ (some of the opcodes dont
16  * exist on 386).  If this becomes an issue, we can get configure to
17  * fall back to the non-atomic C versions of these calls.
18  */
19
20 static inline gint32 InterlockedCompareExchange(volatile gint32 *dest,
21                                                 gint32 exch, gint32 comp)
22 {
23         gint32 old;
24
25         __asm__ __volatile__ ("lock; cmpxchgl %2, %0"
26                               : "=m" (*dest), "=a" (old)
27                               : "r" (exch), "0" (*dest), "a" (comp));   
28         return(old);
29 }
30
31 static inline gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp)
32 {
33         gpointer old;
34
35         __asm__ __volatile__ ("lock; cmpxchgl %2, %0"
36                               : "=m" (*dest), "=a" (old)
37                               : "r" (exch), "0" (*dest), "a" (comp));   
38         return(old);
39 }
40
41 static inline gint32 InterlockedIncrement(volatile gint32 *val)
42 {
43         gint32 tmp;
44         
45         __asm__ __volatile__ ("lock; xaddl %0, %1"
46                               : "=r" (tmp), "=m" (*val)
47                               : "0" (1), "1" (*val));
48
49         return(tmp+1);
50 }
51
52 static inline gint32 InterlockedDecrement(volatile gint32 *val)
53 {
54         gint32 tmp;
55         
56         __asm__ __volatile__ ("lock; xaddl %0, %1"
57                               : "=r" (tmp), "=m" (*val)
58                               : "0" (-1), "1" (*val));
59
60         return(tmp-1);
61 }
62
63 /*
64  * See
65  * http://msdn.microsoft.com/library/en-us/dnmag00/html/win320700.asp?frame=true
66  * for the reasons for using cmpxchg and a loop here.
67  */
68 static inline gint32 InterlockedExchange(volatile gint32 *val, gint32 new)
69 {
70         gint32 ret;
71         
72         __asm__ __volatile__ ("1:; lock; cmpxchgl %2, %0; jne 1b"
73                               : "=m" (*val), "=a" (ret)
74                               : "r" (new), "0" (*val), "a" (*val));
75
76         return(ret);
77 }
78
79 static inline gpointer InterlockedExchangePointer(volatile gpointer *val,
80                                                   gpointer new)
81 {
82         gpointer ret;
83         
84         __asm__ __volatile__ ("1:; lock; cmpxchgl %2, %0; jne 1b"
85                               : "=m" (*val), "=a" (ret)
86                               : "r" (new), "0" (*val), "a" (*val));
87
88         return(ret);
89 }
90
91 static inline gint32 InterlockedExchangeAdd(volatile gint32 *val, gint32 add)
92 {
93         gint32 ret;
94         
95         __asm__ __volatile__ ("lock; xaddl %0, %1"
96                               : "=r" (ret), "=m" (*val)
97                               : "0" (add), "1" (*val));
98         
99         return(ret);
100 }
101 #else
102 extern gint32 InterlockedCompareExchange(volatile gint32 *dest, gint32 exch, gint32 comp);
103 extern gpointer InterlockedCompareExchangePointer(volatile gpointer *dest, gpointer exch, gpointer comp);
104 extern gint32 InterlockedIncrement(volatile gint32 *dest);
105 extern gint32 InterlockedDecrement(volatile gint32 *dest);
106 extern gint32 InterlockedExchange(volatile gint32 *dest, gint32 exch);
107 extern gpointer InterlockedExchangePointer(volatile gpointer *dest, gpointer exch);
108 extern gint32 InterlockedExchangeAdd(volatile gint32 *dest, gint32 add);
109 #endif
110
111 #endif /* _WAPI_ATOMIC_H_ */