Fix release semantics to make sure it flushes the store buffer on ia32/amd64.
[mono.git] / mono / utils / mono-memory-model.h
1 /*
2  * mono-memory-model.h: Mapping of the arch memory model.
3  *
4  * Author:
5  *      Rodrigo Kumpera (kumpera@gmail.com)
6  *
7  * (C) 2011 Xamarin, Inc
8  */
9
10 #ifndef _MONO_UTILS_MONO_MEMMODEL_H_
11 #define _MONO_UTILS_MONO_MEMMODEL_H_
12
13 #include <config.h>
14 #include <mono/utils/mono-membar.h>
15
16 /*
17 In order to allow for fast concurrent code, we must use fencing to properly order
18 memory access - specially on arch with weaker memory models such as ARM or PPC.
19
20 On the other hand, we can't use arm's weak model on targets such as x86 that have
21 a stronger model that requires much much less fencing.
22
23 The idea of exposing each arch memory model is to avoid fencing whenever possible
24 but at the same time make all required ordering explicit. 
25
26 There are four kinds of barriers, LoadLoad, LoadStore, StoreLoad and StoreStore.
27 Each arch must define which ones needs fencing.
28
29 We assume 3 kinds of barriers are available: load, store and memory (load+store).
30
31 TODO: Add support for weaker forms of CAS such as present on ARM.
32 TODO: replace all explicit uses of memory barriers with macros from this section. This will make a nicer read of lazy init code.
33 TODO: if we find places where a data depencency could replace barriers, add macros here to help with it
34 TODO: some arch with strong consistency, such as x86, support weaker access. We might need to expose more kinds of barriers once we exploit this.
35 */
36
37 #define MEMORY_BARRIER mono_memory_barrier ()
38 #define LOAD_BARRIER mono_memory_read_barrier ()
39 #define STORE_BARRIER mono_memory_write_barrier ()
40
41 enum {
42         StoreStoreBarrier,
43         LoadLoadBarrier,
44         StoreLoadBarrier,
45         LoadStoreBarrier,
46         FullBarrier
47 };
48
49 #if defined(__i386__) || defined(__x86_64__)
50 /*
51 Both x86 and amd64 follow the SPO memory model:
52 -Loads are not reordered with other loads
53 -Stores are not reordered with others stores
54 -Stores are not reordered with earlier loads
55 */
56
57 /*Neither sfence or mfence provide the required semantics here*/
58 #define STORE_LOAD_FENCE MEMORY_BARRIER
59 #define STORE_RELEASE_FENCE MEMORY_BARRIER
60
61 #elif defined(__arm__)
62 /*
63 ARM memory model is as weak as it can get. the only guarantee are data dependent
64 accesses.
65 LoadStore fences are much better handled using a data depencency such as:
66 load x;  if (x = x) store y;
67
68 This trick can be applied to other fences such as LoadLoad, but require some assembly:
69
70 LDR R0, [R1]
71 AND R0, R0, #0
72 LDR R3, [R4, R0]
73 */
74
75 #define STORE_STORE_FENCE STORE_BARRIER
76 #define LOAD_LOAD_FENCE LOAD_BARRIER
77 #define STORE_LOAD_FENCE MEMORY_BARRIER
78 #define LOAD_STORE_FENCE MEMORY_BARRIER
79 #define STORE_RELEASE_FENCE MEMORY_BARRIER
80
81 #else
82
83 /*default implementation with the weakest possible memory model */
84 #define STORE_STORE_FENCE STORE_BARRIER
85 #define LOAD_LOAD_FENCE LOAD_BARRIER
86 #define STORE_LOAD_FENCE MEMORY_BARRIER
87 #define LOAD_STORE_FENCE MEMORY_BARRIER
88 #define STORE_RELEASE_FENCE MEMORY_BARRIER
89
90 #endif
91
92 #ifndef STORE_STORE_FENCE
93 #define STORE_STORE_FENCE
94 #endif 
95
96 #ifndef LOAD_LOAD_FENCE
97 #define LOAD_LOAD_FENCE
98 #endif 
99
100 #ifndef STORE_LOAD_FENCE
101 #define STORE_LOAD_FENCE
102 #endif 
103
104 #ifndef LOAD_STORE_FENCE
105 #define LOAD_STORE_FENCE
106 #endif 
107
108 /*
109 Acquire/release semantics macros.
110
111 Acquire/release models what most code needs, which is to do load/store pairing of barriers
112 from multiple threads.
113 Release semantics makes sure all stores are visible before any subsequent memory access.
114 Acquire semantics make sure all following loads won't be visible before the current one.
115
116 This is a slightly harmless variantion on ECMA's that further constraints ordering amongs
117 different kinds of access.
118 */
119 #define mono_atomic_store_release(target,value) do {    \
120         *(target) = (value);    \
121         STORE_RELEASE_FENCE;    \
122 } while (0)
123
124 /*Makes sure all previous stores as visible before */
125 #define mono_atomic_store_seq(target,value) do {        \
126         STORE_STORE_FENCE;      \
127         *(target) = (value);    \
128 } while (0)
129
130
131 /*Combines the guarantees of store_release and store_seq.*/
132 #define mono_atomic_store_release_seq(target,value) do {        \
133         mono_atomic_store_seq (target, value)   \
134         STORE_RELEASE_FENCE;    \
135 } while (0)
136
137
138 #define mono_atomic_load_acquire(target) ({     \
139         typeof (*target) __tmp = *target;       \
140         LOAD_LOAD_FENCE;        \
141         __tmp; })
142
143 #endif /* _MONO_UTILS_MONO_MEMMODEL_H_ */