/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
- /*
- * Copyright (c) 1997-1999
- * Silicon Graphics Computer Systems, Inc.
- *
- * Copyright (c) 1999
- * Boris Fomitchev
- *
- * This material is provided "as is", with absolutely no warranty expressed
- * or implied. Any use is at your own risk.
- *
- * Permission to use or copy this software for any purpose is hereby granted
- * without fee, provided the above notices are retained on all copies.
- * Permission to modify the code and to distribute modified code is granted,
- * provided the above notices are retained, and a notice that the code was
- * modified is included with the above copyright notice.
- *
- */
- #ifndef _STLP_LOCK_FREE_SLIST_H
- #define _STLP_LOCK_FREE_SLIST_H
- #if defined(_STLP_PTHREADS)
- # include <pthread.h>
- # if defined (__GNUC__) && defined (__i386__)
- # define _STLP_HAS_ATOMIC_FREELIST
- /**
- * Class that implements a non-blocking and thread-safe freelist.
- * It is used for the lock-free node allocation engine.
- *
- * @author felixw@inin.com
- */
- class _STLP_atomic_freelist {
- public:
- /**
- * Type representing items of the freelist
- */
- struct item {
- item* _M_next;
- };
- _STLP_atomic_freelist() {
- // Statically assert layout of member is as expected by assembly code
- _STLP_STATIC_ASSERT(sizeof(_M) == 8)
- _M._M_data._M_top = 0;
- _M._M_data._M_sequence = 0;
- }
- /**
- * Atomically pushes the specified item onto the freelist.
- *
- * @param __item [in] Item to add to the front of the list
- */
- void push(item* __item) {
- // NOTE: GCC uses ebx as the PIC register for globals in shared libraries.
- // The GCC version I'm using (3.4.1) won't temporarily spill it if it's
- // used as input, output, or clobber. Instead, it complains with a
- // "can't find a register in class `BREG' while reloading `asm'" error.
- // This is probably a compiler bug, but as the cmpxchg8b instruction
- // requires ebx, I work around this here by using ecx for the '__item'
- // input and spilling ebx into edi. This also precludes us from using
- // a "m" operand for the cmpxchg8b argument (GCC might think it can make
- // it relative to ebx). Instead, we're using esi for the address of _M_data.
- //
- int __tmp1; // These dummy variables are used to tell GCC that the eax, ecx,
- int __tmp2; // and edx registers will not have the same value as their input.
- int __tmp3; // The optimizer will remove them as their values are not used.
- __asm__ __volatile__
- (" movl %%ebx, %%edi\n\t"
- " movl %%ecx, %%ebx\n\t"
- "L1_%=: movl %%eax, (%%ebx)\n\t" // __item._M_next = _M._M_data._M_top
- " leal 1(%%edx),%%ecx\n\t" // new sequence = _M._M_data._M_sequence + 1
- "lock; cmpxchg8b (%%esi)\n\t"
- " jne L1_%=\n\t" // Failed, retry! (edx:eax now contain most recent _M_sequence:_M_top)
- " movl %%edi, %%ebx"
- :"=a" (__tmp1), "=d" (__tmp2), "=c" (__tmp3)
- :"a" (_M._M_data._M_top), "d" (_M._M_data._M_sequence), "c" (__item), "S" (&_M._M_data)
- :"edi", "memory", "cc");
- }
- /**
- * Atomically removes the topmost item from the freelist and returns a
- * pointer to it. Returns NULL if the list is empty.
- *
- * @return Item that was removed from front of list; NULL if list empty
- */
- item* pop() {
- item* __result;
- int __tmp;
- __asm__ __volatile__
- (" movl %%ebx, %%edi\n\t"
- "L1_%=: testl %%eax, %%eax\n\t" // _M_top == NULL?
- " je L2_%=\n\t" // If yes, we're done
- " movl (%%eax), %%ebx\n\t" // new top = _M._M_data._M_top->_M_next
- " leal 1(%%edx),%%ecx\n\t" // new sequence = _M._M_data._M_sequence + 1
- "lock; cmpxchg8b (%%esi)\n\t"
- " jne L1_%=\n\t" // We failed, retry! (edx:eax now contain most recent _M_sequence:_M_top)
- "L2_%=: movl %%edi, %%ebx"
- :"=a" (__result), "=d" (__tmp)
- :"a" (_M._M_data._M_top), "d" (_M._M_data._M_sequence), "S" (&_M._M_data)
- :"edi", "ecx", "memory", "cc");
- return __result;
- }
- /**
- * Atomically detaches all items from the list and returns a pointer to the
- * topmost item. The items are still chained and may be traversed safely as
- * they're now "owned" by the calling thread.
- *
- * @return Pointer to topmost item in the list; NULL if list empty
- */
- item* clear() {
- item* __result;
- int __tmp;
- __asm__ __volatile__
- (" movl %%ebx, %%edi\n\t"
- "L1_%=: testl %%eax, %%eax\n\t" // _M_top == NULL?
- " je L2_%=\n\t" // If yes, we're done
- " xorl %%ebx, %%ebx\n\t" // We're attempting to set _M_top to NULL
- " leal 1(%%edx),%%ecx\n\t" // new sequence = _M._M_data._M_sequence + 1
- "lock; cmpxchg8b (%%esi)\n\t"
- " jne L1_%=\n\t" // Failed, retry! (edx:eax now contain most recent _M_sequence:_M_top)
- "L2_%=: movl %%edi, %%ebx"
- :"=a" (__result), "=d" (__tmp)
- :"a" (_M._M_data._M_top), "d" (_M._M_data._M_sequence), "S" (&_M._M_data)
- :"edi", "ecx", "memory", "cc");
- return __result;
- }
- private:
- union {
- long long _M_align;
- struct {
- item* _M_top; // Topmost element in the freelist
- unsigned int _M_sequence; // Sequence counter to prevent "ABA problem"
- } _M_data;
- } _M;
- _STLP_atomic_freelist(const _STLP_atomic_freelist&);
- _STLP_atomic_freelist& operator=(const _STLP_atomic_freelist&);
- };
- # endif /* if defined(__GNUC__) && defined(__i386__) */
- #elif defined (_STLP_WIN32THREADS)
- # if !defined (_WIN64)
- # define _STLP_USE_ASM_IMPLEMENTATION
- # endif
- // Here are the compiler/platform requirements for the thread safe and
- // lock free singly linked list implementation:
- # if defined (_STLP_USE_ASM_IMPLEMENTATION)
- // For the asm version:
- # if defined (_STLP_MSVC) && defined (_M_IX86) && (_M_IX86 >= 500)
- # define _STLP_HAS_ATOMIC_FREELIST
- # endif
- # else
- // For the API based version:
- # if defined (_STLP_NEW_PLATFORM_SDK) && (!defined (WINVER) || (WINVER >= 0x0501)) && \
- (!defined (_WIN32_WINDOWS) || (_WIN32_WINDOWS >= 0x0501))
- # define _STLP_HAS_ATOMIC_FREELIST
- # endif
- # endif
- # if defined (_STLP_HAS_ATOMIC_FREELIST)
- # if !defined (_STLP_USE_ASM_IMPLEMENTATION)
- # include <windows.h>
- # else
- # if defined (_STLP_MSVC) && (_STLP_MSVC < 1300) || defined (__ICL)
- # pragma warning (push)
- # pragma warning (disable : 4035) //function has no return value
- # endif
- # endif
- /**
- * Class that implements a non-blocking and thread-safe freelist.
- * It is used for the lock-free node allocation engine.
- *
- * @author felixw@inin.com
- */
- class _STLP_atomic_freelist {
- public:
- /**
- * Type representing items of the freelist
- */
- # if defined (_STLP_USE_ASM_IMPLEMENTATION)
- struct item {
- item* _M_next;
- };
- # else
- typedef SLIST_ENTRY item;
- # endif
- _STLP_atomic_freelist() {
- // Statically assert layout of member is as expected by assembly code
- # if defined (_STLP_USE_ASM_IMPLEMENTATION)
- _STLP_STATIC_ASSERT((sizeof(item) == sizeof(item*)) && (sizeof(_M) == 8))
- _M._M_data._M_top = 0;
- _M._M_data._M_sequence = 0;
- # else
- InitializeSListHead(&_M_head);
- # endif
- }
- /**
- * Atomically pushes the specified item onto the freelist.
- *
- * @param __item [in] Item to add to the front of the list
- */
- void push(item* __item) {
- # if defined (_STLP_USE_ASM_IMPLEMENTATION)
- __asm
- {
- mov esi, this
- mov ebx, __item
- mov eax, [esi] // _M._M_data._M_top
- mov edx, [esi+4] // _M._M_data._M_sequence
- L1: mov [ebx], eax // __item._M_next = _M._M_data._M_top
- lea ecx, [edx+1] // new sequence = _M._M_data._M_sequence + 1
- lock cmpxchg8b qword ptr [esi]
- jne L1 // Failed, retry! (edx:eax now contain most recent _M_sequence:_M_top)
- }
- # else
- InterlockedPushEntrySList(&_M_head, __item);
- # endif
- }
- /**
- * Atomically removes the topmost item from the freelist and returns a
- * pointer to it. Returns NULL if the list is empty.
- *
- * @return Item that was removed from front of list; NULL if list empty
- */
- item* pop() {
- # if defined (_STLP_USE_ASM_IMPLEMENTATION)
- __asm
- {
- mov esi, this
- mov eax, [esi] // _M._M_data._M_top
- mov edx, [esi+4] // _M._M_data._M_sequence
- L1: test eax, eax // _M_top == NULL?
- je L2 // Yes, we're done
- mov ebx, [eax] // new top = _M._M_data._M_top->_M_next
- lea ecx, [edx+1] // new sequence = _M._M_data._M_sequence + 1
- lock cmpxchg8b qword ptr [esi]
- jne L1 // Failed, retry! (edx:eax now contain most recent _M_sequence:_M_top)
- L2:
- }
- # else
- return InterlockedPopEntrySList(&_M_head);
- # endif
- }
- /**
- * Atomically detaches all items from the list and returns pointer to the
- * topmost. The items are still chained and may be traversed safely as
- * they're now "owned" by the calling thread.
- *
- * @return Pointer to topmost item in the list; NULL if list empty
- */
- item* clear() {
- # if defined (_STLP_USE_ASM_IMPLEMENTATION)
- __asm
- {
- mov esi, this
- mov eax, [esi] // _M._M_data._M_top
- mov edx, [esi+4] // _M._M_data._M_sequence
- L1: test eax, eax // _M_top == NULL?
- je L2 // Yes, we're done
- xor ebx,ebx // We're attempting to set _M._M_data._M_top to NULL
- lea ecx, [edx+1] // new sequence = _M._M_data._M_sequence + 1
- lock cmpxchg8b qword ptr [esi]
- jne L1 // Failed, retry! (edx:eax now contain most recent _M_sequence:_M_top)
- L2:
- }
- # else
- return InterlockedFlushSList(&_M_head);
- # endif
- }
- private:
- # if defined (_STLP_USE_ASM_IMPLEMENTATION)
- union {
- __int64 _M_align;
- struct {
- item* _M_top; // Topmost element in the freelist
- unsigned int _M_sequence; // Sequence counter to prevent "ABA problem"
- } _M_data;
- } _M;
- # else
- SLIST_HEADER _M_head;
- # endif
- _STLP_atomic_freelist(const _STLP_atomic_freelist&);
- _STLP_atomic_freelist& operator = (const _STLP_atomic_freelist&);
- };
- # if defined (_STLP_USE_ASM_IMPLEMENTATION)
- # if defined (_STLP_MSVC) && (_STLP_MSVC < 1300) || defined (__ICL)
- # pragma warning (pop)
- # endif
- # endif
- # endif /* _STLP_HAS_ATOMIC_FREELIST */
- #endif
- #endif /* _STLP_LOCK_FREE_SLIST_H */