]> pd.if.org Git - liblfds/blob - liblfds/liblfds6.1.1/liblfds611/src/lfds611_abstraction/lfds611_abstraction_dcas.c
Initial import (all versions, including the new 7.1.0)
[liblfds] / liblfds / liblfds6.1.1 / liblfds611 / src / lfds611_abstraction / lfds611_abstraction_dcas.c
1 #include "lfds611_abstraction_internal_body.h"
2
3
4
5
6
7 /****************************************************************************/
8 #if (defined _WIN64 && defined _MSC_VER)
9
10   /* TRD : 64 bit Windows (user-mode or kernel) on any CPU with the Microsoft C compiler
11
12            _WIN64    indicates 64 bit Windows
13            _MSC_VER  indicates Microsoft C compiler
14   */
15
16   static LFDS611_INLINE unsigned char lfds611_abstraction_dcas( volatile lfds611_atom_t *destination, lfds611_atom_t *exchange, lfds611_atom_t *compare )
17   {
18     unsigned char
19       cas_result;
20
21     assert( destination != NULL );
22     assert( exchange != NULL );
23     assert( compare != NULL );
24
25     LFDS611_BARRIER_COMPILER_FULL;
26
27     cas_result = _InterlockedCompareExchange128( (volatile __int64 *) destination, (__int64) *(exchange+1), (__int64) *exchange, (__int64 *) compare );
28
29     LFDS611_BARRIER_COMPILER_FULL;
30
31     return( cas_result ) ;
32   }
33
34 #endif
35
36
37
38
39
40 /****************************************************************************/
41 #if (!defined _WIN64 && defined _WIN32 && defined _MSC_VER)
42
43   /* TRD : 32 bit Windows (user-mode or kernel) on any CPU with the Microsoft C compiler
44
45            (!defined _WIN64 && defined _WIN32)  indicates 32 bit Windows
46            _MSC_VER                             indicates Microsoft C compiler
47   */
48
49   static LFDS611_INLINE unsigned char lfds611_abstraction_dcas( volatile lfds611_atom_t *destination, lfds611_atom_t *exchange, lfds611_atom_t *compare )
50   {
51     __int64
52       original_compare;
53
54     assert( destination != NULL );
55     assert( exchange != NULL );
56     assert( compare != NULL );
57
58     *(__int64 *) &original_compare = *(__int64 *) compare;
59
60     LFDS611_BARRIER_COMPILER_FULL;
61
62     *(__int64 *) compare = _InterlockedCompareExchange64( (volatile __int64 *) destination, *(__int64 *) exchange, *(__int64 *) compare );
63
64     LFDS611_BARRIER_COMPILER_FULL;
65
66     return( (unsigned char) (*(__int64 *) compare == *(__int64 *) &original_compare) );
67   }
68
69 #endif
70
71
72
73
74
75 /****************************************************************************/
76 #if (defined __x86_64__ && defined __GNUC__)
77
78   /* TRD : any OS on x64 with GCC
79
80            __x86_64__  indicates x64
81            __GNUC__    indicates GCC
82   */
83
84   static LFDS611_INLINE unsigned char lfds611_abstraction_dcas( volatile lfds611_atom_t *destination, lfds611_atom_t *exchange, lfds611_atom_t *compare )
85   {
86     unsigned char
87       cas_result;
88
89     assert( destination != NULL );
90     assert( exchange != NULL );
91     assert( compare != NULL );
92
93     // TRD : __asm__ with "memory" in the clobber list is for GCC a full compiler barrier
94     __asm__ __volatile__
95     (
96       "lock;"           // make cmpxchg16b atomic
97       "cmpxchg16b %0;"  // cmpxchg16b sets ZF on success
98       "setz       %3;"  // if ZF set, set cas_result to 1
99
100       // output
101       : "+m" (*(volatile lfds611_atom_t (*)[2]) destination), "+a" (*compare), "+d" (*(compare+1)), "=q" (cas_result)
102
103       // input
104       : "b" (*exchange), "c" (*(exchange+1))
105
106       // clobbered
107       : "cc", "memory"
108     );
109
110     return( cas_result );
111   }
112
113 #endif
114
115
116
117
118
119 /****************************************************************************/
120 #if ((defined __i686__ || defined __arm__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 1 && __GNUC_PATCHLEVEL__ >= 0)
121
122   /* TRD : any OS on x86 or ARM with GCC 4.1.0 or better
123
124            GCC 4.1.0 introduced the __sync_*() atomic intrinsics
125
126            __GNUC__ / __GNUC_MINOR__ / __GNUC_PATCHLEVEL__  indicates GCC and which version
127   */
128
129   static LFDS611_INLINE unsigned char lfds611_abstraction_dcas( volatile lfds611_atom_t *destination, lfds611_atom_t *exchange, lfds611_atom_t *compare )
130   {
131     unsigned char
132       cas_result = 0;
133
134     unsigned long long int
135       original_destination;
136
137     assert( destination != NULL );
138     assert( exchange != NULL );
139     assert( compare != NULL );
140
141     LFDS611_BARRIER_COMPILER_FULL;
142
143     original_destination = __sync_val_compare_and_swap( (volatile unsigned long long int *) destination, *(unsigned long long int *) compare, *(unsigned long long int *) exchange );
144
145     LFDS611_BARRIER_COMPILER_FULL;
146
147     if( original_destination == *(unsigned long long int *) compare )
148       cas_result = 1;
149
150     *(unsigned long long int *) compare = original_destination;
151
152     return( cas_result );
153   }
154
155 #endif
156
157