safe_refcount.h
1 /*************************************************************************/
2 /* safe_refcount.h */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* http://www.godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
9 /* */
10 /* Permission is hereby granted, free of charge, to any person obtaining */
11 /* a copy of this software and associated documentation files (the */
12 /* "Software"), to deal in the Software without restriction, including */
13 /* without limitation the rights to use, copy, modify, merge, publish, */
14 /* distribute, sublicense, and/or sell copies of the Software, and to */
15 /* permit persons to whom the Software is furnished to do so, subject to */
16 /* the following conditions: */
17 /* */
18 /* The above copyright notice and this permission notice shall be */
19 /* included in all copies or substantial portions of the Software. */
20 /* */
21 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
22 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
23 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
24 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
25 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
26 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
27 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
28 /*************************************************************************/
29 #ifndef SAFE_REFCOUNT_H
30 #define SAFE_REFCOUNT_H
31 
32 #include "os/mutex.h"
33 /* x86/x86_64 GCC */
34 
35 #include "platform_config.h"
36 
37 
38 #ifdef NO_THREADS
39 
40 struct SafeRefCount {
41 
42  int count;
43 
44 public:
45 
46  // destroy() is called when weak_count_ drops to zero.
47 
48  bool ref() { //true on success
49 
50  if (count==0)
51  return false;
52  count++;
53 
54  return true;
55  }
56 
57  int refval() { //true on success
58 
59  if (count==0)
60  return 0;
61  count++;
62  return count;
63  }
64 
65  bool unref() { // true if must be disposed of
66 
67  if (count>0)
68  count--;
69 
70  return count==0;
71  }
72 
73  long get() const { // nothrow
74 
75  return static_cast<int const volatile &>( count );
76  }
77 
78  void init(int p_value=1) {
79 
80  count=p_value;
81  };
82 
83 };
84 
85 
86 
87 
88 
89 
90 
91 
92 #else
93 
94 #if defined( PLATFORM_REFCOUNT )
95 
96 #include "platform_refcount.h"
97 
98 
99 #elif defined( __GNUC__ ) && ( defined( __i386__ ) || defined( __x86_64__ ) )
100 
101 #define REFCOUNT_T volatile int
102 #define REFCOUNT_GET_T int const volatile&
103 
104 static inline int atomic_conditional_increment( volatile int * pw ) {
105  // int rv = *pw;
106  // if( rv != 0 ) ++*pw;
107  // return rv;
108 
109  int rv, tmp;
110 
111  __asm__
112  (
113  "movl %0, %%eax\n\t"
114  "0:\n\t"
115  "test %%eax, %%eax\n\t"
116  "je 1f\n\t"
117  "movl %%eax, %2\n\t"
118  "incl %2\n\t"
119  "lock\n\t"
120  "cmpxchgl %2, %0\n\t"
121  "jne 0b\n\t"
122  "1:":
123  "=m"( *pw ), "=&a"( rv ), "=&r"( tmp ): // outputs (%0, %1, %2)
124  "m"( *pw ): // input (%3)
125  "cc" // clobbers
126  );
127 
128  return rv;
129 }
130 
131 static inline int atomic_decrement( volatile int *pw) {
132 
133  // return --(*pw);
134 
135  unsigned char rv;
136 
137  __asm__
138  (
139  "lock\n\t"
140  "decl %0\n\t"
141  "setne %1":
142  "=m" (*pw), "=qm" (rv):
143  "m" (*pw):
144  "memory"
145  );
146  return static_cast<int>(rv);
147 }
148 
149 /* PowerPC32/64 GCC */
150 
151 #elif ( defined( __GNUC__ ) ) && ( defined( __powerpc__ ) || defined( __ppc__ ) )
152 
153 #define REFCOUNT_T int
154 #define REFCOUNT_GET_T int const volatile&
155 
156 inline int atomic_conditional_increment( int * pw )
157 {
158  // if( *pw != 0 ) ++*pw;
159  // return *pw;
160 
161  int rv;
162 
163  __asm__
164  (
165  "0:\n\t"
166  "lwarx %1, 0, %2\n\t"
167  "cmpwi %1, 0\n\t"
168  "beq 1f\n\t"
169  "addi %1, %1, 1\n\t"
170  "1:\n\t"
171  "stwcx. %1, 0, %2\n\t"
172  "bne- 0b":
173 
174  "=m"( *pw ), "=&b"( rv ):
175  "r"( pw ), "m"( *pw ):
176  "cc"
177  );
178 
179  return rv;
180 }
181 
182 
183 inline int atomic_decrement( int * pw )
184 {
185  // return --*pw;
186 
187  int rv;
188 
189  __asm__ __volatile__
190  (
191  "sync\n\t"
192  "0:\n\t"
193  "lwarx %1, 0, %2\n\t"
194  "addi %1, %1, -1\n\t"
195  "stwcx. %1, 0, %2\n\t"
196  "bne- 0b\n\t"
197  "isync":
198 
199  "=m"( *pw ), "=&b"( rv ):
200  "r"( pw ), "m"( *pw ):
201  "memory", "cc"
202  );
203 
204  return rv;
205 }
206 
207 /* CW ARM */
208 
209 #elif defined( __GNUC__ ) && ( defined( __arm__ ) )
210 
211 #define REFCOUNT_T int
212 #define REFCOUNT_GET_T int const volatile&
213 
214 inline int atomic_conditional_increment(volatile int* v)
215 {
216  int t;
217  int tmp;
218 
219  __asm__ __volatile__(
220  "1: ldrex %0, [%2] \n"
221  " cmp %0, #0 \n"
222  " beq 2f \n"
223  " add %0, %0, #1 \n"
224  "2: \n"
225  " strex %1, %0, [%2] \n"
226  " cmp %1, #0 \n"
227  " bne 1b \n"
228 
229  : "=&r" (t), "=&r" (tmp)
230  : "r" (v)
231  : "cc", "memory");
232 
233  return t;
234 }
235 
236 
237 inline int atomic_decrement(volatile int* v)
238 {
239  int t;
240  int tmp;
241 
242  __asm__ __volatile__(
243  "1: ldrex %0, [%2] \n"
244  " add %0, %0, #-1 \n"
245  " strex %1, %0, [%2] \n"
246  " cmp %1, #0 \n"
247  " bne 1b \n"
248 
249  : "=&r" (t), "=&r" (tmp)
250  : "r" (v)
251  : "cc", "memory");
252 
253  return t;
254 }
255 
256 
257 
258 /* CW PPC */
259 
260 #elif ( defined( __MWERKS__ ) ) && defined( __POWERPC__ )
261 
262 inline long atomic_conditional_increment( register long * pw )
263 {
264  register int a;
265 
266  asm
267  {
268  loop:
269 
270  lwarx a, 0, pw
271  cmpwi a, 0
272  beq store
273 
274  addi a, a, 1
275 
276  store:
277 
278  stwcx. a, 0, pw
279  bne- loop
280  }
281 
282  return a;
283 }
284 
285 
286 inline long atomic_decrement( register long * pw )
287 {
288  register int a;
289 
290  asm {
291 
292  sync
293 
294  loop:
295 
296  lwarx a, 0, pw
297  addi a, a, -1
298  stwcx. a, 0, pw
299  bne- loop
300 
301  isync
302  }
303 
304  return a;
305 }
306 
307 /* Any Windows (MSVC) */
308 
309 #elif defined( _MSC_VER )
310 
311 // made functions to not pollute namespace..
312 
313 #define REFCOUNT_T long
314 #define REFCOUNT_GET_T long const volatile&
315 
316 long atomic_conditional_increment( register long * pw );
317 long atomic_decrement( register long * pw );
318 
319 #if 0
320 #elif defined( __GNUC__ ) && defined( ARMV6_ENABLED)
321 
322 
323 #endif
324 
325 
326 
327 
328 #else
329 
330 #error This platform cannot use safe refcount, compile with NO_THREADS or implement it.
331 
332 #endif
333 
334 
335 
336 struct SafeRefCount {
337 
338  REFCOUNT_T count;
339 
340 public:
341 
342  // destroy() is called when weak_count_ drops to zero.
343 
344  bool ref() { //true on success
345 
346  return atomic_conditional_increment( &count ) != 0;
347  }
348 
349  int refval() { //true on success
350 
351  return atomic_conditional_increment( &count );
352  }
353 
354  bool unref() { // true if must be disposed of
355 
356  if( atomic_decrement ( &count ) == 0 ) {
357  return true;
358  }
359 
360  return false;
361  }
362 
363  long get() const { // nothrow
364 
365  return static_cast<REFCOUNT_GET_T>( count );
366  }
367 
368  void init(int p_value=1) {
369 
370  count=p_value;
371  };
372 
373 };
374 
375 
376 
377 #endif // no thread safe
378 
379 #endif
Definition: safe_refcount.h:336