]> pd.if.org Git - liblfds/blob - liblfds/liblfds6.0.0/liblfds600/src/lfds600_abstraction/lfds600_abstraction_cas.c
Initial import (all versions, including the new 7.1.0)
[liblfds] / liblfds / liblfds6.0.0 / liblfds600 / src / lfds600_abstraction / lfds600_abstraction_cas.c
1 #include "lfds600_abstraction_internal.h"
2
3
4
5
6
7 /****************************************************************************/
8 #if (defined _WIN32 && defined _MSC_VER)
9
10   /* TRD : 64 bit and 32 bit Windows (user-mode or kernel) on any CPU with the Microsoft C compiler
11
12            _WIN32    indicates 64-bit or 32-bit Windows
13            _MSC_VER  indicates Microsoft C compiler
14   */
15
16   LFDS600_INLINE lfds600_atom_t lfds600_abstraction_cas( volatile lfds600_atom_t *destination, lfds600_atom_t exchange, lfds600_atom_t compare )
17   {
18     assert( destination != NULL );
19     // TRD : exchange can be any value in its range
20     // TRD : compare can be any value in its range
21
22     return( (lfds600_atom_t) _InterlockedCompareExchangePointer((void * volatile *) destination, (void *) exchange, (void *) compare) );
23   }
24
25 #endif
26
27
28
29
30
31 /****************************************************************************/
32 #if (!defined __arm__ && __GNUC__ >= 4 && __GNUC_MINOR__ >= 1 && __GNUC_PATCHLEVEL__ >= 0)
33
34   /* TRD : any OS on any CPU except ARM with GCC 4.1.0 or better
35
36            GCC 4.1.0 introduced the __sync_*() atomic intrinsics
37
38            __GNUC__ / __GNUC_MINOR__ / __GNUC_PATCHLEVEL__  indicates GCC and which version
39   */
40
41   LFDS600_INLINE lfds600_atom_t lfds600_abstraction_cas( volatile lfds600_atom_t *destination, lfds600_atom_t exchange, lfds600_atom_t compare )
42   {
43     assert( destination != NULL );
44     // TRD : exchange can be any value in its range
45     // TRD : compare can be any value in its range
46
47     // TRD : note the different argument order for the GCC instrinsic to the MSVC instrinsic
48
49     return( (lfds600_atom_t) __sync_val_compare_and_swap(destination, compare, exchange) );
50   }
51
52 #endif
53
54
55
56
57
58 /****************************************************************************/
59 #if (defined __arm__ && __GNUC__)
60
61   /* TRD : any OS on any ARM with GCC
62
63            Remember however we need to set into compare the original value of destination.
64
65            __arm__   indicates ARM
66            __GNUC__  indicates GCC
67   */
68
69   LFDS600_INLINE lfds600_atom_t lfds600_abstraction_cas( volatile lfds600_atom_t *destination, lfds600_atom_t exchange, lfds600_atom_t compare )
70   {
71     lfds600_atom_t
72       stored_flag,
73       original_destination;
74
75     assert( destination != NULL );
76     // TRD : exchange can be any value in its range
77     // TRD : compare can be any value in its range
78
79     /* TRD : this is a standard, plain CAS, vulnerable to ABA */
80
81     __asm__ __volatile__
82     (
83       "  mov    %[stored_flag], #1;"                             // put 1 into stored_flag
84       "  mcr    p15, 0, %[zero], c7, c10, 5;"                    // memory barrier (ARM v6 compatible)
85       "atomic_cas:;"
86       "  ldrex  %[original_destination], [%[destination]];"      // load *destination into original_destination
87       "  teq    %[original_destination], %[compare];"            // compare original_destination with compare
88       "  bne    exit;"                                           // if not equal, exit
89       "  strex  %[stored_flag], %[exchange], [%[destination]];"  // if equal, try to store exchange into *destination (on success, strex puts 0 into stored_flag)
90       "  teq    %[stored_flag], #0;"                             // check if stored_flag is 0
91       "  bne    atomic_cas;"                                     // if not 0, retry (someone else touched *destination after we loaded but before we stored)
92       "  mcr    p15, 0, %[zero], c7, c10, 5;"                    // memory barrier (ARM v6 compatible)
93       "exit:;"
94
95       // output
96       : "+m" (*destination), [original_destination] "=&r" (original_destination), [stored_flag] "=&r" (stored_flag)
97
98       // input
99       : [destination] "r" (destination), [compare] "r" (compare), [exchange] "r" (exchange), [zero] "r" (0)
100
101       // clobbered
102       : "cc", "memory"                                           // memory is clobbered because we issue a memory barrier
103     );
104
105     return( original_destination );
106   }
107
108 #endif
109