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
48namespace foundation
49{
50
51//
52// Atomic operations on native types.
53//
54
55uint32 atomic_read(
56 volatile uint32* ptr);
57
58void atomic_write(
59 volatile uint32* ptr,
60 const uint32 value);
61
62uint32 atomic_inc(
63 volatile uint32* ptr);
64
65uint32 atomic_dec(
66 volatile uint32* ptr);
67
68uint32 atomic_cas(
69 volatile uint32* ptr,
70 const uint32 expected_value,
71 const uint32 new_value);
72
73void atomic_add(
74 volatile float* ptr,
75 const float operand);
76
77
78//
79// Implementation.
80//
81
82APPLESEED_FORCE_INLINE uint32 atomic_read(
83 volatile uint32* ptr)
84{
85 return boost::interprocess::ipcdetail::atomic_read32(ptr);
86}
87
88APPLESEED_FORCE_INLINE void atomic_write(
89 volatile uint32* ptr,
90 const uint32 value)
91{
92 boost::interprocess::ipcdetail::atomic_write32(ptr, value);
93}
94
95APPLESEED_FORCE_INLINE uint32 atomic_inc(
96 volatile uint32* ptr)
97{
98 return boost::interprocess::ipcdetail::atomic_inc32(ptr);
99}
100
101APPLESEED_FORCE_INLINE uint32 atomic_dec(
102 volatile uint32* ptr)
103{
104 return boost::interprocess::ipcdetail::atomic_dec32(ptr);
105}
106
107APPLESEED_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
121APPLESEED_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