]> pd.if.org Git - liblfds/blob - liblfds/liblfds6.0.1/liblfds601/src/lfds601_abstraction/lfds601_abstraction_increment.c
Initial import (all versions, including the new 7.1.0)
[liblfds] / liblfds / liblfds6.0.1 / liblfds601 / src / lfds601_abstraction / lfds601_abstraction_increment.c
1 #include "lfds601_abstraction_internal.h"\r
2 \r
3 \r
4 \r
5 \r
6 \r
7 /****************************************************************************/\r
8 #if (defined _WIN64 && defined _MSC_VER)\r
9 \r
10   /* TRD : 64 bit Windows (user-mode or kernel) on any CPU with the Microsoft C compiler\r
11 \r
12            _WIN64    indicates 64 bit Windows\r
13            _MSC_VER  indicates Microsoft C compiler\r
14   */\r
15 \r
16   LFDS601_INLINE lfds601_atom_t lfds601_abstraction_increment( lfds601_atom_t *value )\r
17   {\r
18     __int64\r
19       rv;\r
20 \r
21     assert( value != NULL );\r
22 \r
23     rv = _InterlockedIncrement64( (__int64 *) value );\r
24 \r
25     return( (lfds601_atom_t) rv );\r
26   }\r
27 \r
28 #endif\r
29 \r
30 \r
31 \r
32 \r
33 \r
34 /****************************************************************************/\r
35 #if (!defined _WIN64 && defined _WIN32 && defined _MSC_VER)\r
36 \r
37   /* TRD : 32 bit Windows (user-mode or kernel) on any CPU with the Microsoft C compiler\r
38 \r
39            (!defined _WIN64 && defined _WIN32)  indicates 32 bit Windows\r
40            _MSC_VER                             indicates Microsoft C compiler\r
41   */\r
42 \r
43   LFDS601_INLINE lfds601_atom_t lfds601_abstraction_increment( lfds601_atom_t *value )\r
44   {\r
45     long int\r
46       rv;\r
47 \r
48     assert( value != NULL );\r
49 \r
50     rv = _InterlockedIncrement( (long int *) value );\r
51 \r
52     return( (lfds601_atom_t) rv );\r
53   }\r
54 \r
55 #endif\r
56 \r
57 \r
58 \r
59 \r
60 \r
61 /****************************************************************************/\r
62 #if (!defined __arm__ && __GNUC__ >= 4 && __GNUC_MINOR__ >= 1 && __GNUC_PATCHLEVEL__ >= 0)\r
63 \r
64   /* TRD : any OS on any CPU with GCC 4.1.0 or better\r
65 \r
66            GCC 4.1.0 introduced the __sync_*() atomic intrinsics\r
67 \r
68            __GNUC__ / __GNUC_MINOR__ / __GNUC_PATCHLEVEL__  indicates GCC and which version\r
69   */\r
70 \r
71   LFDS601_INLINE lfds601_atom_t lfds601_abstraction_increment( lfds601_atom_t *value )\r
72   {\r
73     lfds601_atom_t\r
74       rv;\r
75 \r
76     assert( value != NULL );\r
77 \r
78     // TRD : no need for casting here, GCC has a __sync_add_and_fetch() for all native types\r
79 \r
80     rv = __sync_add_and_fetch( value, 1 );\r
81 \r
82     return( rv );\r
83   }\r
84 \r
85 #endif\r
86 \r
87 \r
88 \r
89 \r
90 \r
91 /****************************************************************************/\r
92 #if (defined __arm__ && __GNUC__ >= 4)\r
93 \r
94   /* TRD : any OS on any CPU with GCC 4.1.0 or better\r
95 \r
96            GCC 4.1.0 introduced the __sync_*() atomic intrinsics\r
97 \r
98            __arm__   indicates ARM\r
99            __GNUC__  indicates GCC\r
100   */\r
101 \r
102   LFDS601_INLINE lfds601_atom_t lfds601_abstraction_increment( lfds601_atom_t *value )\r
103   {\r
104     lfds601_atom_t\r
105       stored_flag = 0,\r
106       new_value = 0;\r
107 \r
108     assert( value != NULL );\r
109 \r
110     __asm__ __volatile__\r
111     (\r
112       "  mov    %[stored_flag], #1;"                        // move 1 into stored_flag\r
113       "  mcr    p15, 0, %[zero], c7, c10, 5;"               // memory barrier (ARM v6 compatible)\r
114       "atomic_add:;"\r
115       "  ldrex  %[new_value], [%[value]];  "                // load *value into new_value\r
116       "  add    %[new_value], #1;"                          // add 1 to new_value\r
117       "  strex  %[stored_flag], %[new_value], [%[value]];"  // try to store new_value into *value (on success, strex puts 0 into stored_flag)\r
118       "  teq    %[stored_flag], #0;"                        // check if stored_flag is 0\r
119       "  bne    atomic_add;"                                // if not 0, retry (someone else touched *value after we loaded but before we stored)\r
120       "  mcr    p15, 0, %[zero], c7, c10, 5;"               // memory barrier (ARM v6 compatible)\r
121 \r
122       // output\r
123       : "+m" (*value), [new_value] "+&r" (new_value), [stored_flag] "+&r" (stored_flag)\r
124 \r
125       // input\r
126       : [value] "r" (value), [zero] "r" (0)\r
127 \r
128       // clobbered\r
129       : "cc", "memory"                                      // memory is clobbered because we issue a memory barrier\r
130     );\r
131 \r
132     return( new_value );\r
133   }\r
134 \r
135 #endif\r
136 \r