MFMv2.0.10
Movable Feast Machine Simulator 2.0.10
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Mutex.h
Go to the documentation of this file.
1 /* -*- mode:C++ -*-
2  Mutex.h A wrapper class for dealing with pthread_mutexes
3  Copyright (C) 2014 The Regents of the University of New Mexico. All rights reserved.
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Lesser General Public
7  License as published by the Free Software Foundation; either
8  version 2.1 of the License, or (at your option) any later version.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this library; if not, write to the Free Software
17  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
18  USA
19 */
20 
28 #ifndef MUTEX_H
29 #define MUTEX_H
30 
31 #include <pthread.h> /* for pthread_mutex_t etc */
32 #include "Fail.h"
33 
34 #ifdef MUTEX_ERROR_CHECKS
35 #define MFM_MUTEX_TYPE PTHREAD_MUTEX_ERRORCHECK
36 #else
37 #define MFM_MUTEX_TYPE PTHREAD_MUTEX_NORMAL
38 #endif
39 
40 namespace MFM
41 {
42  class Mutex
43  {
44  private:
48  pthread_mutex_t m_lock;
49 
50  pthread_mutexattr_t m_attr;
51 
55  bool m_locked;
56 
57  pthread_cond_t m_virtualCond;
58  bool m_inVCW;
59 
63  pthread_t m_threadId;
64 
65  // Declare away copy ctor; pthread_mutexes can't be copied
66  Mutex(const Mutex & ) ;
67 
68  void CondWait(pthread_cond_t & condvar)
69  {
70  pthread_cond_wait(&condvar, &m_lock);
71 
72  // The signal gave us back the lock without going through
73  // Mutex::Lock; simulate its effects
74  if (m_locked)
75  {
76  FAIL(LOCK_FAILURE);
77  }
78  m_threadId = pthread_self();
79  m_locked = true;
80  }
81 
82  public:
83 
84  class ScopeLock
85  {
86  private:
87  Mutex & m_mutex;
88  public:
89  ScopeLock(Mutex & mutex) : m_mutex(mutex)
90  {
91  m_mutex.Lock();
92  }
93  ~ScopeLock()
94  {
95  m_mutex.Unlock();
96  }
97  };
98 
99  class Predicate
100  {
101  private:
102  Mutex & m_mutex;
103  pthread_cond_t m_condvar;
104  pthread_t m_threadIdOfWaiter;
105  public:
106  virtual bool EvaluatePredicate() = 0;
107 
108  Predicate(Mutex & mutex) : m_mutex(mutex)
109  {
110  pthread_cond_init(&m_condvar, NULL);
111  }
112 
113  void WaitForCondition()
114  {
115  m_mutex.AssertIHoldTheLock();
116  m_threadIdOfWaiter = m_mutex.m_threadId;
117 
118  while (!EvaluatePredicate())
119  {
120  m_mutex.CondWait(m_condvar);
121  }
122  }
123 
124  void SignalCondition()
125  {
126  m_mutex.AssertIHoldTheLock();
127  pthread_cond_signal(&m_condvar);
128  }
129  };
130 
137  Mutex() :
138  m_locked(false)
139  , m_inVCW(false)
140  {
141 
142  if (pthread_mutexattr_init(&m_attr))
143  {
144  FAIL(LOCK_FAILURE);
145  }
146 
147  if (pthread_mutexattr_settype(&m_attr, MFM_MUTEX_TYPE))
148  {
149  FAIL(LOCK_FAILURE);
150  }
151 
152  if (pthread_mutex_init(&m_lock, &m_attr))
153  {
154  FAIL(LOCK_FAILURE);
155  }
156  }
157 
166  {
167  if (m_locked)
168  {
169  FAIL(LOCK_FAILURE);
170  }
171 
172  if (pthread_mutex_destroy(&m_lock))
173  {
174  FAIL(LOCK_FAILURE);
175  }
176 
177  if (pthread_mutexattr_destroy(&m_attr))
178  {
179  FAIL(LOCK_FAILURE);
180  }
181  }
182 
190  bool TryLock()
191  {
192  if (m_locked && pthread_equal(m_threadId, pthread_self()))
193  {
194  FAIL(LOCK_FAILURE);
195  }
196 
197  bool ret = !pthread_mutex_trylock(&m_lock);
198  if (ret)
199  {
200  m_locked = true;
201  m_threadId = pthread_self();
202  }
203  return ret;
204  }
205 
212  void Lock()
213  {
214  if (m_locked && pthread_equal(m_threadId, pthread_self()))
215  {
216  FAIL(LOCK_FAILURE);
217  }
218 
219  if (pthread_mutex_lock(&m_lock))
220  {
221  FAIL(LOCK_FAILURE);
222  }
223 
224  // Update threadid before declaring locked so, for example, the
225  // first condition in this method can't trigger on a possibly
226  // stale threadid.
227  m_threadId = pthread_self();
228  m_locked = true;
229  }
230 
239  {
240  if (!m_locked)
241  {
242  FAIL(LOCK_FAILURE);
243  }
244 
245  if (!pthread_equal(m_threadId, pthread_self()))
246  {
247  FAIL(LOCK_FAILURE);
248  }
249  }
250 
258  void Unlock()
259  {
261 
262  m_locked = false;
263  m_threadId = 0;
264  pthread_mutex_unlock(&m_lock);
265  }
266 
278  {
279  if (!m_locked)
280  {
281  return false;
282  }
283 
284  if (pthread_equal(m_threadId, pthread_self()))
285  {
286  FAIL(LOCK_FAILURE);
287  }
288 
289  return true;
290  }
291 
292  void ReportMutexStatus(int level) ; // level not Logger::Level to avoid #include loop :(
293 
294 #ifdef LOSER_LOCK
295 
301  bool IHoldThisLock() const
302  {
303  return m_locked && pthread_equal(m_threadId, pthread_self());
304  }
305 #endif /* LOSER_LOCK */
306 
307  };
308 } /* namespace MFM */
309 
310 #endif /*MUTEX_H*/
bool TryLock()
Definition: Mutex.h:190
~Mutex()
Definition: Mutex.h:165
void AssertIHoldTheLock()
Definition: Mutex.h:238
Definition: Mutex.h:84
Definition: Mutex.h:42
bool IsLockedByAnother()
Definition: Mutex.h:277
void Lock()
Definition: Mutex.h:212
Definition: Mutex.h:99
Mutex()
Definition: Mutex.h:137
void Unlock()
Definition: Mutex.h:258