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