latch.h

00001 /* -*- mode:C++; c-basic-offset:4 -*-
00002      Shore-MT -- Multi-threaded port of the SHORE storage manager
00003    
00004                        Copyright (c) 2007-2009
00005       Data Intensive Applications and Systems Labaratory (DIAS)
00006                Ecole Polytechnique Federale de Lausanne
00007    
00008                          All Rights Reserved.
00009    
00010    Permission to use, copy, modify and distribute this software and
00011    its documentation is hereby granted, provided that both the
00012    copyright notice and this permission notice appear in all copies of
00013    the software, derivative works or modified versions, and any
00014    portions thereof, and that both notices appear in supporting
00015    documentation.
00016    
00017    This code is distributed in the hope that it will be useful, but
00018    WITHOUT ANY WARRANTY; without even the implied warranty of
00019    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS
00020    DISCLAIM ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
00021    RESULTING FROM THE USE OF THIS SOFTWARE.
00022 */
00023 
00024 // -*- mode:c++; c-basic-offset:4 -*-
00025 /*<std-header orig-src='shore' incl-file-exclusion='LATCH_H'>
00026 
00027  $Id: latch.h,v 1.35 2010/07/07 20:50:11 nhall Exp $
00028 
00029 SHORE -- Scalable Heterogeneous Object REpository
00030 
00031 Copyright (c) 1994-99 Computer Sciences Department, University of
00032                       Wisconsin -- Madison
00033 All Rights Reserved.
00034 
00035 Permission to use, copy, modify and distribute this software and its
00036 documentation is hereby granted, provided that both the copyright
00037 notice and this permission notice appear in all copies of the
00038 software, derivative works or modified versions, and any portions
00039 thereof, and that both notices appear in supporting documentation.
00040 
00041 THE AUTHORS AND THE COMPUTER SCIENCES DEPARTMENT OF THE UNIVERSITY
00042 OF WISCONSIN - MADISON ALLOW FREE USE OF THIS SOFTWARE IN ITS
00043 "AS IS" CONDITION, AND THEY DISCLAIM ANY LIABILITY OF ANY KIND
00044 FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
00045 
00046 This software was developed with support by the Advanced Research
00047 Project Agency, ARPA order number 018 (formerly 8230), monitored by
00048 the U.S. Army Research Laboratory under contract DAAB07-91-C-Q518.
00049 Further funding for this work was provided by DARPA through
00050 Rome Research Laboratory Contract No. F30602-97-2-0247.
00051 
00052 */
00053 
00054 #ifndef LATCH_H
00055 #define LATCH_H
00056 
00057 #include "w_defines.h"
00058 
00059 /*  -- do not edit anything above this line --   </std-header>*/
00060 
00061 #ifndef STHREAD_H
00062 #include <sthread.h>
00063 #endif
00064 
00065 #ifdef __GNUG__
00066 #pragma interface
00067 #endif
00068 
00069 #include <list>
00070 
00071 /**\enum latch_mode_t
00072  */
00073 enum latch_mode_t { LATCH_NL = 0, LATCH_SH = 1, LATCH_EX = 2 };
00074 
00075 
00076 
00077 class latch_t;
00078 extern ostream &operator<<(ostream &, const latch_t &);
00079 
00080 /** \brief Indicates a latch is held by this thread.
00081  *
00082  *\details Every time we want to grab a latch,
00083  * we have to create a latch_holder_t. 
00084  * We do that with the holder_search class, 
00085  * which searches a TLS list to make sure  we(this thread) 
00086  * doesn't already hold the latch, and, if not,
00087  * it creates a new latch_holder_t for the new latch acquisition.
00088  * It then stuffs the latch_holder_t in the TLS list.  
00089  * If we do already have hold the latch in some capacity, 
00090  * the holder_search returns that existing latch_holder_t.
00091  * \sa holder_search
00092  */
00093 class latch_holder_t 
00094 {
00095 public:
00096 
00097     static __thread latch_holder_t* thread_local_holders;
00098     static __thread latch_holder_t* thread_local_freelist;
00099 
00100     latch_t*     _latch;
00101     latch_mode_t _mode;
00102     int          _count;
00103 private:
00104     sthread_t*   _threadid; // REMOVE ME (for debuging)
00105 
00106     // disabled
00107     latch_holder_t &operator=(latch_holder_t const &other); 
00108 public:
00109     // internal freelist use only!
00110     latch_holder_t* _prev;
00111     latch_holder_t* _next;
00112     
00113     latch_holder_t()
00114     : _latch(NULL), _mode(LATCH_NL), _count(0), _threadid(NULL)
00115     {
00116         _threadid = sthread_t::me();
00117     }
00118 
00119     bool operator==(latch_holder_t const &other) const {
00120         if(_threadid != other._threadid) return false;
00121         return _latch == other._latch && 
00122               _mode == other._mode && _count == other._count;    
00123     }
00124 
00125     void print(ostream &o) const;
00126 };
00127 
00128 #include <iosfwd>
00129 
00130 /**\brief A short-term hold (exclusive or shared) on a page.
00131  *
00132  * \details
00133  * A latch may be acquire()d multiple times by a single thread.  
00134  * The mode of subsequent acquire()s must be at or above the level 
00135  * of the currently held latch.  
00136  * Each of these individual locks must be released.
00137  * \sa latch_holder_t
00138  */
00139 class latch_t : public sthread_named_base_t {
00140 
00141 public:
00142     /**\cond skip */
00143     /// Used for debugging support:
00144     /// Link together all the thread-local storage for latch holders in a list,
00145     /// so that we can print this info later.
00146     static void             on_thread_init(sthread_t *);
00147     /// Used for debugging support:
00148     /// Remove thread's latch info from the list.
00149     static void             on_thread_destroy(sthread_t *);
00150     /**\endcond skip */
00151     
00152     /// Create a latch with the given name.
00153     NORET                   latch_t(const char* const desc = 0);
00154     NORET                   ~latch_t();
00155 
00156     // Dump latch info to the ostream. Not thread-safe. 
00157     ostream&                print(ostream &) const;
00158 
00159     // Return a unique id for the latch.For debugging.
00160     inline const void *     id() const { return &_lock; } 
00161     
00162     /// Change the name of the latch.
00163     inline void             setname(const char *const desc);
00164 
00165     /// Acquire the latch in given mode. \sa  timeout_t.
00166     w_rc_t                  latch_acquire(
00167                                 latch_mode_t             m, 
00168                                 sthread_t::timeout_in_ms timeout = 
00169                                       sthread_base_t::WAIT_FOREVER);
00170     /**\brief Upgrade from SH to EX if it can be done w/o blocking.
00171      * \details Returns bool indicating if it would have blocked, in which
00172      * case the upgrade did not occur. If it didn't have to block, the
00173      * upgrade did occur.
00174      * \note Does \b not increment the count. 
00175      */
00176     w_rc_t                  upgrade_if_not_block(bool& would_block);
00177 
00178     /**\brief Convert atomically an EX latch into an SH latch. 
00179      * \details
00180      * Does not decrement the latch count.
00181      */
00182     void                    downgrade();
00183 
00184     /**\brief release the latch.  
00185      * \details
00186      * Decrements the latch count and releases only when
00187      * it hits 0.
00188      * Returns the resulting latch count. 
00189      */
00190     int                     latch_release();
00191     /**\brief Unreliable, but helpful for some debugging.
00192      */
00193     bool                    is_latched() const;
00194 
00195     /*
00196      * GNATS 30 fix: changes lock_cnt name to latch_cnt,
00197      * and adds _total_cnt to the latch structure itself so it can
00198      * keep track of the total #holders
00199      * This is an additional cost, but it is a great debugging aid.
00200      * \todo TODO: get rid of BUG_LATCH_SEMANTICS_FIX: replace with gnats #
00201      */
00202 
00203     /// Number of acquires.  A thread may hold more than once.
00204     int                     latch_cnt() const { return _total_count; }
00205 
00206     /// How many threads hold the R/W lock.
00207     int                     num_holders() const;
00208     ///  True iff held in EX mode.
00209     bool                    is_mine() const; // only if ex 
00210     ///  True iff held in EX or SH mode.  Actually, it returns the
00211     //latch count (# times this thread holds the latch).
00212     int                     held_by_me() const; // sh or ex
00213     ///  EX,  SH, or NL (if not held at all).
00214     latch_mode_t            mode() const;
00215 
00216     /// string names of modes. 
00217     static const char* const    latch_mode_str[3];
00218 
00219 private:
00220     // found, iterator
00221     w_rc_t                _acquire(latch_mode_t m,
00222                                  sthread_t::timeout_in_ms,
00223                                  latch_holder_t* me);
00224     // return #times this thread holds the latch after this release
00225     int                   _release(latch_holder_t* me);
00226     void                  _downgrade(latch_holder_t* me);
00227     
00228 /* 
00229  * Note: the problem with #threads and #cpus and os preemption is real.
00230  * And it causes things to hang; and it's hard to debug, in the sense that
00231  * using pthread facilities gives thread-analysis tools and debuggers 
00232  * understood-things with which to work.
00233  * Consequently, we use w_pthread_rwlock for our lock.
00234  */
00235     mutable srwlock_t           _lock;
00236 
00237     // disabled
00238     NORET                        latch_t(const latch_t&);
00239     latch_t&                     operator=(const latch_t&);
00240 
00241     w_base_t::uint4_t            _total_count;
00242 };
00243 
00244 
00245 
00246 inline void
00247 latch_t::setname(const char* const desc)
00248 {
00249     rename("l:", desc);
00250 }
00251 
00252 inline bool
00253 latch_t::is_latched() const
00254 {
00255     /* NOTE: Benign race -- this function is naturally unreliable, as
00256      * its return value may become invalid as soon as it is
00257      * generated. The only way to reliably know if the lock is held at
00258      * a particular moment is to hold it yourself, which defeats the
00259      * purpose of asking in the first place...
00260      * ... except for assertions / debugging... since there are bugs
00261      * in acquire/release of latches 
00262      */
00263     return _lock.is_locked();
00264 }
00265 
00266 inline int
00267 latch_t::num_holders() const
00268 {
00269     return _lock.num_holders();
00270 }
00271 
00272 
00273 inline latch_mode_t
00274 latch_t::mode() const
00275 {
00276     switch(_lock.mode()) {
00277     case mcs_rwlock::NONE: return LATCH_NL;
00278     case mcs_rwlock::WRITER: return LATCH_EX;
00279     case mcs_rwlock::READER: return LATCH_SH;
00280     default: w_assert1(0); // shouldn't ever happen
00281              return LATCH_SH; // keep compiler happy
00282     }
00283 }
00284 
00285 // unsafe: for use in debugger:
00286 extern "C" void print_my_latches();
00287 extern "C" void print_all_latches();
00288 extern "C" void print_latch(const latch_t *l);
00289 
00290 /*<std-footer incl-file-exclusion='LATCH_H'>  -- do not edit anything below this line -- */
00291 
00292 #endif          /*</std-footer>*/

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