1 | |
2 | // |
3 | // This source file is part of appleseed. |
4 | // Visit http://appleseedhq.net/ for additional information and resources. |
5 | // |
6 | // This software is released under the MIT license. |
7 | // |
8 | // Copyright (c) 2016-2017 Francois Beaune, The appleseedhq Organization |
9 | // |
10 | // Permission is hereby granted, free of charge, to any person obtaining a copy |
11 | // of this software and associated documentation files (the "Software"), to deal |
12 | // in the Software without restriction, including without limitation the rights |
13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
14 | // copies of the Software, and to permit persons to whom the Software is |
15 | // furnished to do so, subject to the following conditions: |
16 | // |
17 | // The above copyright notice and this permission notice shall be included in |
18 | // all copies or substantial portions of the Software. |
19 | // |
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
26 | // THE SOFTWARE. |
27 | // |
28 | |
29 | #ifndef APPLESEED_FOUNDATION_PLATFORM_ATOMIC_H |
30 | #define APPLESEED_FOUNDATION_PLATFORM_ATOMIC_H |
31 | |
32 | // appleseed.foundation headers. |
33 | #include "foundation/platform/compiler.h" |
34 | #include "foundation/platform/types.h" |
35 | #ifdef _WIN32 |
36 | #include "foundation/platform/windows.h" |
37 | #endif |
38 | #include "foundation/utility/casts.h" |
39 | #include "foundation/utility/memory.h" |
40 | |
41 | // Boost headers. |
42 | #include "boost/atomic/atomic.hpp" |
43 | #include "boost/interprocess/detail/atomic.hpp" |
44 | |
45 | // Standard headers. |
46 | #include <cassert> |
47 | |
48 | namespace foundation |
49 | { |
50 | |
51 | // |
52 | // Atomic operations on native types. |
53 | // |
54 | |
55 | uint32 atomic_read( |
56 | volatile uint32* ptr); |
57 | |
58 | void atomic_write( |
59 | volatile uint32* ptr, |
60 | const uint32 value); |
61 | |
62 | uint32 atomic_inc( |
63 | volatile uint32* ptr); |
64 | |
65 | uint32 atomic_dec( |
66 | volatile uint32* ptr); |
67 | |
68 | uint32 atomic_cas( |
69 | volatile uint32* ptr, |
70 | const uint32 expected_value, |
71 | const uint32 new_value); |
72 | |
73 | void atomic_add( |
74 | volatile float* ptr, |
75 | const float operand); |
76 | |
77 | |
78 | // |
79 | // Implementation. |
80 | // |
81 | |
82 | APPLESEED_FORCE_INLINE uint32 atomic_read( |
83 | volatile uint32* ptr) |
84 | { |
85 | return boost::interprocess::ipcdetail::atomic_read32(ptr); |
86 | } |
87 | |
88 | APPLESEED_FORCE_INLINE void atomic_write( |
89 | volatile uint32* ptr, |
90 | const uint32 value) |
91 | { |
92 | boost::interprocess::ipcdetail::atomic_write32(ptr, value); |
93 | } |
94 | |
95 | APPLESEED_FORCE_INLINE uint32 atomic_inc( |
96 | volatile uint32* ptr) |
97 | { |
98 | return boost::interprocess::ipcdetail::atomic_inc32(ptr); |
99 | } |
100 | |
101 | APPLESEED_FORCE_INLINE uint32 atomic_dec( |
102 | volatile uint32* ptr) |
103 | { |
104 | return boost::interprocess::ipcdetail::atomic_dec32(ptr); |
105 | } |
106 | |
107 | APPLESEED_FORCE_INLINE uint32 atomic_cas( |
108 | volatile uint32* ptr, |
109 | const uint32 expected_value, |
110 | const uint32 new_value) |
111 | { |
112 | #if defined _WIN32 |
113 | return InterlockedCompareExchange(ptr, new_value, expected_value); |
114 | #elif defined __GNUC__ |
115 | return __sync_val_compare_and_swap(ptr, expected_value, new_value); |
116 | #else |
117 | #error Unsupported platform. |
118 | #endif |
119 | } |
120 | |
121 | APPLESEED_FORCE_INLINE void atomic_add( |
122 | volatile float* ptr, |
123 | const float operand) |
124 | { |
125 | assert(is_aligned(ptr, 4)); |
126 | |
127 | volatile uint32* iptr = reinterpret_cast<volatile uint32*>(ptr); |
128 | uint32 expected = *iptr; |
129 | |
130 | while (true) |
131 | { |
132 | const float value = binary_cast<float>(expected); |
133 | const uint32 new_value = binary_cast<uint32>(value + operand); |
134 | const uint32 actual = atomic_cas(iptr, expected, new_value); |
135 | if (actual == expected) |
136 | return; |
137 | expected = actual; |
138 | } |
139 | } |
140 | |
141 | } // namespace foundation |
142 | |
143 | #endif // !APPLESEED_FOUNDATION_PLATFORM_ATOMIC_H |
144 | |