/project/jni/stlport/src/lock_free_slist.h

https://github.com/aichunyu/FFPlayer · C Header · 309 lines · 197 code · 25 blank · 87 comment · 31 complexity · 0aa7aa5268f5b6797de48a55e9765fe5 MD5 · raw file

  1. /*
  2. * Copyright (c) 1997-1999
  3. * Silicon Graphics Computer Systems, Inc.
  4. *
  5. * Copyright (c) 1999
  6. * Boris Fomitchev
  7. *
  8. * This material is provided "as is", with absolutely no warranty expressed
  9. * or implied. Any use is at your own risk.
  10. *
  11. * Permission to use or copy this software for any purpose is hereby granted
  12. * without fee, provided the above notices are retained on all copies.
  13. * Permission to modify the code and to distribute modified code is granted,
  14. * provided the above notices are retained, and a notice that the code was
  15. * modified is included with the above copyright notice.
  16. *
  17. */
  18. #ifndef _STLP_LOCK_FREE_SLIST_H
  19. #define _STLP_LOCK_FREE_SLIST_H
  20. #if defined(_STLP_PTHREADS)
  21. # include <pthread.h>
  22. # if defined (__GNUC__) && defined (__i386__)
  23. # define _STLP_HAS_ATOMIC_FREELIST
  24. /**
  25. * Class that implements a non-blocking and thread-safe freelist.
  26. * It is used for the lock-free node allocation engine.
  27. *
  28. * @author felixw@inin.com
  29. */
  30. class _STLP_atomic_freelist {
  31. public:
  32. /**
  33. * Type representing items of the freelist
  34. */
  35. struct item {
  36. item* _M_next;
  37. };
  38. _STLP_atomic_freelist() {
  39. // Statically assert layout of member is as expected by assembly code
  40. _STLP_STATIC_ASSERT(sizeof(_M) == 8)
  41. _M._M_data._M_top = 0;
  42. _M._M_data._M_sequence = 0;
  43. }
  44. /**
  45. * Atomically pushes the specified item onto the freelist.
  46. *
  47. * @param __item [in] Item to add to the front of the list
  48. */
  49. void push(item* __item) {
  50. // NOTE: GCC uses ebx as the PIC register for globals in shared libraries.
  51. // The GCC version I'm using (3.4.1) won't temporarily spill it if it's
  52. // used as input, output, or clobber. Instead, it complains with a
  53. // "can't find a register in class `BREG' while reloading `asm'" error.
  54. // This is probably a compiler bug, but as the cmpxchg8b instruction
  55. // requires ebx, I work around this here by using ecx for the '__item'
  56. // input and spilling ebx into edi. This also precludes us from using
  57. // a "m" operand for the cmpxchg8b argument (GCC might think it can make
  58. // it relative to ebx). Instead, we're using esi for the address of _M_data.
  59. //
  60. int __tmp1; // These dummy variables are used to tell GCC that the eax, ecx,
  61. int __tmp2; // and edx registers will not have the same value as their input.
  62. int __tmp3; // The optimizer will remove them as their values are not used.
  63. __asm__ __volatile__
  64. (" movl %%ebx, %%edi\n\t"
  65. " movl %%ecx, %%ebx\n\t"
  66. "L1_%=: movl %%eax, (%%ebx)\n\t" // __item._M_next = _M._M_data._M_top
  67. " leal 1(%%edx),%%ecx\n\t" // new sequence = _M._M_data._M_sequence + 1
  68. "lock; cmpxchg8b (%%esi)\n\t"
  69. " jne L1_%=\n\t" // Failed, retry! (edx:eax now contain most recent _M_sequence:_M_top)
  70. " movl %%edi, %%ebx"
  71. :"=a" (__tmp1), "=d" (__tmp2), "=c" (__tmp3)
  72. :"a" (_M._M_data._M_top), "d" (_M._M_data._M_sequence), "c" (__item), "S" (&_M._M_data)
  73. :"edi", "memory", "cc");
  74. }
  75. /**
  76. * Atomically removes the topmost item from the freelist and returns a
  77. * pointer to it. Returns NULL if the list is empty.
  78. *
  79. * @return Item that was removed from front of list; NULL if list empty
  80. */
  81. item* pop() {
  82. item* __result;
  83. int __tmp;
  84. __asm__ __volatile__
  85. (" movl %%ebx, %%edi\n\t"
  86. "L1_%=: testl %%eax, %%eax\n\t" // _M_top == NULL?
  87. " je L2_%=\n\t" // If yes, we're done
  88. " movl (%%eax), %%ebx\n\t" // new top = _M._M_data._M_top->_M_next
  89. " leal 1(%%edx),%%ecx\n\t" // new sequence = _M._M_data._M_sequence + 1
  90. "lock; cmpxchg8b (%%esi)\n\t"
  91. " jne L1_%=\n\t" // We failed, retry! (edx:eax now contain most recent _M_sequence:_M_top)
  92. "L2_%=: movl %%edi, %%ebx"
  93. :"=a" (__result), "=d" (__tmp)
  94. :"a" (_M._M_data._M_top), "d" (_M._M_data._M_sequence), "S" (&_M._M_data)
  95. :"edi", "ecx", "memory", "cc");
  96. return __result;
  97. }
  98. /**
  99. * Atomically detaches all items from the list and returns a pointer to the
  100. * topmost item. The items are still chained and may be traversed safely as
  101. * they're now "owned" by the calling thread.
  102. *
  103. * @return Pointer to topmost item in the list; NULL if list empty
  104. */
  105. item* clear() {
  106. item* __result;
  107. int __tmp;
  108. __asm__ __volatile__
  109. (" movl %%ebx, %%edi\n\t"
  110. "L1_%=: testl %%eax, %%eax\n\t" // _M_top == NULL?
  111. " je L2_%=\n\t" // If yes, we're done
  112. " xorl %%ebx, %%ebx\n\t" // We're attempting to set _M_top to NULL
  113. " leal 1(%%edx),%%ecx\n\t" // new sequence = _M._M_data._M_sequence + 1
  114. "lock; cmpxchg8b (%%esi)\n\t"
  115. " jne L1_%=\n\t" // Failed, retry! (edx:eax now contain most recent _M_sequence:_M_top)
  116. "L2_%=: movl %%edi, %%ebx"
  117. :"=a" (__result), "=d" (__tmp)
  118. :"a" (_M._M_data._M_top), "d" (_M._M_data._M_sequence), "S" (&_M._M_data)
  119. :"edi", "ecx", "memory", "cc");
  120. return __result;
  121. }
  122. private:
  123. union {
  124. long long _M_align;
  125. struct {
  126. item* _M_top; // Topmost element in the freelist
  127. unsigned int _M_sequence; // Sequence counter to prevent "ABA problem"
  128. } _M_data;
  129. } _M;
  130. _STLP_atomic_freelist(const _STLP_atomic_freelist&);
  131. _STLP_atomic_freelist& operator=(const _STLP_atomic_freelist&);
  132. };
  133. # endif /* if defined(__GNUC__) && defined(__i386__) */
  134. #elif defined (_STLP_WIN32THREADS)
  135. # if !defined (_WIN64)
  136. # define _STLP_USE_ASM_IMPLEMENTATION
  137. # endif
  138. // Here are the compiler/platform requirements for the thread safe and
  139. // lock free singly linked list implementation:
  140. # if defined (_STLP_USE_ASM_IMPLEMENTATION)
  141. // For the asm version:
  142. # if defined (_STLP_MSVC) && defined (_M_IX86) && (_M_IX86 >= 500)
  143. # define _STLP_HAS_ATOMIC_FREELIST
  144. # endif
  145. # else
  146. // For the API based version:
  147. # if defined (_STLP_NEW_PLATFORM_SDK) && (!defined (WINVER) || (WINVER >= 0x0501)) && \
  148. (!defined (_WIN32_WINDOWS) || (_WIN32_WINDOWS >= 0x0501))
  149. # define _STLP_HAS_ATOMIC_FREELIST
  150. # endif
  151. # endif
  152. # if defined (_STLP_HAS_ATOMIC_FREELIST)
  153. # if !defined (_STLP_USE_ASM_IMPLEMENTATION)
  154. # include <windows.h>
  155. # else
  156. # if defined (_STLP_MSVC) && (_STLP_MSVC < 1300) || defined (__ICL)
  157. # pragma warning (push)
  158. # pragma warning (disable : 4035) //function has no return value
  159. # endif
  160. # endif
  161. /**
  162. * Class that implements a non-blocking and thread-safe freelist.
  163. * It is used for the lock-free node allocation engine.
  164. *
  165. * @author felixw@inin.com
  166. */
  167. class _STLP_atomic_freelist {
  168. public:
  169. /**
  170. * Type representing items of the freelist
  171. */
  172. # if defined (_STLP_USE_ASM_IMPLEMENTATION)
  173. struct item {
  174. item* _M_next;
  175. };
  176. # else
  177. typedef SLIST_ENTRY item;
  178. # endif
  179. _STLP_atomic_freelist() {
  180. // Statically assert layout of member is as expected by assembly code
  181. # if defined (_STLP_USE_ASM_IMPLEMENTATION)
  182. _STLP_STATIC_ASSERT((sizeof(item) == sizeof(item*)) && (sizeof(_M) == 8))
  183. _M._M_data._M_top = 0;
  184. _M._M_data._M_sequence = 0;
  185. # else
  186. InitializeSListHead(&_M_head);
  187. # endif
  188. }
  189. /**
  190. * Atomically pushes the specified item onto the freelist.
  191. *
  192. * @param __item [in] Item to add to the front of the list
  193. */
  194. void push(item* __item) {
  195. # if defined (_STLP_USE_ASM_IMPLEMENTATION)
  196. __asm
  197. {
  198. mov esi, this
  199. mov ebx, __item
  200. mov eax, [esi] // _M._M_data._M_top
  201. mov edx, [esi+4] // _M._M_data._M_sequence
  202. L1: mov [ebx], eax // __item._M_next = _M._M_data._M_top
  203. lea ecx, [edx+1] // new sequence = _M._M_data._M_sequence + 1
  204. lock cmpxchg8b qword ptr [esi]
  205. jne L1 // Failed, retry! (edx:eax now contain most recent _M_sequence:_M_top)
  206. }
  207. # else
  208. InterlockedPushEntrySList(&_M_head, __item);
  209. # endif
  210. }
  211. /**
  212. * Atomically removes the topmost item from the freelist and returns a
  213. * pointer to it. Returns NULL if the list is empty.
  214. *
  215. * @return Item that was removed from front of list; NULL if list empty
  216. */
  217. item* pop() {
  218. # if defined (_STLP_USE_ASM_IMPLEMENTATION)
  219. __asm
  220. {
  221. mov esi, this
  222. mov eax, [esi] // _M._M_data._M_top
  223. mov edx, [esi+4] // _M._M_data._M_sequence
  224. L1: test eax, eax // _M_top == NULL?
  225. je L2 // Yes, we're done
  226. mov ebx, [eax] // new top = _M._M_data._M_top->_M_next
  227. lea ecx, [edx+1] // new sequence = _M._M_data._M_sequence + 1
  228. lock cmpxchg8b qword ptr [esi]
  229. jne L1 // Failed, retry! (edx:eax now contain most recent _M_sequence:_M_top)
  230. L2:
  231. }
  232. # else
  233. return InterlockedPopEntrySList(&_M_head);
  234. # endif
  235. }
  236. /**
  237. * Atomically detaches all items from the list and returns pointer to the
  238. * topmost. The items are still chained and may be traversed safely as
  239. * they're now "owned" by the calling thread.
  240. *
  241. * @return Pointer to topmost item in the list; NULL if list empty
  242. */
  243. item* clear() {
  244. # if defined (_STLP_USE_ASM_IMPLEMENTATION)
  245. __asm
  246. {
  247. mov esi, this
  248. mov eax, [esi] // _M._M_data._M_top
  249. mov edx, [esi+4] // _M._M_data._M_sequence
  250. L1: test eax, eax // _M_top == NULL?
  251. je L2 // Yes, we're done
  252. xor ebx,ebx // We're attempting to set _M._M_data._M_top to NULL
  253. lea ecx, [edx+1] // new sequence = _M._M_data._M_sequence + 1
  254. lock cmpxchg8b qword ptr [esi]
  255. jne L1 // Failed, retry! (edx:eax now contain most recent _M_sequence:_M_top)
  256. L2:
  257. }
  258. # else
  259. return InterlockedFlushSList(&_M_head);
  260. # endif
  261. }
  262. private:
  263. # if defined (_STLP_USE_ASM_IMPLEMENTATION)
  264. union {
  265. __int64 _M_align;
  266. struct {
  267. item* _M_top; // Topmost element in the freelist
  268. unsigned int _M_sequence; // Sequence counter to prevent "ABA problem"
  269. } _M_data;
  270. } _M;
  271. # else
  272. SLIST_HEADER _M_head;
  273. # endif
  274. _STLP_atomic_freelist(const _STLP_atomic_freelist&);
  275. _STLP_atomic_freelist& operator = (const _STLP_atomic_freelist&);
  276. };
  277. # if defined (_STLP_USE_ASM_IMPLEMENTATION)
  278. # if defined (_STLP_MSVC) && (_STLP_MSVC < 1300) || defined (__ICL)
  279. # pragma warning (pop)
  280. # endif
  281. # endif
  282. # endif /* _STLP_HAS_ATOMIC_FREELIST */
  283. #endif
  284. #endif /* _STLP_LOCK_FREE_SLIST_H */