safe_refcount.h 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  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-2014 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. #include "os/mutex.h"
  32. /* x86/x86_64 GCC */
  33. #include "platform_config.h"
  34. #ifdef NO_THREADS
  35. struct SafeRefCount {
  36. int count;
  37. public:
  38. // destroy() is called when weak_count_ drops to zero.
  39. bool ref() { //true on success
  40. if (count==0)
  41. return false;
  42. count++;
  43. return true;
  44. }
  45. int refval() { //true on success
  46. if (count==0)
  47. return 0;
  48. count++;
  49. return count;
  50. }
  51. bool unref() { // true if must be disposed of
  52. if (count>0)
  53. count--;
  54. return count==0;
  55. }
  56. long get() const { // nothrow
  57. return static_cast<int const volatile &>( count );
  58. }
  59. void init(int p_value=1) {
  60. count=p_value;
  61. };
  62. };
  63. #else
  64. #if defined( PLATFORM_REFCOUNT )
  65. #include "platform_refcount.h"
  66. #elif defined( __GNUC__ ) && ( defined( __i386__ ) || defined( __x86_64__ ) )
  67. #define REFCOUNT_T volatile int
  68. #define REFCOUNT_GET_T int const volatile&
  69. static inline int atomic_conditional_increment( volatile int * pw ) {
  70. // int rv = *pw;
  71. // if( rv != 0 ) ++*pw;
  72. // return rv;
  73. int rv, tmp;
  74. __asm__
  75. (
  76. "movl %0, %%eax\n\t"
  77. "0:\n\t"
  78. "test %%eax, %%eax\n\t"
  79. "je 1f\n\t"
  80. "movl %%eax, %2\n\t"
  81. "incl %2\n\t"
  82. "lock\n\t"
  83. "cmpxchgl %2, %0\n\t"
  84. "jne 0b\n\t"
  85. "1:":
  86. "=m"( *pw ), "=&a"( rv ), "=&r"( tmp ): // outputs (%0, %1, %2)
  87. "m"( *pw ): // input (%3)
  88. "cc" // clobbers
  89. );
  90. return rv;
  91. }
  92. static inline int atomic_decrement( volatile int *pw) {
  93. // return --(*pw);
  94. unsigned char rv;
  95. __asm__
  96. (
  97. "lock\n\t"
  98. "decl %0\n\t"
  99. "setne %1":
  100. "=m" (*pw), "=qm" (rv):
  101. "m" (*pw):
  102. "memory"
  103. );
  104. return static_cast<int>(rv);
  105. }
  106. /* PowerPC32/64 GCC */
  107. #elif ( defined( __GNUC__ ) ) && ( defined( __powerpc__ ) || defined( __ppc__ ) )
  108. #define REFCOUNT_T int
  109. #define REFCOUNT_GET_T int const volatile&
  110. inline int atomic_conditional_increment( int * pw )
  111. {
  112. // if( *pw != 0 ) ++*pw;
  113. // return *pw;
  114. int rv;
  115. __asm__
  116. (
  117. "0:\n\t"
  118. "lwarx %1, 0, %2\n\t"
  119. "cmpwi %1, 0\n\t"
  120. "beq 1f\n\t"
  121. "addi %1, %1, 1\n\t"
  122. "1:\n\t"
  123. "stwcx. %1, 0, %2\n\t"
  124. "bne- 0b":
  125. "=m"( *pw ), "=&b"( rv ):
  126. "r"( pw ), "m"( *pw ):
  127. "cc"
  128. );
  129. return rv;
  130. }
  131. inline int atomic_decrement( int * pw )
  132. {
  133. // return --*pw;
  134. int rv;
  135. __asm__ __volatile__
  136. (
  137. "sync\n\t"
  138. "0:\n\t"
  139. "lwarx %1, 0, %2\n\t"
  140. "addi %1, %1, -1\n\t"
  141. "stwcx. %1, 0, %2\n\t"
  142. "bne- 0b\n\t"
  143. "isync":
  144. "=m"( *pw ), "=&b"( rv ):
  145. "r"( pw ), "m"( *pw ):
  146. "memory", "cc"
  147. );
  148. return rv;
  149. }
  150. /* CW ARM */
  151. #elif defined( __GNUC__ ) && ( defined( __arm__ ) )
  152. #define REFCOUNT_T int
  153. #define REFCOUNT_GET_T int const volatile&
  154. inline int atomic_conditional_increment(volatile int* v)
  155. {
  156. int t;
  157. int tmp;
  158. __asm__ __volatile__(
  159. "1: ldrex %0, [%2] \n"
  160. " cmp %0, #0 \n"
  161. " beq 2f \n"
  162. " add %0, %0, #1 \n"
  163. "2: \n"
  164. " strex %1, %0, [%2] \n"
  165. " cmp %1, #0 \n"
  166. " bne 1b \n"
  167. : "=&r" (t), "=&r" (tmp)
  168. : "r" (v)
  169. : "cc", "memory");
  170. return t;
  171. }
  172. inline int atomic_decrement(volatile int* v)
  173. {
  174. int t;
  175. int tmp;
  176. __asm__ __volatile__(
  177. "1: ldrex %0, [%2] \n"
  178. " add %0, %0, #-1 \n"
  179. " strex %1, %0, [%2] \n"
  180. " cmp %1, #0 \n"
  181. " bne 1b \n"
  182. : "=&r" (t), "=&r" (tmp)
  183. : "r" (v)
  184. : "cc", "memory");
  185. return t;
  186. }
  187. /* CW PPC */
  188. #elif ( defined( __MWERKS__ ) ) && defined( __POWERPC__ )
  189. inline long atomic_conditional_increment( register long * pw )
  190. {
  191. register int a;
  192. asm
  193. {
  194. loop:
  195. lwarx a, 0, pw
  196. cmpwi a, 0
  197. beq store
  198. addi a, a, 1
  199. store:
  200. stwcx. a, 0, pw
  201. bne- loop
  202. }
  203. return a;
  204. }
  205. inline long atomic_decrement( register long * pw )
  206. {
  207. register int a;
  208. asm {
  209. sync
  210. loop:
  211. lwarx a, 0, pw
  212. addi a, a, -1
  213. stwcx. a, 0, pw
  214. bne- loop
  215. isync
  216. }
  217. return a;
  218. }
  219. /* Any Windows (MSVC) */
  220. #elif defined( _MSC_VER )
  221. // made functions to not pollute namespace..
  222. #define REFCOUNT_T long
  223. #define REFCOUNT_GET_T long const volatile&
  224. long atomic_conditional_increment( register long * pw );
  225. long atomic_decrement( register long * pw );
  226. #if 0
  227. #elif defined( __GNUC__ ) && defined( ARMV6_ENABLED)
  228. #endif
  229. #else
  230. #error This platform cannot use safe refcount, compile with NO_THREADS or implement it.
  231. #endif
  232. struct SafeRefCount {
  233. REFCOUNT_T count;
  234. public:
  235. // destroy() is called when weak_count_ drops to zero.
  236. bool ref() { //true on success
  237. return atomic_conditional_increment( &count ) != 0;
  238. }
  239. int refval() { //true on success
  240. return atomic_conditional_increment( &count );
  241. }
  242. bool unref() { // true if must be disposed of
  243. if( atomic_decrement ( &count ) == 0 ) {
  244. return true;
  245. }
  246. return false;
  247. }
  248. long get() const { // nothrow
  249. return static_cast<REFCOUNT_GET_T>( count );
  250. }
  251. void init(int p_value=1) {
  252. count=p_value;
  253. };
  254. };
  255. #endif // no thread safe
  256. #endif