| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | /*************************************************************************/ | 
					
						
							|  |  |  | /*  safe_refcount.h                                                      */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							|  |  |  | /*                       This file is part of:                           */ | 
					
						
							|  |  |  | /*                           GODOT ENGINE                                */ | 
					
						
							| 
									
										
										
										
											2017-08-27 14:16:55 +02:00
										 |  |  | /*                      https://godotengine.org                          */ | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | /*************************************************************************/ | 
					
						
							| 
									
										
										
										
											2018-01-01 14:40:08 +01:00
										 |  |  | /* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur.                 */ | 
					
						
							|  |  |  | /* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md)    */ | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* Permission is hereby granted, free of charge, to any person obtaining */ | 
					
						
							|  |  |  | /* a copy of this software and associated documentation files (the       */ | 
					
						
							|  |  |  | /* "Software"), to deal in the Software without restriction, including   */ | 
					
						
							|  |  |  | /* without limitation the rights to use, copy, modify, merge, publish,   */ | 
					
						
							|  |  |  | /* distribute, sublicense, and/or sell copies of the Software, and to    */ | 
					
						
							|  |  |  | /* permit persons to whom the Software is furnished to do so, subject to */ | 
					
						
							|  |  |  | /* the following conditions:                                             */ | 
					
						
							|  |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* The above copyright notice and this permission notice shall be        */ | 
					
						
							|  |  |  | /* included in all copies or substantial portions of the Software.       */ | 
					
						
							|  |  |  | /*                                                                       */ | 
					
						
							|  |  |  | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */ | 
					
						
							|  |  |  | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */ | 
					
						
							|  |  |  | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ | 
					
						
							|  |  |  | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */ | 
					
						
							|  |  |  | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */ | 
					
						
							|  |  |  | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */ | 
					
						
							|  |  |  | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */ | 
					
						
							|  |  |  | /*************************************************************************/ | 
					
						
							| 
									
										
										
										
											2018-01-05 00:50:27 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | #ifndef SAFE_REFCOUNT_H
 | 
					
						
							|  |  |  | #define SAFE_REFCOUNT_H
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "os/mutex.h"
 | 
					
						
							|  |  |  | /* x86/x86_64 GCC */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "platform_config.h"
 | 
					
						
							| 
									
										
										
										
											2017-01-06 10:15:44 -03:00
										 |  |  | #include "typedefs.h"
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-25 00:01:55 +02:00
										 |  |  | // Atomic functions, these are used for multithread safe reference counters!
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #ifdef NO_THREADS
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Bogus implementation unaware of multiprocessing */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <class T> | 
					
						
							|  |  |  | static _ALWAYS_INLINE_ T atomic_conditional_increment(register T *pw) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (*pw == 0) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	(*pw)++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return *pw; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <class T> | 
					
						
							|  |  |  | static _ALWAYS_INLINE_ T atomic_decrement(register T *pw) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	(*pw)--; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return *pw; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <class T> | 
					
						
							|  |  |  | static _ALWAYS_INLINE_ T atomic_increment(register T *pw) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	(*pw)++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return *pw; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <class T, class V> | 
					
						
							|  |  |  | static _ALWAYS_INLINE_ T atomic_sub(register T *pw, register V val) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	(*pw) -= val; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return *pw; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <class T, class V> | 
					
						
							|  |  |  | static _ALWAYS_INLINE_ T atomic_add(register T *pw, register V val) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	(*pw) += val; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return *pw; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <class T, class V> | 
					
						
							|  |  |  | static _ALWAYS_INLINE_ T atomic_exchange_if_greater(register T *pw, register V val) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (val > *pw) | 
					
						
							|  |  |  | 		*pw = val; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return *pw; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #elif defined(__GNUC__)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Implementation for GCC & Clang */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // GCC guarantees atomic intrinsics for sizes of 1, 2, 4 and 8 bytes.
 | 
					
						
							|  |  |  | // Clang states it supports GCC atomic builtins.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <class T> | 
					
						
							|  |  |  | static _ALWAYS_INLINE_ T atomic_conditional_increment(register T *pw) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (true) { | 
					
						
							|  |  |  | 		T tmp = static_cast<T const volatile &>(*pw); | 
					
						
							|  |  |  | 		if (tmp == 0) | 
					
						
							|  |  |  | 			return 0; // if zero, can't add to it anymore
 | 
					
						
							|  |  |  | 		if (__sync_val_compare_and_swap(pw, tmp, tmp + 1) == tmp) | 
					
						
							|  |  |  | 			return tmp + 1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <class T> | 
					
						
							|  |  |  | static _ALWAYS_INLINE_ T atomic_decrement(register T *pw) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return __sync_sub_and_fetch(pw, 1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <class T> | 
					
						
							|  |  |  | static _ALWAYS_INLINE_ T atomic_increment(register T *pw) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return __sync_add_and_fetch(pw, 1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <class T, class V> | 
					
						
							|  |  |  | static _ALWAYS_INLINE_ T atomic_sub(register T *pw, register V val) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return __sync_sub_and_fetch(pw, val); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <class T, class V> | 
					
						
							|  |  |  | static _ALWAYS_INLINE_ T atomic_add(register T *pw, register V val) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return __sync_add_and_fetch(pw, val); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <class T, class V> | 
					
						
							|  |  |  | static _ALWAYS_INLINE_ T atomic_exchange_if_greater(register T *pw, register V val) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (true) { | 
					
						
							|  |  |  | 		T tmp = static_cast<T const volatile &>(*pw); | 
					
						
							|  |  |  | 		if (tmp >= val) | 
					
						
							|  |  |  | 			return tmp; // already greater, or equal
 | 
					
						
							|  |  |  | 		if (__sync_val_compare_and_swap(pw, tmp, val) == tmp) | 
					
						
							|  |  |  | 			return val; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #elif defined(_MSC_VER)
 | 
					
						
							| 
									
										
										
										
											2017-09-26 18:01:24 +02:00
										 |  |  | // For MSVC use a separate compilation unit to prevent windows.h from polluting
 | 
					
						
							|  |  |  | // the global namespace.
 | 
					
						
							|  |  |  | uint32_t atomic_conditional_increment(register uint32_t *pw); | 
					
						
							|  |  |  | uint32_t atomic_decrement(register uint32_t *pw); | 
					
						
							|  |  |  | uint32_t atomic_increment(register uint32_t *pw); | 
					
						
							|  |  |  | uint32_t atomic_sub(register uint32_t *pw, register uint32_t val); | 
					
						
							|  |  |  | uint32_t atomic_add(register uint32_t *pw, register uint32_t val); | 
					
						
							|  |  |  | uint32_t atomic_exchange_if_greater(register uint32_t *pw, register uint32_t val); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | uint64_t atomic_conditional_increment(register uint64_t *pw); | 
					
						
							|  |  |  | uint64_t atomic_decrement(register uint64_t *pw); | 
					
						
							|  |  |  | uint64_t atomic_increment(register uint64_t *pw); | 
					
						
							|  |  |  | uint64_t atomic_sub(register uint64_t *pw, register uint64_t val); | 
					
						
							|  |  |  | uint64_t atomic_add(register uint64_t *pw, register uint64_t val); | 
					
						
							|  |  |  | uint64_t atomic_exchange_if_greater(register uint64_t *pw, register uint64_t val); | 
					
						
							| 
									
										
										
										
											2017-09-25 00:01:55 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | //no threads supported?
 | 
					
						
							|  |  |  | #error Must provide atomic functions for this platform or compiler!
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2017-06-22 05:05:59 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | struct SafeRefCount { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 	uint32_t count; | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  | 	// destroy() is called when weak_count_ drops to zero.
 | 
					
						
							| 
									
										
										
										
											2016-03-09 00:00:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-25 00:01:55 +02:00
										 |  |  | 	_ALWAYS_INLINE_ bool ref() { //true on success
 | 
					
						
							| 
									
										
										
										
											2016-03-09 00:00:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		return atomic_conditional_increment(&count) != 0; | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-25 00:01:55 +02:00
										 |  |  | 	_ALWAYS_INLINE_ uint32_t refval() { //true on success
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		return atomic_conditional_increment(&count); | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-25 00:01:55 +02:00
										 |  |  | 	_ALWAYS_INLINE_ bool unref() { // true if must be disposed of
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		if (atomic_decrement(&count) == 0) { | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 			return true; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-03-09 00:00:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-03-09 00:00:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-25 00:01:55 +02:00
										 |  |  | 	_ALWAYS_INLINE_ uint32_t get() const { // nothrow
 | 
					
						
							| 
									
										
										
										
											2016-03-09 00:00:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-06 10:15:44 -03:00
										 |  |  | 		return count; | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-03-09 00:00:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-25 00:01:55 +02:00
										 |  |  | 	_ALWAYS_INLINE_ void init(uint32_t p_value = 1) { | 
					
						
							| 
									
										
										
										
											2016-03-09 00:00:52 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-03-05 16:44:50 +01:00
										 |  |  | 		count = p_value; | 
					
						
							| 
									
										
										
										
											2017-01-06 10:15:44 -03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-02-09 22:10:30 -03:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-09 00:00:52 +01:00
										 |  |  | #endif
 |