Open Dynamics Engine
threading_atomics_provs.h
1 /*************************************************************************
2  * *
3  * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. *
4  * All rights reserved. Email: russ@q12.org Web: www.q12.org *
5  * *
6  * Threading atomics providers file. *
7  * Copyright (C) 2011-2012 Oleh Derevenko. All rights reserved. *
8  * e-mail: odar@eleks.com (change all "a" to "e") *
9  * *
10  * This library is free software; you can redistribute it and/or *
11  * modify it under the terms of EITHER: *
12  * (1) The GNU Lesser General Public License as published by the Free *
13  * Software Foundation; either version 2.1 of the License, or (at *
14  * your option) any later version. The text of the GNU Lesser *
15  * General Public License is included with this library in the *
16  * file LICENSE.TXT. *
17  * (2) The BSD-style license that is included with this library in *
18  * the file LICENSE-BSD.TXT. *
19  * *
20  * This library is distributed in the hope that it will be useful, *
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
23  * LICENSE.TXT and LICENSE-BSD.TXT for more details. *
24  * *
25  *************************************************************************/
26 
27 /*
28  * Fake atomics provider for built-in threading support provider.
29  * OU-based atomics provider for built-in threading support provider.
30  *
31  * The classes have been moved into a separate header as they are to be used
32  * in both WIN and POSIX implementations.
33  */
34 
35 
36 #ifndef _ODE_THREADING_ATOMICS_PROVS_H_
37 #define _ODE_THREADING_ATOMICS_PROVS_H_
38 
39 
40 #include <ode/odeconfig.h>
41 #include <ode/error.h>
42 
43 
44 /************************************************************************/
45 /* Fake atomics provider class implementation */
46 /************************************************************************/
47 
49 {
50 public:
51  typedef unsigned long atomicord_t;
52  typedef void *atomicptr_t;
53 
54 public:
55  static void IncrementTargetNoRet(volatile atomicord_t *value_accumulator_ptr)
56  {
57  ++(*value_accumulator_ptr);
58  }
59 
60  static void DecrementTargetNoRet(volatile atomicord_t *value_accumulator_ptr)
61  {
62  --(*value_accumulator_ptr);
63  }
64 
65  static atomicord_t QueryTargetValue(volatile atomicord_t *value_storage_ptr)
66  {
67  return *value_storage_ptr;
68  }
69 
70  template<unsigned type_size>
71  static size_t AddValueToTarget(volatile void *value_accumulator_ptr, ptrdiff_t value_addend);
72 
73  static bool CompareExchangeTargetPtr(volatile atomicptr_t *pointer_storage_ptr,
74  atomicptr_t comparand_value, atomicptr_t new_value)
75  {
76  bool exchange_result = false;
77 
78  atomicptr_t original_value = *pointer_storage_ptr;
79 
80  if (original_value == comparand_value)
81  {
82  *pointer_storage_ptr = new_value;
83 
84  exchange_result = true;
85  }
86 
87  return exchange_result;
88  }
89 };
90 
91 template<>
92 inline size_t dxFakeAtomicsProvider::AddValueToTarget<sizeof(dxFakeAtomicsProvider::atomicord_t)>(volatile void *value_accumulator_ptr, ptrdiff_t value_addend)
93 {
94  atomicord_t original_value = *(volatile atomicord_t *)value_accumulator_ptr;
95 
96  *(volatile atomicord_t *)value_accumulator_ptr = original_value + (atomicord_t)value_addend;
97 
98  return original_value;
99 }
100 
101 template<>
102 inline size_t dxFakeAtomicsProvider::AddValueToTarget<2 * sizeof(dxFakeAtomicsProvider::atomicord_t)>(volatile void *value_accumulator_ptr, ptrdiff_t value_addend)
103 {
104  atomicptr_t original_value = *(volatile atomicptr_t *)value_accumulator_ptr;
105 
106  *(volatile atomicptr_t *)value_accumulator_ptr = (atomicptr_t)((size_t)original_value + (size_t)value_addend);
107 
108  return (size_t)original_value;
109 }
110 
111 
112 #if dBUILTIN_THREADING_IMPL_ENABLED
113 
114 /************************************************************************/
115 /* dxOUAtomicsProvider class implementation */
116 /************************************************************************/
117 
118 #if !dOU_ENABLED
119 #error OU library must be enabled for this to compile
120 #elif !dATOMICS_ENABLED
121 #error OU Atomics must be enabled for this to compile
122 #endif
123 #include "odeou.h"
124 
125 class dxOUAtomicsProvider
126 {
127 public:
128  typedef _OU_NAMESPACE::atomicord32 atomicord_t;
129  typedef _OU_NAMESPACE::atomicptr atomicptr_t;
130 
131 public:
132  static void IncrementTargetNoRet(volatile atomicord_t *value_accumulator_ptr)
133  {
134  _OU_NAMESPACE::AtomicIncrementNoResult(value_accumulator_ptr);
135  }
136 
137  static void DecrementTargetNoRet(volatile atomicord_t *value_accumulator_ptr)
138  {
139  _OU_NAMESPACE::AtomicDecrementNoResult(value_accumulator_ptr);
140  }
141 
142  static atomicord_t QueryTargetValue(volatile atomicord_t *value_storage_ptr)
143  {
144  // Query value with memory barrier before
145  atomicord_t result_value = *value_storage_ptr;
146 
147  if (!_OU_NAMESPACE::AtomicCompareExchange(value_storage_ptr, result_value, result_value))
148  {
149  result_value = *value_storage_ptr;
150  }
151 
152  return result_value;
153  }
154 
155  template<unsigned type_size>
156  static size_t AddValueToTarget(volatile void *value_accumulator_ptr, ptrdiff_t value_addend);
157 
158  static bool CompareExchangeTargetPtr(volatile atomicptr_t *pointer_storage_ptr,
159  atomicptr_t comparand_value, atomicptr_t new_value)
160  {
161  return _OU_NAMESPACE::AtomicCompareExchangePointer(pointer_storage_ptr, comparand_value, new_value);
162  }
163 };
164 
165 template<>
166 inline size_t dxOUAtomicsProvider::AddValueToTarget<sizeof(dxOUAtomicsProvider::atomicord_t)>(volatile void *value_accumulator_ptr, ptrdiff_t value_addend)
167 {
168  return _OU_NAMESPACE::AtomicExchangeAdd((volatile atomicord_t *)value_accumulator_ptr, (atomicord_t)value_addend);
169 }
170 
171 template<>
172 inline size_t dxOUAtomicsProvider::AddValueToTarget<2 * sizeof(dxOUAtomicsProvider::atomicord_t)>(volatile void *value_accumulator_ptr, ptrdiff_t value_addend)
173 {
174  atomicptr_t original_value;
175 
176  while (true)
177  {
178  original_value = *(volatile atomicptr_t *)value_accumulator_ptr;
179 
180  atomicptr_t new_value = (atomicptr_t)((size_t)original_value + (size_t)value_addend);
181  if (_OU_NAMESPACE::AtomicCompareExchangePointer((volatile atomicptr_t *)value_accumulator_ptr, original_value, new_value))
182  {
183  break;
184  }
185  }
186 
187  return (size_t)original_value;
188 }
189 
190 
191 #endif // #if dBUILTIN_THREADING_IMPL_ENABLED
192 
193 
194 #endif // #ifndef _ODE_THREADING_ATOMICS_PROVS_H_
Definition: threading_atomics_provs.h:48