123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307 |
- /*
- * 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_WINNT) || (_WIN32_WINNT >= 0x0501))
- # define _STLP_HAS_ATOMIC_FREELIST
- # endif
- # endif
- # if defined (_STLP_HAS_ATOMIC_FREELIST)
- # if defined (_STLP_USE_ASM_IMPLEMENTATION)
- # 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 */
|