mcs_lock.h

00001 #ifndef MCS_LOCK_H
00002 #define MCS_LOCK_H
00003 /* -*- mode:C++; c-basic-offset:4 -*-
00004      Shore-MT -- Multi-threaded port of the SHORE storage manager
00005    
00006                        Copyright (c) 2007-2009
00007       Data Intensive Applications and Systems Labaratory (DIAS)
00008                Ecole Polytechnique Federale de Lausanne
00009    
00010                          All Rights Reserved.
00011    
00012    Permission to use, copy, modify and distribute this software and
00013    its documentation is hereby granted, provided that both the
00014    copyright notice and this permission notice appear in all copies of
00015    the software, derivative works or modified versions, and any
00016    portions thereof, and that both notices appear in supporting
00017    documentation.
00018    
00019    This code is distributed in the hope that it will be useful, but
00020    WITHOUT ANY WARRANTY; without even the implied warranty of
00021    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS
00022    DISCLAIM ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
00023    RESULTING FROM THE USE OF THIS SOFTWARE.
00024 */
00025 
00026 // -*- mode:c++; c-basic-offset:4 -*-
00027 /*<std-header orig-src='shore' incl-file-exclusion='MCS_LOCK_H'>
00028 
00029  $Id: mcs_lock.h,v 1.7 2010/11/08 15:07:23 nhall Exp $
00030 
00031 SHORE -- Scalable Heterogeneous Object REpository
00032 
00033 Copyright (c) 1994-99 Computer Sciences Department, University of
00034                       Wisconsin -- Madison
00035 All Rights Reserved.
00036 
00037 Permission to use, copy, modify and distribute this software and its
00038 documentation is hereby granted, provided that both the copyright
00039 notice and this permission notice appear in all copies of the
00040 software, derivative works or modified versions, and any portions
00041 thereof, and that both notices appear in supporting documentation.
00042 
00043 THE AUTHORS AND THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY
00044 OF WISCONSIN - MADISON ALLOW FREE USE OF THIS SOFTWARE IN ITS
00045 "AS IS" CONDITION, AND THEY DISCLAIM ANY LIABILITY OF ANY KIND
00046 FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
00047 
00048 This software was developed with support by the Advanced Research
00049 Project Agency, ARPA order number 018 (formerly 8230), monitored by
00050 the U.S. Army Research Laboratory under contract DAAB07-91-C-Q518.
00051 Further funding for this work was provided by DARPA through
00052 Rome Research Laboratory Contract No. F30602-97-2-0247.
00053 
00054 */
00055 
00056 /*  -- do not edit anything above this line --   </std-header>*/
00057 
00058 /**\cond skip */
00059 
00060 /**\brief An MCS queuing spinlock. 
00061  *
00062  * Useful for short, contended critical sections. 
00063  * If contention is expected to be rare, use a
00064  * tatas_lock; 
00065  * if critical sections are long, use pthread_mutex_t so 
00066  * the thread can block instead of spinning.
00067  *
00068  * Tradeoffs are:
00069    - test-and-test-and-set locks: low-overhead but not scalable
00070    - queue-based locks: higher overhead but scalable
00071    - pthread mutexes : high overhead and blocks, but frees up cpu for other threads
00072 */
00073 struct mcs_lock {
00074     struct qnode;
00075     typedef qnode volatile* qnode_ptr;
00076     struct qnode {
00077         qnode_ptr _next;
00078         bool _waiting;
00079         //      qnode() : _next(NULL), _waiting(false) { } // non-POD, alas
00080     };
00081     struct ext_qnode {
00082         qnode _node;
00083         mcs_lock* _held;
00084         operator qnode*() { return &_node; }
00085     };
00086 #define MCS_EXT_QNODE_INITIALIZER {{NULL,false},NULL}
00087 #define MCS_EXT_QNODE_INITIALIZE(x) \
00088 { (x)._node._next = NULL; (x)._node._waiting = false; (x)._held = NULL; }
00089     qnode_ptr volatile _tail;
00090     mcs_lock() : _tail(NULL) { }
00091 
00092     /* This spinning occurs whenever there are critical sections ahead
00093        of us.
00094 
00095        CC mangles this as __1cImcs_lockPspin_on_waiting6Mpon0AFqnode__v_
00096     */
00097     void spin_on_waiting(qnode_ptr me) {
00098         while(me->_waiting);
00099     }
00100     /* Only acquire the lock if it is free...
00101      */
00102     bool attempt(ext_qnode* me) {
00103         if(attempt((qnode_ptr) me)) {
00104             me->_held = this;
00105             return true;
00106         }
00107         return false;
00108     }
00109     bool attempt(qnode_ptr me) {
00110         me->_next = NULL;
00111         me->_waiting = true;
00112         membar_producer();
00113         qnode_ptr pred = (qnode_ptr) atomic_cas_ptr(&_tail, 0, (void*) me);
00114         // lock held?
00115         if(pred)
00116             return false;
00117         membar_enter();
00118         return true;
00119     }
00120     // return true if the lock was free
00121     void* acquire(ext_qnode* me) {
00122         me->_held = this;
00123         return acquire((qnode*) me);
00124     }
00125     void* acquire(qnode_ptr me) {
00126         me->_next = NULL;
00127         me->_waiting = true;
00128         membar_producer();
00129         qnode_ptr pred = (qnode_ptr) atomic_swap_ptr(&_tail, (void*) me);
00130         if(pred) {
00131             pred->_next = me;
00132             spin_on_waiting(me);
00133         }
00134         membar_enter();
00135         return (void*) pred;
00136     }
00137 
00138     /* This spinning only occurs when we are at _tail and catch a
00139        thread trying to enqueue itself.
00140 
00141        CC mangles this as __1cImcs_lockMspin_on_next6Mpon0AFqnode__3_
00142     */
00143     qnode_ptr spin_on_next(qnode_ptr me) {
00144         qnode_ptr next;
00145         while(!(next=me->_next));
00146         return next;
00147     }
00148     void release(ext_qnode *me) { 
00149         w_assert1(is_mine(me));
00150         me->_held = 0; release((qnode*) me); 
00151     }
00152     void release(ext_qnode &me) { w_assert1(is_mine(&me)); release(&me); }
00153     void release(qnode &me) { release(&me); }
00154     void release(qnode_ptr me) {
00155         membar_exit();
00156 
00157         qnode_ptr next;
00158         if(!(next=me->_next)) {
00159             if(me == _tail && me == (qnode_ptr) 
00160                     atomic_cas_ptr(&_tail, (void*) me, NULL))
00161             return;
00162             next = spin_on_next(me);
00163         }
00164         next->_waiting = false;
00165     }
00166     // bool is_mine(qnode_ptr me) { return me->_held == this; }
00167     bool is_mine(ext_qnode* me) { return me->_held == this; }
00168 };
00169 /**\endcond skip */
00170 #endif
00171 

Generated on Thu Dec 9 08:42:27 2010 for Shore Storage Manager by  doxygen 1.4.7