2
* Copyright (c) 2005, Eric Crahen
4
* Permission is hereby granted, free of charge, to any person obtaining a copy
5
* of this software and associated documentation files (the "Software"), to deal
6
* in the Software without restriction, including without limitation the rights
7
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
* copies of the Software, and to permit persons to whom the Software is furnished
9
* to do so, subject to the following conditions:
11
* The above copyright notice and this permission notice shall be included in all
12
* copies or substantial portions of the Software.
14
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
#include "RecursiveMutexImpl.h"
26
#include "ThreadImpl.h"
28
#include "zthread/Guard.h"
37
* Create a new RecursiveMutexImpl
39
* @exception Initialization_Exception thrown if resources could not be
42
RecursiveMutexImpl::RecursiveMutexImpl()
43
: _owner(0), _count(0) {
48
* Destroy this RecursiveMutexImpl and release its resources
50
RecursiveMutexImpl::~RecursiveMutexImpl() {
54
// It is an error to destroy a mutex that has not been released
57
ZTDEBUG("** You are destroying a mutex which was never released. **\n");
58
assert(0); // Destroyed mutex while in use
62
if(_waiters.size() > 0) {
64
ZTDEBUG("** You are destroying a mutex which is blocking %d threads. **\n", _waiters.size());
65
assert(0); // Destroyed mutex while in use
74
void RecursiveMutexImpl::acquire() {
76
// Get the monitor for the current thread
77
Monitor& m = ThreadImpl::current()->getMonitor();
80
Guard<FastLock> g1(_lock);
82
// If there is an entry count and the current thread is
83
// the owner, increment the count and continue.
89
// Acquire the lock if it is free and there are no waiting threads
90
if(_owner == 0 && _waiters.empty()) {
97
} else { // Otherwise, wait()
99
_waiters.push_back(&m);
105
Guard<FastLock, UnlockedScope> g2(g1);
112
// Remove from waiter list, regarless of weather release() is called or
113
// not. The monitor is sticky, so its possible a state 'stuck' from a
114
// previous operation and will leave the wait() w/o release() having
116
List::iterator i = std::find(_waiters.begin(), _waiters.end(), &m);
117
if(i != _waiters.end())
120
// If awoke due to a notify(), take ownership.
122
case Monitor::SIGNALED:
132
case Monitor::INTERRUPTED:
133
throw Interrupted_Exception();
136
throw Synchronization_Exception();
145
bool RecursiveMutexImpl::tryAcquire(unsigned long timeout) {
147
// Get the monitor for the current thread
148
Monitor& m = ThreadImpl::current()->getMonitor();
150
Guard<FastLock> g1(_lock);
152
// If there is an entry count and the current thread is
153
// the owner, increment the count and continue.
159
// Acquire the lock if it is free and there are no waiting threads
160
if(_owner == 0 && _waiters.empty()) {
167
} else { // Otherwise, wait()
169
_waiters.push_back(&m);
171
Monitor::STATE state = Monitor::TIMEDOUT;
173
// Don't bother waiting if the timeout is 0
180
Guard<FastLock, UnlockedScope> g2(g1);
181
state = m.wait(timeout);
189
// Remove from waiter list, regarless of weather release() is called or
190
// not. The monitor is sticky, so its possible a state 'stuck' from a
191
// previous operation and will leave the wait() w/o release() having
193
List::iterator i = std::find(_waiters.begin(), _waiters.end(), &m);
194
if(i != _waiters.end())
197
// If awoke due to a notify(), take ownership.
199
case Monitor::SIGNALED:
209
case Monitor::INTERRUPTED:
210
throw Interrupted_Exception();
212
case Monitor::TIMEDOUT:
216
throw Synchronization_Exception();
227
void RecursiveMutexImpl::release() {
229
// Get the monitor for the current thread
230
Monitor& m = ThreadImpl::current()->getMonitor();
232
Guard<FastLock> g1(_lock);
234
// Make sure the operation is valid
236
throw InvalidOp_Exception();
238
// Update the count, if it has reached 0, wake another waiter.
243
// Try to find a waiter with a backoff & retry scheme
246
// Go through the list, attempt to notify() a waiter.
247
for(List::iterator i = _waiters.begin(); i != _waiters.end();) {
249
// Try the monitor lock, if it cant be locked skip to the next waiter
251
if(n->tryAcquire()) {
253
// If notify() is not sucessful, it is because the wait() has already
254
// been ended (killed/interrupted/notify'd)
255
bool woke = n->notify();
258
// Once notify() succeeds, return
269
{ // Backoff and try again
271
Guard<FastLock, UnlockedScope> g2(g1);
282
} // namespace ZThread