~ubuntu-branches/ubuntu/trusty/hugin/trusty-proposed

« back to all changes in this revision

Viewing changes to src/foreign/zthread/src/RecursiveMutexImpl.cxx

  • Committer: Bazaar Package Importer
  • Author(s): Andreas Metzler
  • Date: 2011-01-06 14:28:24 UTC
  • mfrom: (1.1.9 upstream) (0.1.21 experimental)
  • Revision ID: james.westby@ubuntu.com-20110106142824-zn9lxylg5z44dynn
* Drop Cyril Brulebois from Uploaders. Thank you very much for your work.
* Bump package version. (rc3 was re-released as 2010.4.0).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2005, Eric Crahen
 
3
 *
 
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:
 
10
 *
 
11
 * The above copyright notice and this permission notice shall be included in all
 
12
 * copies or substantial portions of the Software.
 
13
 *
 
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.
 
20
 *
 
21
 */
 
22
 
 
23
#include "Debug.h"
 
24
 
 
25
#include "RecursiveMutexImpl.h"
 
26
#include "ThreadImpl.h"
 
27
 
 
28
#include "zthread/Guard.h"
 
29
 
 
30
#include <assert.h>
 
31
#include <errno.h>
 
32
#include <algorithm>
 
33
 
 
34
namespace ZThread {
 
35
 
 
36
  /**
 
37
   * Create a new RecursiveMutexImpl
 
38
   *
 
39
   * @exception Initialization_Exception thrown if resources could not be
 
40
   * properly allocated
 
41
   */
 
42
  RecursiveMutexImpl::RecursiveMutexImpl() 
 
43
    : _owner(0), _count(0) {
 
44
 
 
45
  }
 
46
 
 
47
  /**
 
48
   * Destroy this RecursiveMutexImpl and release its resources
 
49
   */
 
50
  RecursiveMutexImpl::~RecursiveMutexImpl() {
 
51
 
 
52
#ifndef NDEBUG
 
53
 
 
54
    // It is an error to destroy a mutex that has not been released
 
55
    if(_owner != 0) { 
 
56
 
 
57
      ZTDEBUG("** You are destroying a mutex which was never released. **\n");
 
58
      assert(0); // Destroyed mutex while in use
 
59
 
 
60
    }
 
61
 
 
62
    if(_waiters.size() > 0) { 
 
63
 
 
64
      ZTDEBUG("** You are destroying a mutex which is blocking %d threads. **\n", _waiters.size());
 
65
      assert(0); // Destroyed mutex while in use
 
66
 
 
67
    }
 
68
 
 
69
#endif
 
70
 
 
71
  }
 
72
 
 
73
 
 
74
  void RecursiveMutexImpl::acquire() {
 
75
 
 
76
    // Get the monitor for the current thread
 
77
    Monitor& m = ThreadImpl::current()->getMonitor();
 
78
    Monitor::STATE state;
 
79
 
 
80
    Guard<FastLock> g1(_lock);
 
81
      
 
82
    // If there is an entry count and the current thread is 
 
83
    // the owner, increment the count and continue.
 
84
    if(_owner == &m) 
 
85
      _count++;
 
86
 
 
87
    else {
 
88
 
 
89
      // Acquire the lock if it is free and there are no waiting threads
 
90
      if(_owner == 0 && _waiters.empty()) {
 
91
 
 
92
        assert(_count == 0);
 
93
 
 
94
        _owner = &m;    
 
95
        _count++;
 
96
 
 
97
      } else { // Otherwise, wait()
 
98
        
 
99
        _waiters.push_back(&m);
 
100
 
 
101
        m.acquire();
 
102
 
 
103
        {
 
104
 
 
105
          Guard<FastLock, UnlockedScope> g2(g1);
 
106
          state = m.wait();
 
107
 
 
108
        }
 
109
 
 
110
        m.release();
 
111
        
 
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
 
115
        // been called.
 
116
        List::iterator i = std::find(_waiters.begin(), _waiters.end(), &m);
 
117
        if(i != _waiters.end())
 
118
          _waiters.erase(i);
 
119
 
 
120
        // If awoke due to a notify(), take ownership. 
 
121
        switch(state) {
 
122
          case Monitor::SIGNALED:
 
123
          
 
124
            assert(_owner == 0);
 
125
            assert(_count == 0);
 
126
 
 
127
            _owner = &m;
 
128
            _count++;
 
129
            
 
130
            break;
 
131
 
 
132
          case Monitor::INTERRUPTED:
 
133
            throw Interrupted_Exception();
 
134
            
 
135
          default:
 
136
            throw Synchronization_Exception();
 
137
        } 
 
138
            
 
139
      }
 
140
      
 
141
    }
 
142
 
 
143
  }
 
144
 
 
145
  bool RecursiveMutexImpl::tryAcquire(unsigned long timeout) {
 
146
  
 
147
    // Get the monitor for the current thread
 
148
    Monitor& m = ThreadImpl::current()->getMonitor();
 
149
 
 
150
    Guard<FastLock> g1(_lock);
 
151
  
 
152
    // If there is an entry count and the current thread is 
 
153
    // the owner, increment the count and continue.
 
154
    if(_owner == &m)
 
155
      _count++;
 
156
 
 
157
    else {
 
158
 
 
159
      // Acquire the lock if it is free and there are no waiting threads
 
160
      if(_owner == 0 && _waiters.empty()) {
 
161
 
 
162
        assert(_count == 0);
 
163
 
 
164
        _owner = &m;
 
165
        _count++;
 
166
 
 
167
      } else { // Otherwise, wait()
 
168
 
 
169
        _waiters.push_back(&m);
 
170
 
 
171
        Monitor::STATE state = Monitor::TIMEDOUT;
 
172
 
 
173
        // Don't bother waiting if the timeout is 0
 
174
        if(timeout) {
 
175
 
 
176
          m.acquire();
 
177
 
 
178
          {
 
179
          
 
180
            Guard<FastLock, UnlockedScope> g2(g1);
 
181
            state = m.wait(timeout);
 
182
          
 
183
          }
 
184
 
 
185
          m.release();
 
186
        
 
187
        }
 
188
 
 
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
 
192
        // been called.
 
193
        List::iterator i = std::find(_waiters.begin(), _waiters.end(), &m);
 
194
        if(i != _waiters.end())
 
195
          _waiters.erase(i);
 
196
 
 
197
        // If awoke due to a notify(), take ownership. 
 
198
        switch(state) {
 
199
          case Monitor::SIGNALED:
 
200
 
 
201
            assert(_count == 0);
 
202
            assert(_owner == 0);
 
203
 
 
204
            _owner = &m;
 
205
            _count++;
 
206
            
 
207
            break;
 
208
 
 
209
          case Monitor::INTERRUPTED:
 
210
            throw Interrupted_Exception();
 
211
          
 
212
          case Monitor::TIMEDOUT:
 
213
            return false;
 
214
 
 
215
          default:
 
216
            throw Synchronization_Exception();
 
217
        } 
 
218
            
 
219
      }
 
220
      
 
221
    }
 
222
 
 
223
    return true;
 
224
 
 
225
  }
 
226
 
 
227
  void RecursiveMutexImpl::release() {
 
228
 
 
229
    // Get the monitor for the current thread
 
230
    Monitor& m = ThreadImpl::current()->getMonitor();
 
231
 
 
232
    Guard<FastLock> g1(_lock);
 
233
 
 
234
    // Make sure the operation is valid
 
235
    if(!(_owner == &m))
 
236
      throw InvalidOp_Exception();
 
237
 
 
238
    // Update the count, if it has reached 0, wake another waiter.
 
239
    if(--_count == 0) {
 
240
    
 
241
      _owner = 0;
 
242
 
 
243
      // Try to find a waiter with a backoff & retry scheme
 
244
      for(;;) {
 
245
 
 
246
        // Go through the list, attempt to notify() a waiter.
 
247
        for(List::iterator i = _waiters.begin(); i != _waiters.end();) {
 
248
        
 
249
          // Try the monitor lock, if it cant be locked skip to the next waiter
 
250
          Monitor* n = *i;
 
251
          if(n->tryAcquire()) {
 
252
           
 
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();
 
256
            n->release();
 
257
          
 
258
            // Once notify() succeeds, return
 
259
            if(woke)
 
260
              return;
 
261
          
 
262
          } else ++i;
 
263
        
 
264
        }
 
265
      
 
266
        if(_waiters.empty())
 
267
          return;
 
268
 
 
269
        { // Backoff and try again
 
270
 
 
271
          Guard<FastLock, UnlockedScope> g2(g1);
 
272
          ThreadImpl::yield();
 
273
 
 
274
        }
 
275
 
 
276
      }
 
277
 
 
278
    }
 
279
  
 
280
  }
 
281
 
 
282
} // namespace ZThread
 
283
 
 
284
 
 
285
 
 
286