library of assembled shared sources |
http://lass.cocamware.com |
00001 /** @file 00002 * @author Bram de Greve (bramz@users.sourceforge.net) 00003 * @author Tom De Muer (tomdemuer@users.sourceforge.net) 00004 * 00005 * *** BEGIN LICENSE INFORMATION *** 00006 * 00007 * The contents of this file are subject to the Common Public Attribution License 00008 * Version 1.0 (the "License"); you may not use this file except in compliance with 00009 * the License. You may obtain a copy of the License at 00010 * http://lass.sourceforge.net/cpal-license. The License is based on the 00011 * Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover 00012 * use of software over a computer network and provide for limited attribution for 00013 * the Original Developer. In addition, Exhibit A has been modified to be consistent 00014 * with Exhibit B. 00015 * 00016 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT 00017 * WARRANTY OF ANY KIND, either express or implied. See the License for the specific 00018 * language governing rights and limitations under the License. 00019 * 00020 * The Original Code is LASS - Library of Assembled Shared Sources. 00021 * 00022 * The Initial Developer of the Original Code is Bram de Greve and Tom De Muer. 00023 * The Original Developer is the Initial Developer. 00024 * 00025 * All portions of the code written by the Initial Developer are: 00026 * Copyright (C) 2004-2007 the Initial Developer. 00027 * All Rights Reserved. 00028 * 00029 * Contributor(s): 00030 * 00031 * Alternatively, the contents of this file may be used under the terms of the 00032 * GNU General Public License Version 2 or later (the GPL), in which case the 00033 * provisions of GPL are applicable instead of those above. If you wish to allow use 00034 * of your version of this file only under the terms of the GPL and not to allow 00035 * others to use your version of this file under the CPAL, indicate your decision by 00036 * deleting the provisions above and replace them with the notice and other 00037 * provisions required by the GPL License. If you do not delete the provisions above, 00038 * a recipient may use your version of this file under either the CPAL or the GPL. 00039 * 00040 * *** END LICENSE INFORMATION *** 00041 */ 00042 00043 namespace lass 00044 { 00045 namespace util 00046 { 00047 00048 // --- public -------------------------------------------------------------------------------------- 00049 00050 template <typename T, typename A> 00051 lock_free_stack<T, A>::lock_free_stack(): 00052 util::AllocatorConcurrentFreeList<A>(sizeof(node_t)), 00053 top_() 00054 { 00055 } 00056 00057 00058 00059 template <typename T, typename A> 00060 lock_free_stack<T, A>::~lock_free_stack() 00061 { 00062 node_t top = top_.get(); 00063 while (top) 00064 { 00065 node_t* const next = top->next; 00066 free_node(top); 00067 top = next; 00068 } 00069 } 00070 00071 00072 00073 /** push value on stack. 00074 * @arg exception safe: if no node of could be allocatoed, or if copy constructor of x throws, 00075 * it fails gracefully. 00076 */ 00077 template <typename T, typename A> 00078 void lock_free_stack<T, A>::push(const value_type& x) 00079 { 00080 node_t* node = make_node(x); 00081 push_node(node); 00082 } 00083 00084 00085 00086 /** Try to pop a value and copy it in @a x . 00087 * @return false if stack is empty 00088 * @arg strong exception safety: if copy-constructor of x throws, 00089 * node is put back on top and exception is propagated 00090 */ 00091 template <typename T, typename A> 00092 bool lock_free_stack<T, A>::pop(value_type& x) 00093 { 00094 node_t* const node = pop_node(); 00095 if (!node) 00096 { 00097 return false; 00098 } 00099 try 00100 { 00101 x = node->value; 00102 } 00103 catch (...) 00104 { 00105 // put it back! 00106 push_node(node); 00107 throw; 00108 } 00109 free_node(node); 00110 return true; 00111 } 00112 00113 00114 00115 /** Try to pop a value and swap it in @a x . 00116 * @return false if stack is empty 00117 * @arg condition on @a value_type: x.swap(y) must be a valid, non throwing operation. 00118 * @arg exception safety: no-throw guarantee (if x.swap(y) plays by the rules) 00119 */ 00120 template <typename T, typename A> 00121 bool lock_free_stack<T, A>::pop_swap(value_type& x) 00122 { 00123 node_t* const node = pop_node(); 00124 if (!node) 00125 { 00126 return false; 00127 } 00128 x.swap(node->value); 00129 free_node(node); 00130 return true; 00131 } 00132 00133 00134 00135 // --- private ------------------------------------------------------------------------------------- 00136 00137 template <typename T, typename A> 00138 typename lock_free_stack<T, A>::node_t* const 00139 lock_free_stack<T, A>::make_node(const value_type& x) 00140 { 00141 node_t* node = static_cast<node_t*>(this->allocate()); 00142 try 00143 { 00144 new (&node->value) value_type(x); 00145 } 00146 catch (...) 00147 { 00148 this->deallocate(node); 00149 throw; 00150 } 00151 node->next = 0; 00152 return node; 00153 } 00154 00155 00156 00157 template <typename T, typename A> 00158 void lock_free_stack<T, A>::free_node(node_t* node) 00159 { 00160 node->value.~value_type(); 00161 this->deallocate(node); 00162 } 00163 00164 00165 00166 template <typename T, typename A> 00167 void lock_free_stack<T, A>::push_node(node_t* node) 00168 { 00169 do 00170 { 00171 pointer_t top = top_; 00172 node->next = top.get(); 00173 pointer_t new_top(node, top.tag() + 1); 00174 } 00175 while (!top_.atomicCompareAndSwap(top, new_top)); 00176 } 00177 00178 00179 00180 template <typename T, typename A> 00181 typename lock_free_stack<T, A>::node_t* const 00182 lock_free_stack<T, A>::pop_node() 00183 { 00184 pointer_t top; 00185 do 00186 { 00187 pointer_t top = top_; 00188 if (!top) 00189 { 00190 return 0; 00191 } 00192 00193 // This is the tricky part ... does top still exist? In theory, it can be freed by now. 00194 // But here's the cunning part: the use of AllocatorLockFreeFreeList ensures that at least 00195 // the memory is not reclaimed (it merely is in purgatory instead). 00196 // So, it's somehow safe to access its next member (it may give a totally wacked up 00197 // result, but that doesn't really matter). 00198 // It comes at a sacrifice though: memory will only be reclaimed at the end of the 00199 // stack's lifecycle. [Bramz] 00200 // 00201 // Update: This is not entirely true ... if top is currently "in use", then top->next may 00202 // correspond with a bit pattern that isn't a valid pointer at all (and most likely, 00203 // if it is a valid bit pattern, it won't point to allocated memory). Anyway, this 00204 // means that the behaviour is pretty much undefined. The machine can do whatever it wants: 00205 // halt, reboot, make funny noises or make some coffee ... [Bramz] 00206 // 00207 pointer_t next(top->next, top.tag() + 1); 00208 } 00209 while (!top_.atomicCompareAndSwap(top, next)); 00210 return top.get(); 00211 } 00212 00213 } 00214 00215 } 00216 00217 // EOF
Generated on Mon Nov 10 14:20:30 2008 for Library of Assembled Shared Sources by 1.5.7.1 |