Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenlock_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_WINNT) || (_WIN32_WINNT >= 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 # if defined (_STLP_MSVC) && (_STLP_MSVC < 1300) || defined (__ICL) 00170 # pragma warning (push) 00171 # pragma warning (disable : 4035) //function has no return value 00172 # endif 00173 # endif 00174 00180 class _STLP_atomic_freelist { 00181 public: 00185 # if defined (_STLP_USE_ASM_IMPLEMENTATION) 00186 struct item { 00187 item* _M_next; 00188 }; 00189 # else 00190 typedef SLIST_ENTRY item; 00191 # endif 00192 00193 _STLP_atomic_freelist() { 00194 // Statically assert layout of member is as expected by assembly code 00195 # if defined (_STLP_USE_ASM_IMPLEMENTATION) 00196 _STLP_STATIC_ASSERT((sizeof(item) == sizeof(item*)) && (sizeof(_M) == 8)) 00197 _M._M_data._M_top = 0; 00198 _M._M_data._M_sequence = 0; 00199 # else 00200 InitializeSListHead(&_M_head); 00201 # endif 00202 } 00203 00209 void push(item* __item) { 00210 # if defined (_STLP_USE_ASM_IMPLEMENTATION) 00211 __asm 00212 { 00213 mov esi, this 00214 mov ebx, __item 00215 mov eax, [esi] // _M._M_data._M_top 00216 mov edx, [esi+4] // _M._M_data._M_sequence 00217 L1: mov [ebx], eax // __item._M_next = _M._M_data._M_top 00218 lea ecx, [edx+1] // new sequence = _M._M_data._M_sequence + 1 00219 lock cmpxchg8b qword ptr [esi] 00220 jne L1 // Failed, retry! (edx:eax now contain most recent _M_sequence:_M_top) 00221 } 00222 # else 00223 InterlockedPushEntrySList(&_M_head, __item); 00224 # endif 00225 } 00226 00233 item* pop() { 00234 # if defined (_STLP_USE_ASM_IMPLEMENTATION) 00235 __asm 00236 { 00237 mov esi, this 00238 mov eax, [esi] // _M._M_data._M_top 00239 mov edx, [esi+4] // _M._M_data._M_sequence 00240 L1: test eax, eax // _M_top == NULL? 00241 je L2 // Yes, we're done 00242 mov ebx, [eax] // new top = _M._M_data._M_top->_M_next 00243 lea ecx, [edx+1] // new sequence = _M._M_data._M_sequence + 1 00244 lock cmpxchg8b qword ptr [esi] 00245 jne L1 // Failed, retry! (edx:eax now contain most recent _M_sequence:_M_top) 00246 L2: 00247 } 00248 # else 00249 return InterlockedPopEntrySList(&_M_head); 00250 # endif 00251 } 00252 00260 item* clear() { 00261 # if defined (_STLP_USE_ASM_IMPLEMENTATION) 00262 __asm 00263 { 00264 mov esi, this 00265 mov eax, [esi] // _M._M_data._M_top 00266 mov edx, [esi+4] // _M._M_data._M_sequence 00267 L1: test eax, eax // _M_top == NULL? 00268 je L2 // Yes, we're done 00269 xor ebx,ebx // We're attempting to set _M._M_data._M_top to NULL 00270 lea ecx, [edx+1] // new sequence = _M._M_data._M_sequence + 1 00271 lock cmpxchg8b qword ptr [esi] 00272 jne L1 // Failed, retry! (edx:eax now contain most recent _M_sequence:_M_top) 00273 L2: 00274 } 00275 # else 00276 return InterlockedFlushSList(&_M_head); 00277 # endif 00278 } 00279 00280 private: 00281 # if defined (_STLP_USE_ASM_IMPLEMENTATION) 00282 union { 00283 __int64 _M_align; 00284 struct { 00285 item* _M_top; // Topmost element in the freelist 00286 unsigned int _M_sequence; // Sequence counter to prevent "ABA problem" 00287 } _M_data; 00288 } _M; 00289 # else 00290 SLIST_HEADER _M_head; 00291 # endif 00292 00293 _STLP_atomic_freelist(const _STLP_atomic_freelist&); 00294 _STLP_atomic_freelist& operator = (const _STLP_atomic_freelist&); 00295 }; 00296 00297 # if defined (_STLP_USE_ASM_IMPLEMENTATION) 00298 # if defined (_STLP_MSVC) && (_STLP_MSVC < 1300) || defined (__ICL) 00299 # pragma warning (pop) 00300 # endif 00301 # endif 00302 00303 # endif /* _STLP_HAS_ATOMIC_FREELIST */ 00304 00305 #endif 00306 00307 #endif /* _STLP_LOCK_FREE_SLIST_H */ Generated on Sat May 26 2012 04:34:03 for ReactOS by
1.7.6.1
|