library of assembled shared sources

http://lass.cocamware.com

lock_free_stack.inl

Go to the documentation of this file.
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 doxygen 1.5.7.1
SourceForge.net Logo