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>*/