summaryrefslogtreecommitdiff
path: root/core/safe_refcount.h
diff options
context:
space:
mode:
Diffstat (limited to 'core/safe_refcount.h')
-rw-r--r--core/safe_refcount.h379
1 files changed, 379 insertions, 0 deletions
diff --git a/core/safe_refcount.h b/core/safe_refcount.h
new file mode 100644
index 0000000000..0ee32c3fe7
--- /dev/null
+++ b/core/safe_refcount.h
@@ -0,0 +1,379 @@
+/*************************************************************************/
+/* safe_refcount.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/*************************************************************************/
+#ifndef SAFE_REFCOUNT_H
+#define SAFE_REFCOUNT_H
+
+#include "os/mutex.h"
+/* x86/x86_64 GCC */
+
+#include "platform_config.h"
+
+
+#ifdef NO_THREADS
+
+struct SafeRefCount {
+
+ int count;
+
+public:
+
+ // destroy() is called when weak_count_ drops to zero.
+
+ bool ref() { //true on success
+
+ if (count==0)
+ return false;
+ count++;
+
+ return true;
+ }
+
+ int refval() { //true on success
+
+ if (count==0)
+ return 0;
+ count++;
+ return count;
+ }
+
+ bool unref() { // true if must be disposed of
+
+ if (count>0)
+ count--;
+
+ return count==0;
+ }
+
+ long get() const { // nothrow
+
+ return static_cast<int const volatile &>( count );
+ }
+
+ void init(int p_value=1) {
+
+ count=p_value;
+ };
+
+};
+
+
+
+
+
+
+
+
+#else
+
+#if defined( PLATFORM_REFCOUNT )
+
+#include "platform_refcount.h"
+
+
+#elif defined( __GNUC__ ) && ( defined( __i386__ ) || defined( __x86_64__ ) )
+
+#define REFCOUNT_T volatile int
+#define REFCOUNT_GET_T int const volatile&
+
+static inline int atomic_conditional_increment( volatile int * pw ) {
+ // int rv = *pw;
+ // if( rv != 0 ) ++*pw;
+ // return rv;
+
+ int rv, tmp;
+
+ __asm__
+ (
+ "movl %0, %%eax\n\t"
+ "0:\n\t"
+ "test %%eax, %%eax\n\t"
+ "je 1f\n\t"
+ "movl %%eax, %2\n\t"
+ "incl %2\n\t"
+ "lock\n\t"
+ "cmpxchgl %2, %0\n\t"
+ "jne 0b\n\t"
+ "1:":
+ "=m"( *pw ), "=&a"( rv ), "=&r"( tmp ): // outputs (%0, %1, %2)
+ "m"( *pw ): // input (%3)
+ "cc" // clobbers
+ );
+
+ return rv;
+}
+
+static inline int atomic_decrement( volatile int *pw) {
+
+ // return --(*pw);
+
+ unsigned char rv;
+
+ __asm__
+ (
+ "lock\n\t"
+ "decl %0\n\t"
+ "setne %1":
+ "=m" (*pw), "=qm" (rv):
+ "m" (*pw):
+ "memory"
+ );
+ return static_cast<int>(rv);
+}
+
+/* PowerPC32/64 GCC */
+
+#elif defined( __GNUC__ ) && ( defined( __powerpc__ ) || defined( __ppc__ ) )
+
+#define REFCOUNT_T int
+#define REFCOUNT_GET_T int const volatile&
+
+inline int atomic_conditional_increment( int * pw )
+{
+ // if( *pw != 0 ) ++*pw;
+ // return *pw;
+
+ int rv;
+
+ __asm__
+ (
+ "0:\n\t"
+ "lwarx %1, 0, %2\n\t"
+ "cmpwi %1, 0\n\t"
+ "beq 1f\n\t"
+ "addi %1, %1, 1\n\t"
+ "1:\n\t"
+ "stwcx. %1, 0, %2\n\t"
+ "bne- 0b":
+
+ "=m"( *pw ), "=&b"( rv ):
+ "r"( pw ), "m"( *pw ):
+ "cc"
+ );
+
+ return rv;
+}
+
+
+inline int atomic_decrement( int * pw )
+{
+ // return --*pw;
+
+ int rv;
+
+ __asm__ __volatile__
+ (
+ "sync\n\t"
+ "0:\n\t"
+ "lwarx %1, 0, %2\n\t"
+ "addi %1, %1, -1\n\t"
+ "stwcx. %1, 0, %2\n\t"
+ "bne- 0b\n\t"
+ "isync":
+
+ "=m"( *pw ), "=&b"( rv ):
+ "r"( pw ), "m"( *pw ):
+ "memory", "cc"
+ );
+
+ return rv;
+}
+
+/* CW ARM */
+
+#elif defined( __GNUC__ ) && ( defined( __arm__ ) )
+
+#define REFCOUNT_T int
+#define REFCOUNT_GET_T int const volatile&
+
+inline int atomic_conditional_increment(volatile int* v)
+{
+ int t;
+ int tmp;
+
+ __asm__ __volatile__(
+ "1: ldrex %0, [%2] \n"
+ " cmp %0, #0 \n"
+ " beq 2f \n"
+ " add %0, %0, #1 \n"
+ "2: \n"
+ " strex %1, %0, [%2] \n"
+ " cmp %1, #0 \n"
+ " bne 1b \n"
+
+ : "=&r" (t), "=&r" (tmp)
+ : "r" (v)
+ : "cc", "memory");
+
+ return t;
+}
+
+
+inline int atomic_decrement(volatile int* v)
+{
+ int t;
+ int tmp;
+
+ __asm__ __volatile__(
+ "1: ldrex %0, [%2] \n"
+ " add %0, %0, #-1 \n"
+ " strex %1, %0, [%2] \n"
+ " cmp %1, #0 \n"
+ " bne 1b \n"
+
+ : "=&r" (t), "=&r" (tmp)
+ : "r" (v)
+ : "cc", "memory");
+
+ return t;
+}
+
+
+
+/* CW PPC */
+
+#elif defined( __MWERKS__ ) && defined( __POWERPC__ )
+
+inline long atomic_conditional_increment( register long * pw )
+{
+ register int a;
+
+ asm
+ {
+ loop:
+
+ lwarx a, 0, pw
+ cmpwi a, 0
+ beq store
+
+ addi a, a, 1
+
+ store:
+
+ stwcx. a, 0, pw
+ bne- loop
+ }
+
+ return a;
+}
+
+
+inline long atomic_decrement( register long * pw )
+{
+ register int a;
+
+ asm {
+
+ sync
+
+ loop:
+
+ lwarx a, 0, pw
+ addi a, a, -1
+ stwcx. a, 0, pw
+ bne- loop
+
+ isync
+ }
+
+ return a;
+}
+
+/* Any Windows (MSVC) */
+
+#elif defined( _MSC_VER )
+
+// made functions to not pollute namespace..
+
+#define REFCOUNT_T long
+#define REFCOUNT_GET_T long const volatile&
+
+long atomic_conditional_increment( register long * pw );
+long atomic_decrement( register long * pw );
+
+#if 0
+#elif defined( __GNUC__ ) && defined( ARMV6_ENABLED)
+
+
+#endif
+
+
+
+
+#else
+
+#error This platform cannot use safe refcount, compile with NO_THREADS or implement it.
+
+#endif
+
+
+
+struct SafeRefCount {
+
+ REFCOUNT_T count;
+
+public:
+
+ // destroy() is called when weak_count_ drops to zero.
+
+ bool ref() { //true on success
+
+ return atomic_conditional_increment( &count ) != 0;
+ }
+
+ int refval() { //true on success
+
+ return atomic_conditional_increment( &count );
+ }
+
+ bool unref() { // true if must be disposed of
+
+ if( atomic_decrement ( &count ) == 0 ) {
+ return true;
+ }
+
+ return false;
+ }
+
+ long get() const { // nothrow
+
+ return static_cast<REFCOUNT_GET_T>( count );
+ }
+
+ void init(int p_value=1) {
+
+ count=p_value;
+ };
+
+};
+
+
+
+#endif // no thread safe
+
+#endif