/home/ntakagi/work/STLport-5.1.5/src/lock_free_slist.h

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 1997-1999
00003  * Silicon Graphics Computer Systems, Inc.
00004  *
00005  * Copyright (c) 1999
00006  * Boris Fomitchev
00007  *
00008  * This material is provided "as is", with absolutely no warranty expressed
00009  * or implied. Any use is at your own risk.
00010  *
00011  * Permission to use or copy this software for any purpose is hereby granted
00012  * without fee, provided the above notices are retained on all copies.
00013  * Permission to modify the code and to distribute modified code is granted,
00014  * provided the above notices are retained, and a notice that the code was
00015  * modified is included with the above copyright notice.
00016  *
00017  */
00018 
00019 #ifndef _STLP_LOCK_FREE_SLIST_H
00020 #define _STLP_LOCK_FREE_SLIST_H
00021 
00022 #if defined(_STLP_PTHREADS)
00023 #  include <pthread.h>
00024 
00025 #  if defined (__GNUC__) && defined (__i386__)
00026 
00027 #    define _STLP_HAS_ATOMIC_FREELIST
00028 
00034 class _STLP_atomic_freelist {
00035 public:
00039   struct item {
00040     item* _M_next;
00041   };
00042 
00043   _STLP_atomic_freelist() {
00044     // Statically assert layout of member is as expected by assembly code
00045     _STLP_STATIC_ASSERT(sizeof(_M) == 8)
00046     _M._M_data._M_top       = 0;
00047     _M._M_data._M_sequence  = 0;
00048   }
00049 
00055   void push(item* __item) {
00056     // NOTE: GCC uses ebx as the PIC register for globals in shared libraries.
00057     //       The GCC version I'm using (3.4.1) won't temporarily spill it if it's
00058     //       used as input, output, or clobber.  Instead, it complains with a
00059     //       "can't find a register in class `BREG' while reloading `asm'" error.
00060     //       This is probably a compiler bug, but as the cmpxchg8b instruction
00061     //       requires ebx, I work around this here by using ecx for the '__item'
00062     //       input and spilling ebx into edi.  This also precludes us from using
00063     //       a "m" operand for the cmpxchg8b argument (GCC might think it can make
00064     //       it relative to ebx).  Instead, we're using esi for the address of _M_data.
00065     //
00066     int __tmp1;     // These dummy variables are used to tell GCC that the eax, ecx,
00067     int __tmp2;     // and edx registers will not have the same value as their input.
00068     int __tmp3;     // The optimizer will remove them as their values are not used.
00069     __asm__ __volatile__
00070       ("       movl       %%ebx, %%edi\n\t"
00071        "       movl       %%ecx, %%ebx\n\t"
00072        "L1_%=: movl       %%eax, (%%ebx)\n\t"     // __item._M_next = _M._M_data._M_top
00073        "       leal       1(%%edx),%%ecx\n\t"     // new sequence = _M._M_data._M_sequence + 1
00074        "lock;  cmpxchg8b  (%%esi)\n\t"
00075        "       jne        L1_%=\n\t"              // Failed, retry! (edx:eax now contain most recent _M_sequence:_M_top)
00076        "       movl       %%edi, %%ebx"
00077       :"=a" (__tmp1), "=d" (__tmp2), "=c" (__tmp3)
00078       :"a" (_M._M_data._M_top), "d" (_M._M_data._M_sequence), "c" (__item), "S" (&_M._M_data)
00079       :"edi", "memory", "cc");
00080   }
00081 
00088   item* pop() {
00089     item*   __result;
00090     int     __tmp;
00091     __asm__ __volatile__
00092       ("       movl       %%ebx, %%edi\n\t"
00093        "L1_%=: testl      %%eax, %%eax\n\t"       // _M_top == NULL?
00094        "       je         L2_%=\n\t"              // If yes, we're done
00095        "       movl       (%%eax), %%ebx\n\t"     // new top = _M._M_data._M_top->_M_next
00096        "       leal       1(%%edx),%%ecx\n\t"     // new sequence = _M._M_data._M_sequence + 1
00097        "lock;  cmpxchg8b  (%%esi)\n\t"
00098        "       jne        L1_%=\n\t"              // We failed, retry! (edx:eax now contain most recent _M_sequence:_M_top)
00099        "L2_%=: movl       %%edi, %%ebx"
00100       :"=a" (__result), "=d" (__tmp)
00101       :"a" (_M._M_data._M_top), "d" (_M._M_data._M_sequence), "S" (&_M._M_data)
00102       :"edi", "ecx", "memory", "cc");
00103     return __result;
00104   }
00105 
00113   item* clear() {
00114     item*   __result;
00115     int     __tmp;
00116     __asm__ __volatile__
00117       ("       movl       %%ebx, %%edi\n\t"
00118        "L1_%=: testl      %%eax, %%eax\n\t"       // _M_top == NULL?
00119        "       je         L2_%=\n\t"              // If yes, we're done
00120        "       xorl       %%ebx, %%ebx\n\t"       // We're attempting to set _M_top to NULL
00121        "       leal       1(%%edx),%%ecx\n\t"     // new sequence = _M._M_data._M_sequence + 1
00122        "lock;  cmpxchg8b  (%%esi)\n\t"
00123        "       jne        L1_%=\n\t"              // Failed, retry! (edx:eax now contain most recent _M_sequence:_M_top)
00124        "L2_%=: movl       %%edi, %%ebx"
00125       :"=a" (__result), "=d" (__tmp)
00126       :"a" (_M._M_data._M_top), "d" (_M._M_data._M_sequence), "S" (&_M._M_data)
00127       :"edi", "ecx", "memory", "cc");
00128     return __result;
00129   }
00130 
00131 private:
00132     union {
00133       long long   _M_align;
00134       struct {
00135         item*           _M_top;         // Topmost element in the freelist
00136         unsigned int    _M_sequence;    // Sequence counter to prevent "ABA problem"
00137       } _M_data;
00138     } _M;
00139 
00140   _STLP_atomic_freelist(const _STLP_atomic_freelist&);
00141   _STLP_atomic_freelist& operator=(const _STLP_atomic_freelist&);
00142 };
00143 
00144 #  endif /* if defined(__GNUC__) && defined(__i386__) */
00145 
00146 #elif defined (_STLP_WIN32THREADS)
00147 
00148 #  if !defined (_WIN64)
00149 #    define _STLP_USE_ASM_IMPLEMENTATION
00150 #  endif
00151 
00152 // Here are the compiler/platform requirements for the thread safe and
00153 // lock free singly linked list implementation:
00154 #  if defined (_STLP_USE_ASM_IMPLEMENTATION)
00155 // For the asm version:
00156 #    if defined (_STLP_MSVC) && defined (_M_IX86) && (_M_IX86 >= 500)
00157 #      define _STLP_HAS_ATOMIC_FREELIST
00158 #    endif
00159 #  else
00160 // For the API based version:
00161 #    if defined (_STLP_NEW_PLATFORM_SDK) && (!defined (WINVER) || (WINVER >= 0x0501)) && \
00162                                             (!defined (_WIN32_WINDOWS) || (_WIN32_WINDOWS >= 0x0501))
00163 #      define _STLP_HAS_ATOMIC_FREELIST
00164 #    endif
00165 #  endif
00166 
00167 #  if defined (_STLP_HAS_ATOMIC_FREELIST)
00168 #    if !defined (_STLP_USE_ASM_IMPLEMENTATION)
00169 #      include <windows.h>
00170 #    else
00171 #      if defined (_STLP_MSVC) && (_STLP_MSVC < 1300) || defined (__ICL)
00172 #        pragma warning (push)
00173 #        pragma warning (disable : 4035) //function has no return value
00174 #      endif
00175 #    endif
00176 
00182 class _STLP_atomic_freelist {
00183 public:
00187 #    if defined (_STLP_USE_ASM_IMPLEMENTATION)
00188   struct item {
00189       item*   _M_next;
00190   };
00191 #    else
00192   typedef SLIST_ENTRY item;
00193 #    endif
00194 
00195   _STLP_atomic_freelist() {
00196     // Statically assert layout of member is as expected by assembly code
00197 #    if defined (_STLP_USE_ASM_IMPLEMENTATION)
00198     _STLP_STATIC_ASSERT((sizeof(item) == sizeof(item*)) && (sizeof(_M) == 8))
00199     _M._M_data._M_top       = 0;
00200     _M._M_data._M_sequence  = 0;
00201 #    else
00202     InitializeSListHead(&_M_head);
00203 #    endif
00204   }
00205 
00211   void push(item* __item) {
00212 #    if defined (_STLP_USE_ASM_IMPLEMENTATION)
00213     __asm
00214     {
00215         mov             esi, this
00216         mov             ebx, __item
00217         mov             eax, [esi]              // _M._M_data._M_top
00218         mov             edx, [esi+4]            // _M._M_data._M_sequence
00219     L1: mov             [ebx], eax              // __item._M_next = _M._M_data._M_top
00220         lea             ecx, [edx+1]            // new sequence = _M._M_data._M_sequence + 1
00221         lock cmpxchg8b  qword ptr [esi]
00222         jne             L1                      // Failed, retry! (edx:eax now contain most recent _M_sequence:_M_top)
00223     }
00224 #    else
00225     InterlockedPushEntrySList(&_M_head, __item);
00226 #    endif
00227   }
00228 
00235   item* pop() {
00236 #    if defined (_STLP_USE_ASM_IMPLEMENTATION)
00237     __asm
00238     {
00239         mov             esi, this
00240         mov             eax, [esi]              // _M._M_data._M_top
00241         mov             edx, [esi+4]            // _M._M_data._M_sequence
00242     L1: test            eax, eax                // _M_top == NULL?
00243         je              L2                      // Yes, we're done
00244         mov             ebx, [eax]              // new top = _M._M_data._M_top->_M_next
00245         lea             ecx, [edx+1]            // new sequence = _M._M_data._M_sequence + 1
00246         lock cmpxchg8b  qword ptr [esi]
00247         jne             L1                      // Failed, retry! (edx:eax now contain most recent _M_sequence:_M_top)
00248     L2:
00249     }
00250 #    else
00251     return InterlockedPopEntrySList(&_M_head);
00252 #    endif
00253   }
00254 
00262   item* clear() {
00263 #    if defined (_STLP_USE_ASM_IMPLEMENTATION)
00264     __asm
00265     {
00266         mov             esi, this
00267         mov             eax, [esi]              // _M._M_data._M_top
00268         mov             edx, [esi+4]            // _M._M_data._M_sequence
00269     L1: test            eax, eax                // _M_top == NULL?
00270         je              L2                      // Yes, we're done
00271         xor             ebx,ebx                 // We're attempting to set _M._M_data._M_top to NULL
00272         lea             ecx, [edx+1]            // new sequence = _M._M_data._M_sequence + 1
00273         lock cmpxchg8b  qword ptr [esi]
00274         jne             L1                      // Failed, retry! (edx:eax now contain most recent _M_sequence:_M_top)
00275     L2:
00276     }
00277 #    else
00278     return InterlockedFlushSList(&_M_head);
00279 #    endif
00280   }
00281 
00282 private:
00283 #    if defined (_STLP_USE_ASM_IMPLEMENTATION)
00284   union {
00285     __int64     _M_align;
00286     struct {
00287       item*           _M_top;         // Topmost element in the freelist
00288       unsigned int    _M_sequence;    // Sequence counter to prevent "ABA problem"
00289     } _M_data;
00290   } _M;
00291 #    else
00292   SLIST_HEADER _M_head;
00293 #    endif
00294 
00295   _STLP_atomic_freelist(const _STLP_atomic_freelist&);
00296   _STLP_atomic_freelist& operator = (const _STLP_atomic_freelist&);
00297 };
00298 
00299 #    if defined (_STLP_USE_ASM_IMPLEMENTATION)
00300 #      if defined (_STLP_MSVC) && (_STLP_MSVC < 1300) || defined (__ICL)
00301 #        pragma warning (pop)
00302 #      endif
00303 #    endif
00304 
00305 #  endif /* _STLP_HAS_ATOMIC_FREELIST */
00306 
00307 #endif
00308 
00309 #endif /* _STLP_LOCK_FREE_SLIST_H */



Generated on Mon Mar 10 15:32:17 2008 by  doxygen 1.5.1