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/exception.h>
25 #include <core/threading/spinlock.h>
26 #include <core/threading/thread.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 /** Constructor */
73 {
74  spinlock_data = new SpinlockData();
75 #ifdef USE_POSIX_SPIN_LOCKS
76  pthread_spin_init(&(spinlock_data->spinlock), PTHREAD_PROCESS_PRIVATE);
77 #endif
78 }
79 
80 /** Destructor */
82 {
83 #ifdef USE_POSIX_SPIN_LOCKS
84  pthread_spin_destroy(&(spinlock_data->spinlock));
85 #endif
86  delete spinlock_data;
87  spinlock_data = NULL;
88 }
89 
90 /** Lock this spinlock.
91  * A call to lock() will block until the lock on the spinlock could be aquired.
92  * If you want to avoid see consider using try_lock().
93  */
94 void
96 {
97 #ifdef USE_POSIX_SPIN_LOCKS
98  int err = 0;
99  if ((err = pthread_spin_lock(&(spinlock_data->spinlock))) != 0) {
100  throw Exception(err, "Failed to aquire lock for thread %s", Thread::current_thread()->name());
101  }
102 #else
103  bool locked = false;
104  while (!locked) {
105  locked = spinlock_data->mutex.try_lock();
106  }
107 #endif
108 }
109 
110 /** Tries to lock the spinlock.
111  * This can also be used to check if a spinlock is locked. The code for this
112  * can be:
113  *
114  * @code
115  * bool locked = false;
116  * if ( spinlock->try_lock() ) {
117  * spinlock->unlock();
118  * locked = true;
119  * }
120  * @endcode
121  *
122  * This cannot be implemented in Spinlock in a locked() method since this
123  * would lead to race conditions in many situations.
124  *
125  * @return true, if the spinlock could be locked, false otherwise.
126  */
127 bool
129 {
130 #ifdef USE_POSIX_SPIN_LOCKS
131  if (pthread_spin_trylock(&(spinlock_data->spinlock)) == 0) {
132  return true;
133  } else {
134  return false;
135  }
136 #else
137  return spinlock_data->mutex.try_lock();
138 #endif
139 }
140 
141 /** Unlock the spinlock. */
142 void
144 {
145 #ifdef USE_POSIX_SPIN_LOCKS
146  pthread_spin_unlock(&(spinlock_data->spinlock));
147 #else
148  spinlock_data->mutex.unlock();
149 #endif
150 }
151 
152 } // end namespace fawkes
fawkes::Spinlock::Spinlock
Spinlock()
Constructor.
Definition: spinlock.cpp:72
fawkes::Thread::current_thread
static Thread * current_thread()
Get the Thread instance of the currently running thread.
Definition: thread.cpp:1366
fawkes::Spinlock::try_lock
bool try_lock()
Tries to lock the spinlock.
Definition: spinlock.cpp:128
fawkes::Spinlock::~Spinlock
~Spinlock()
Destructor.
Definition: spinlock.cpp:81
fawkes
Fawkes library namespace.
fawkes::Spinlock::lock
void lock()
Lock this spinlock.
Definition: spinlock.cpp:95
fawkes::Spinlock::unlock
void unlock()
Unlock the spinlock.
Definition: spinlock.cpp:143
fawkes::Exception
Base class for exceptions in Fawkes.
Definition: exception.h:36