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.4 2010/06/23 23:43:43 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) { }
00080     };
00081     struct ext_qnode : qnode {
00082         mcs_lock* _held;
00083     };
00084     qnode_ptr volatile _tail;
00085     mcs_lock() : _tail(NULL) { }
00086 
00087     /* This spinning occurs whenever there are critical sections ahead
00088        of us.
00089 
00090        CC mangles this as __1cImcs_lockPspin_on_waiting6Mpon0AFqnode__v_
00091     */
00092     void spin_on_waiting(qnode_ptr me) {
00093         while(me->_waiting);
00094     }
00095     /* Only acquire the lock if it is free...
00096      */
00097     bool attempt(ext_qnode* me) {
00098         if(attempt((qnode_ptr) me)) {
00099             me->_held = this;
00100             return true;
00101         }
00102         return false;
00103     }
00104     bool attempt(qnode_ptr me) {
00105         me->_next = NULL;
00106         me->_waiting = true;
00107         membar_producer();
00108         qnode_ptr pred = (qnode_ptr) atomic_cas_ptr(&_tail, 0, (void*) me);
00109         // lock held?
00110         if(pred)
00111             return false;
00112         membar_enter();
00113         return true;
00114     }
00115     // return true if the lock was free
00116     void* acquire(ext_qnode* me) {
00117         me->_held = this;
00118         return acquire((qnode*) me);
00119     }
00120     void* acquire(qnode_ptr me) {
00121         me->_next = NULL;
00122         me->_waiting = true;
00123         membar_producer();
00124         qnode_ptr pred = (qnode_ptr) atomic_swap_ptr(&_tail, (void*) me);
00125         if(pred) {
00126             pred->_next = me;
00127             spin_on_waiting(me);
00128         }
00129         membar_enter();
00130         return (void*) pred;
00131     }
00132 
00133     /* This spinning only occurs when we are at _tail and catch a
00134        thread trying to enqueue itself.
00135 
00136        CC mangles this as __1cImcs_lockMspin_on_next6Mpon0AFqnode__3_
00137     */
00138     qnode_ptr spin_on_next(qnode_ptr me) {
00139         qnode_ptr next;
00140         while(!(next=me->_next));
00141         return next;
00142     }
00143     void release(ext_qnode *me) { 
00144         w_assert1(is_mine(me));
00145         me->_held = 0; release((qnode*) me); 
00146     }
00147     void release(ext_qnode &me) { release(&me); }
00148     void release(qnode &me) { release(&me); }
00149     void release(qnode_ptr me) {
00150         w_assert1(is_mine(me));
00151         membar_exit();
00152 
00153         qnode_ptr next;
00154         if(!(next=me->_next)) {
00155             if(me == _tail && me == (qnode_ptr) 
00156                     atomic_cas_ptr(&_tail, (void*) me, NULL))
00157             return;
00158             next = spin_on_next(me);
00159         }
00160         next->_waiting = false;
00161     }
00162     bool is_mine(qnode_ptr me) { return me._held == this; }
00163     bool is_mine(ext_qnode* me) { return me->_held == this; }
00164 };
00165 /**\endcond skip */
00166 #endif
00167 

Generated on Wed Jul 7 17:22:32 2010 for Shore Storage Manager by  doxygen 1.4.7