Fawkes API  Fawkes Development Version
spinlock.cpp
1 
2 /***************************************************************************
3  * spinlock.h - Spinlock
4  *
5  * Created: Wed Apr 02 13:20:31 2008
6  * Copyright 2006-2008 Tim Niemueller [www.niemueller.de]
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version. A runtime exception applies to
14  * this software (see LICENSE.GPL_WRE file mentioned below for details).
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Library General Public License for more details.
20  *
21  * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22  */
23 
24 #include <core/threading/spinlock.h>
25 #include <core/threading/thread.h>
26 #include <core/exception.h>
27 
28 #include <pthread.h>
29 #include <unistd.h>
30 
31 // cf. http://people.redhat.com/drepper/posix-option-groups.html
32 #if defined(_POSIX_SPIN_LOCKS) && (_POSIX_SPIN_LOCKS - 200112L) >= 0
33 # define USE_POSIX_SPIN_LOCKS
34 #else
35 # undef USE_POSIX_SPIN_LOCKS
36 # include <core/threading/mutex.h>
37 #endif
38 
39 namespace fawkes {
40 
41 /** @class Spinlock <core/threading/spinlock.h>
42  * Spin lock.
43  * This class is similar to a Mutex in that it is used in a multi-threading
44  * environment to lock access to resources.
45  *
46  * The difference is that the spinlock will do a busy waiting until it acquires
47  * the lock while the mutex would block and wait, and may even starve if another
48  * threads releases a lock only for a short period of time.
49  *
50  * Spinlocks are risky, priority inversion may be caused if used improperly.
51  * Be sure what you are doing if you use spinlocks.
52  *
53  * @ingroup Threading
54  * @ingroup FCL
55  *
56  * @author Tim Niemueller
57  */
58 
59 /// @cond INTERNALS
60 class SpinlockData
61 {
62  public:
63 #ifdef USE_POSIX_SPIN_LOCKS
64  pthread_spinlock_t spinlock;
65 #else
66  Mutex mutex;
67 #endif
68 };
69 /// @endcond
70 
71 
72 /** Constructor */
74 {
75  spinlock_data = new SpinlockData();
76 #ifdef USE_POSIX_SPIN_LOCKS
77  pthread_spin_init(&(spinlock_data->spinlock), PTHREAD_PROCESS_PRIVATE);
78 #endif
79 }
80 
81 /** Destructor */
83 {
84 #ifdef USE_POSIX_SPIN_LOCKS
85  pthread_spin_destroy(&(spinlock_data->spinlock));
86 #endif
87  delete spinlock_data;
88  spinlock_data = NULL;
89 }
90 
91 
92 /** Lock this spinlock.
93  * A call to lock() will block until the lock on the spinlock could be aquired.
94  * If you want to avoid see consider using try_lock().
95  */
96 void
98 {
99 #ifdef USE_POSIX_SPIN_LOCKS
100  int err = 0;
101  if ( (err = pthread_spin_lock(&(spinlock_data->spinlock))) != 0 ) {
102  throw Exception(err, "Failed to aquire lock for thread %s", Thread::current_thread()->name());
103  }
104 #else
105  bool locked = false;
106  while ( ! locked ) {
107  locked = spinlock_data->mutex.try_lock();
108  }
109 #endif
110 }
111 
112 
113 /** Tries to lock the spinlock.
114  * This can also be used to check if a spinlock is locked. The code for this
115  * can be:
116  *
117  * @code
118  * bool locked = false;
119  * if ( spinlock->try_lock() ) {
120  * spinlock->unlock();
121  * locked = true;
122  * }
123  * @endcode
124  *
125  * This cannot be implemented in Spinlock in a locked() method since this
126  * would lead to race conditions in many situations.
127  *
128  * @return true, if the spinlock could be locked, false otherwise.
129  */
130 bool
132 {
133 #ifdef USE_POSIX_SPIN_LOCKS
134  if (pthread_spin_trylock(&(spinlock_data->spinlock)) == 0) {
135  return true;
136  } else {
137  return false;
138  }
139 #else
140  return spinlock_data->mutex.try_lock();
141 #endif
142 }
143 
144 
145 /** Unlock the spinlock. */
146 void
148 {
149 #ifdef USE_POSIX_SPIN_LOCKS
150  pthread_spin_unlock(&(spinlock_data->spinlock));
151 #else
152  spinlock_data->mutex.unlock();
153 #endif
154 }
155 
156 
157 } // end namespace fawkes
Fawkes library namespace.
~Spinlock()
Destructor.
Definition: spinlock.cpp:82
Spinlock()
Constructor.
Definition: spinlock.cpp:73
bool try_lock()
Tries to lock the spinlock.
Definition: spinlock.cpp:131
Base class for exceptions in Fawkes.
Definition: exception.h:36
void unlock()
Unlock the spinlock.
Definition: spinlock.cpp:147
static Thread * current_thread()
Get the Thread instance of the currently running thread.
Definition: thread.cpp:1318
void lock()
Lock this spinlock.
Definition: spinlock.cpp:97