/home/ntakagi/work/STLport-5.1.5/src/lock_free_slist.hGo 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 ![]() |