MongoDB  2.7.0
mutex.h
1 // @file mutex.h
2 
3 /* Copyright 2009 10gen Inc.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #pragma once
19 
20 #ifdef _WIN32
21 #include "mongo/platform/windows_basic.h"
22 #endif
23 
24 #include <boost/noncopyable.hpp>
25 #include <boost/thread/mutex.hpp>
26 #include <boost/thread/xtime.hpp>
27 
28 #include "mongo/util/assert_util.h"
29 #include "mongo/util/heapcheck.h"
30 #include "mongo/util/concurrency/threadlocal.h"
31 #include "mongo/util/time_support.h"
32 
33 #if defined(_DEBUG)
34 #include "mongo/util/concurrency/mutexdebugger.h"
35 #endif
36 
37 // Macro to get line as a string constant
38 #define MONGO_STRINGIFY(X) #X
39 // Double-expansion trick to get preproc to actually substitute __LINE__
40 #define _MONGO_LINE_STRING(LINE) MONGO_STRINGIFY( LINE )
41 #define MONGO_LINE_STRING _MONGO_LINE_STRING( __LINE__ )
42 
43 // Mutex names should be as <file>::<line> string
44 #define MONGO_FILE_LINE __FILE__ "::" MONGO_LINE_STRING
45 
46 namespace mongo {
47 
48  inline boost::xtime incxtimemillis( long long s ) {
49  boost::xtime xt;
50  boost::xtime_get(&xt, MONGO_BOOST_TIME_UTC);
51  xt.sec += (int)( s / 1000 );
52  xt.nsec += (int)(( s % 1000 ) * 1000000);
53  if ( xt.nsec >= 1000000000 ) {
54  xt.nsec -= 1000000000;
55  xt.sec++;
56  }
57  return xt;
58  }
59 
60  // If you create a local static instance of this class, that instance will be destroyed
61  // before all global static objects are destroyed, so _destroyingStatics will be set
62  // to true before the global static variables are destroyed.
63  class StaticObserver : boost::noncopyable {
64  public:
65  static bool _destroyingStatics;
66  ~StaticObserver() { _destroyingStatics = true; }
67  };
68 
74  class mutex : boost::noncopyable {
75  public:
76  const char * const _name;
77  mutex(const char *name) : _name(name)
78  {
79  _m = new boost::timed_mutex();
80  IGNORE_OBJECT( _m ); // Turn-off heap checking on _m
81  }
82  ~mutex() {
83  if( !StaticObserver::_destroyingStatics ) {
84  UNIGNORE_OBJECT( _m );
85  delete _m;
86  }
87  }
88 
89  class try_lock : boost::noncopyable {
90  public:
91  try_lock( mongo::mutex &m , int millis = 0 )
92  : _l( m.boost() , incxtimemillis( millis ) ) ,
93  ok( _l.owns_lock() )
94  { }
95  private:
96  boost::timed_mutex::scoped_timed_lock _l;
97  public:
98  const bool ok;
99  };
100 
101  class scoped_lock : boost::noncopyable {
102  public:
103 #if defined(_DEBUG)
104  struct PostStaticCheck {
105  PostStaticCheck();
106  } _check;
107  mongo::mutex * const _mut;
108 #endif
109  scoped_lock( mongo::mutex &m ) :
110 #if defined(_DEBUG)
111  _mut(&m),
112 #endif
113  _l( m.boost() ) {
114 #if defined(_DEBUG)
115  mutexDebugger.entering(_mut->_name);
116 #endif
117  }
118  ~scoped_lock() {
119 #if defined(_DEBUG)
120  mutexDebugger.leaving(_mut->_name);
121 #endif
122  }
123  boost::timed_mutex::scoped_lock &boost() { return _l; }
124  private:
125  boost::timed_mutex::scoped_lock _l;
126  };
127  private:
128  boost::timed_mutex &boost() { return *_m; }
129  boost::timed_mutex *_m;
130  };
131 
132  typedef mongo::mutex::scoped_lock scoped_lock;
133 
139 #if defined(_WIN32)
140  class SimpleMutex : boost::noncopyable {
141  public:
142  SimpleMutex( const StringData& ) { InitializeCriticalSection( &_cs ); }
143  void dassertLocked() const { }
144  void lock() { EnterCriticalSection( &_cs ); }
145  void unlock() { LeaveCriticalSection( &_cs ); }
146  class scoped_lock {
147  SimpleMutex& _m;
148  public:
149  scoped_lock( SimpleMutex &m ) : _m(m) { _m.lock(); }
150  ~scoped_lock() { _m.unlock(); }
151  const SimpleMutex& m() const { return _m; }
152  };
153 
154  private:
155  CRITICAL_SECTION _cs;
156  };
157 #else
158  class SimpleMutex : boost::noncopyable {
159  public:
160  void dassertLocked() const { }
161  SimpleMutex(const StringData& name) { verify( pthread_mutex_init(&_lock,0) == 0 ); }
162  ~SimpleMutex(){
163  if ( ! StaticObserver::_destroyingStatics ) {
164  verify( pthread_mutex_destroy(&_lock) == 0 );
165  }
166  }
167 
168  void lock() { verify( pthread_mutex_lock(&_lock) == 0 ); }
169  void unlock() { verify( pthread_mutex_unlock(&_lock) == 0 ); }
170  public:
171  class scoped_lock : boost::noncopyable {
172  SimpleMutex& _m;
173  public:
174  scoped_lock( SimpleMutex &m ) : _m(m) { _m.lock(); }
175  ~scoped_lock() { _m.unlock(); }
176  const SimpleMutex& m() const { return _m; }
177  };
178 
179  private:
180  pthread_mutex_t _lock;
181  };
182 #endif
183 
187  class RecursiveMutex : boost::noncopyable {
188  public:
189  RecursiveMutex(const StringData& name) : m(name) { }
190  bool isLocked() const { return n.get() > 0; }
191  class scoped_lock : boost::noncopyable {
192  RecursiveMutex& rm;
193  int& nLocksByMe;
194  public:
195  scoped_lock( RecursiveMutex &m ) : rm(m), nLocksByMe(rm.n.getRef()) {
196  if( nLocksByMe++ == 0 )
197  rm.m.lock();
198  }
199  ~scoped_lock() {
200  verify( nLocksByMe > 0 );
201  if( --nLocksByMe == 0 ) {
202  rm.m.unlock();
203  }
204  }
205  };
206  private:
207  SimpleMutex m;
209  };
210 
211 }
Definition: mutex.h:89
Definition: mutex.h:101
Definition: mutex.h:191
The concept with SimpleMutex is that it is a basic lock/unlock with no special functionality (such as...
Definition: mutex.h:158
On pthread systems, it is an error to destroy a mutex while held (boost mutex may use pthread)...
Definition: mutex.h:74
Definition: mutex.h:63
Definition: mutex.h:171
This can be used instead of boost recursive mutex.
Definition: mutex.h:187