Orocos Real-Time Toolkit  2.9.0
Mutex.hpp
Go to the documentation of this file.
1 /***************************************************************************
2  tag: Peter Soetens Thu Oct 10 16:16:57 CEST 2002 Mutex.hpp
3 
4  Mutex.hpp - description
5  -------------------
6  begin : Thu October 10 2002
7  copyright : (C) 2002 Peter Soetens
8  email : peter.soetens@mech.kuleuven.ac.be
9 
10  ***************************************************************************
11  * This library is free software; you can redistribute it and/or *
12  * modify it under the terms of the GNU General Public *
13  * License as published by the Free Software Foundation; *
14  * version 2 of the License. *
15  * *
16  * As a special exception, you may use this file as part of a free *
17  * software library without restriction. Specifically, if other files *
18  * instantiate templates or use macros or inline functions from this *
19  * file, or you compile this file and link it with other files to *
20  * produce an executable, this file does not by itself cause the *
21  * resulting executable to be covered by the GNU General Public *
22  * License. This exception does not however invalidate any other *
23  * reasons why the executable file might be covered by the GNU General *
24  * Public License. *
25  * *
26  * This library is distributed in the hope that it will be useful, *
27  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
28  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
29  * Lesser General Public License for more details. *
30  * *
31  * You should have received a copy of the GNU General Public *
32  * License along with this library; if not, write to the Free Software *
33  * Foundation, Inc., 59 Temple Place, *
34  * Suite 330, Boston, MA 02111-1307 USA *
35  * *
36  ***************************************************************************/
37 
38 
39 #ifndef OS_MUTEX_HPP
40 #define OS_MUTEX_HPP
41 
42 #include "fosi.h"
43 #include "../rtt-config.h"
44 #include "rtt-os-fwd.hpp"
45 #include "CAS.hpp"
46 #include "Semaphore.hpp"
47 #include "Time.hpp"
48 
49 #include <cassert>
50 
51 #ifdef ORO_OS_USE_BOOST_THREAD
52 // BOOST_DATE_TIME_POSIX_TIME_STD_CONFIG is defined in rtt-config.h
53 #include <boost/thread/mutex.hpp>
54 #include <boost/thread/recursive_mutex.hpp>
55 #include <boost/thread/shared_mutex.hpp>
56 #include <boost/date_time/posix_time/posix_time_types.hpp>
57 #endif
58 
59 namespace RTT
60 { namespace os {
61 
68  {
69  public:
70  virtual ~MutexInterface() {}
71  virtual void lock() =0;
72  virtual void unlock() =0;
73  virtual bool trylock() = 0;
74  virtual bool timedlock(Seconds) = 0;
75  virtual void lock_shared() {}
76  virtual void unlock_shared() {}
77  virtual bool trylock_shared() { return false; }
78  virtual bool timedlock_shared(Seconds) { return false; }
79  };
80 
81 
92  class RTT_API Mutex : public MutexInterface
93  {
94  friend class Condition;
95 #ifndef ORO_OS_USE_BOOST_THREAD
96  protected:
98  public:
103  {
104  rtos_mutex_init( &m);
105  }
106 
112  virtual ~Mutex()
113  {
114  if ( trylock() ) {
115  unlock();
116  rtos_mutex_destroy( &m );
117  }
118  }
119 
120  virtual void lock ()
121  {
122  rtos_mutex_lock( &m );
123  }
124 
125  virtual void unlock()
126  {
127  rtos_mutex_unlock( &m );
128  }
129 
135  virtual bool trylock()
136  {
137  if ( rtos_mutex_trylock( &m ) == 0 )
138  return true;
139  return false;
140  }
141 
149  virtual bool timedlock(Seconds s)
150  {
151  if ( rtos_mutex_trylock_for( &m, Seconds_to_nsecs(s) ) == 0 )
152  return true;
153  return false;
154  }
155 #else
156  protected:
157  boost::timed_mutex m;
158  public:
162  Mutex()
163  {
164  }
165 
171  virtual ~Mutex()
172  {
173  }
174 
175  virtual void lock ()
176  {
177  m.lock();
178  }
179 
180  virtual void unlock()
181  {
182  m.unlock();
183  }
184 
190  virtual bool trylock()
191  {
192  return m.try_lock();
193  }
194 
202  virtual bool timedlock(Seconds s)
203  {
204  return m.timed_lock( boost::posix_time::microseconds(Seconds_to_nsecs(s)/1000) );
205  }
206 #endif
207 
208  };
209 
219  {
220 #ifndef ORO_OS_USE_BOOST_THREAD
221  protected:
223  public:
228  {
229  rtos_mutex_rec_init( &recm );
230  }
231 
237  virtual ~MutexRecursive()
238  {
239  if ( trylock() ) {
240  unlock();
241  rtos_mutex_rec_destroy( &recm );
242  }
243  }
244 
245  void lock ()
246  {
247  rtos_mutex_rec_lock( &recm );
248  }
249 
250  virtual void unlock()
251  {
252  rtos_mutex_rec_unlock( &recm );
253  }
254 
260  virtual bool trylock()
261  {
262  if ( rtos_mutex_rec_trylock( &recm ) == 0 )
263  return true;
264  return false;
265  }
266 
274  virtual bool timedlock(Seconds s)
275  {
276  if ( rtos_mutex_rec_trylock_for( &recm, Seconds_to_nsecs(s) ) == 0 )
277  return true;
278  return false;
279  }
280 #else
281  protected:
282  boost::recursive_timed_mutex recm;
283  public:
288  {
289  }
290 
296  virtual ~MutexRecursive()
297  {
298  }
299 
300  void lock ()
301  {
302  recm.lock();
303  }
304 
305  virtual void unlock()
306  {
307  recm.unlock();
308  }
309 
315  virtual bool trylock()
316  {
317  return recm.try_lock();
318  }
319 
327  virtual bool timedlock(Seconds s)
328  {
329  return recm.timed_lock( boost::posix_time::microseconds( Seconds_to_nsecs(s)/1000 ) );
330  }
331 #endif
332  };
333 
347  {
348  protected:
349  typedef unsigned int Status;
353 
354  static const Status one_reader = (1 << 0);
355  static const Status one_wait_to_read = (1 << 10);
356  static const Status one_writer = (1 << 20);
357  static const Status status_mask = (1 << 10) - 1;
358 
359  static inline unsigned int readers(Status status) {
360  return (status & status_mask);
361  }
362  static inline unsigned int waitToRead(Status status) {
363  return ((status >> 10) & status_mask);
364  }
365  static inline unsigned int writers(Status status) {
366  return ((status >> 20) & status_mask);
367  }
368 
369  public:
374  : read_semaphore(0)
375  , write_semaphore(0)
376  {
377  ORO_ATOMIC_SETUP( &status, 0 );
378  }
379 
383  virtual ~SharedMutex()
384  {
385  ORO_ATOMIC_CLEANUP( &status );
386  }
387 
388  virtual void lock ()
389  {
390  Status old_status, new_status;
391  do {
392  new_status = old_status = (Status) oro_atomic_read( &status );
393  new_status += one_writer;
394  assert(writers(new_status) > 0); // overflow?
395  } while(!CAS(&status, (int) old_status, (int) new_status));
396 
397  if (readers(old_status) > 0 || writers(old_status) > 0) {
398  write_semaphore.wait();
399  }
400  }
401 
402  virtual void unlock()
403  {
404  Status old_status, new_status;
405  unsigned int wait_to_read = 0;
406  do {
407  new_status = old_status = (Status) oro_atomic_read( &status );
408  assert(readers(old_status) == 0);
409  assert(writers(old_status) > 0);
410  new_status -= one_writer;
411  wait_to_read = waitToRead(old_status);
412  if (wait_to_read > 0) {
413  // all waiting threads can be unblocked
414  new_status = (new_status & (status_mask << 20)) | wait_to_read;
415  }
416  } while(!CAS(&status, (int) old_status, (int) new_status));
417 
418  // Signal threads that have been waiting for a read lock
419  if (wait_to_read > 0) {
420  for(unsigned int i = 0; i < wait_to_read; ++i) read_semaphore.signal();
421  } else
422  // ... or signal a thread that has been waiting for a write lock
423  if (writers(old_status) > 1) {
424  write_semaphore.signal();
425  }
426  }
427 
434  virtual bool trylock()
435  {
436  return false;
437  }
438 
448  virtual bool timedlock(Seconds s)
449  {
450  (void) s;
451  return false;
452  }
453 
457  void lock_shared ()
458  {
459  Status old_status, new_status;
460  do {
461  new_status = old_status = (Status) oro_atomic_read( &status );
462  if (writers(old_status) > 0) {
463  new_status += one_wait_to_read;
464  assert(waitToRead(new_status) > 0); // overflow?
465  } else {
466  new_status += one_reader;
467  assert(readers(new_status) > 0); // overflow?
468  }
469  } while(!CAS(&status, (int) old_status, (int) new_status));
470 
471  // wait until all writers are finished
472  if (writers(old_status) > 0) {
473  read_semaphore.wait();
474  }
475  }
476 
480  virtual void unlock_shared()
481  {
482  Status old_status, new_status;
483  do {
484  new_status = old_status = (Status) oro_atomic_read( &status );
485  assert(readers(old_status) > 0);
486  new_status -= one_reader;
487  } while(!CAS(&status, (int) old_status, (int) new_status));
488 
489  // one writer thread can be unblocked if there are no more readers
490  if (readers(old_status) == 1 && writers(old_status) > 0) {
491  write_semaphore.signal();
492  }
493  }
494 
501  virtual bool trylock_shared()
502  {
503  return false;
504  }
505 
515  virtual bool timedlock_shared(Seconds s)
516  {
517  (void) s;
518  return false;
519  }
520  };
521 
522 }}
523 
524 #endif
virtual bool timedlock(Seconds s)
Lock this mutex, but don&#39;t wait longer for the lock than the specified timeout.
Definition: Mutex.hpp:149
double Seconds
Seconds are stored as a double precision float.
Definition: Time.hpp:53
int rtos_mutex_rec_lock(rt_rec_mutex_t *m)
virtual ~Mutex()
Destroy a Mutex.
Definition: Mutex.hpp:112
rt_mutex_t m
Definition: Mutex.hpp:97
unsigned int Status
Definition: Mutex.hpp:349
oro_atomic_t status
Definition: Mutex.hpp:350
virtual void unlock_shared()
Definition: Mutex.hpp:76
int rtos_mutex_unlock(rt_mutex_t *m)
void signal()
Raise this semaphore and signal one thread waiting on this semaphore.
Definition: Semaphore.hpp:96
int rtos_mutex_rec_init(rt_rec_mutex_t *m)
virtual bool timedlock(Seconds s)
Lock this mutex, but don&#39;t wait longer for the lock than the specified timeout.
Definition: Mutex.hpp:274
virtual void lock_shared()
Definition: Mutex.hpp:75
int rtos_mutex_rec_trylock(rt_rec_mutex_t *m)
An object oriented wrapper around a counting semaphore.
Definition: Semaphore.hpp:61
int rtos_mutex_rec_trylock_for(rt_rec_mutex_t *m, NANO_TIME relative_time)
virtual void unlock()
Definition: Mutex.hpp:250
virtual bool trylock()
Try to lock this mutex.
Definition: Mutex.hpp:135
#define RTT_API
Definition: rtt-config.h:97
An object oriented wrapper around a condition variable.
Definition: Condition.hpp:60
virtual void lock()
Definition: Mutex.hpp:388
virtual ~SharedMutex()
Destroy a shared Mutex.
Definition: Mutex.hpp:383
virtual void unlock_shared()
Release shared ownership of this mutex.
Definition: Mutex.hpp:480
static unsigned int waitToRead(Status status)
Definition: Mutex.hpp:362
int oro_atomic_read(oro_atomic_t *a)
Returns the current counter value of the atomic structure a.
static unsigned int writers(Status status)
Definition: Mutex.hpp:365
virtual bool timedlock_shared(Seconds)
Definition: Mutex.hpp:78
virtual bool trylock_shared()
Attempt to obtain shared ownership of this mutex.
Definition: Mutex.hpp:501
int rtos_mutex_rec_unlock(rt_rec_mutex_t *m)
virtual ~MutexRecursive()
Destroy a MutexRecursive.
Definition: Mutex.hpp:237
void wait()
Lower this semaphore and return if value() is non zero.
Definition: Semaphore.hpp:87
bool CAS(volatile T *addr, const V &expected, const W &value)
Compare And Swap.
Definition: CAS.hpp:54
void ORO_ATOMIC_SETUP(oro_atomic_t *a, int n)
Initializes the uninitialized atomic structure a with a counter value of &#39;n&#39;.
Semaphore write_semaphore
Definition: Mutex.hpp:352
void lock_shared()
Obtain shared ownership of this mutex.
Definition: Mutex.hpp:457
int rtos_mutex_lock(rt_mutex_t *m)
void ORO_ATOMIC_CLEANUP(oro_atomic_t *a)
Cleans up all resources allocated durint the setup of atomic structure a.
An object oriented wrapper around a shared mutex (multiple readers allowed, but only one writer with ...
Definition: Mutex.hpp:346
virtual void unlock()
Definition: Mutex.hpp:402
int rtos_mutex_init(rt_mutex_t *m)
virtual void lock()
Definition: Mutex.hpp:120
int rtos_mutex_destroy(rt_mutex_t *m)
rt_rec_mutex_t recm
Definition: Mutex.hpp:222
virtual bool trylock()
Try to lock this mutex exclusively.
Definition: Mutex.hpp:434
virtual bool timedlock(Seconds s)
Lock this mutex exclusively, but don&#39;t wait longer for the lock than the specified timeout...
Definition: Mutex.hpp:448
int rtos_mutex_trylock(rt_mutex_t *m)
nsecs Seconds_to_nsecs(const Seconds s)
Definition: Time.hpp:107
virtual bool timedlock_shared(Seconds s)
Attempt to obtain shared ownership of this mutex, but don&#39;t wait longer for the lock than the specifi...
Definition: Mutex.hpp:515
virtual bool trylock_shared()
Definition: Mutex.hpp:77
static unsigned int readers(Status status)
Definition: Mutex.hpp:359
An object oriented wrapper around a non recursive mutex.
Definition: Mutex.hpp:92
virtual void unlock()
Definition: Mutex.hpp:125
Contains TaskContext, Activity, OperationCaller, Operation, Property, InputPort, OutputPort, Attribute.
Definition: Activity.cpp:52
An object oriented wrapper around a recursive mutex.
Definition: Mutex.hpp:218
int rtos_mutex_trylock_for(rt_mutex_t *m, NANO_TIME relative_time)
Mutex()
Initialize a Mutex.
Definition: Mutex.hpp:102
virtual bool trylock()
Try to lock this mutex.
Definition: Mutex.hpp:260
MutexRecursive()
Initialize a recursive Mutex.
Definition: Mutex.hpp:227
virtual ~MutexInterface()
Definition: Mutex.hpp:70
An interface to a Mutex.
Definition: Mutex.hpp:67
Structure that contains an int for atomic operations.
Definition: oro_arch.h:10
SharedMutex()
Initialize a shared Mutex.
Definition: Mutex.hpp:373
int rtos_mutex_rec_destroy(rt_rec_mutex_t *m)
Semaphore read_semaphore
Definition: Mutex.hpp:351
cyg_mutex_t rt_mutex_t
Definition: fosi.h:185