root/trunk/dep/src/zthread/SemaphoreImpl.h @ 2

Revision 2, 8.6 kB (checked in by yumileroy, 17 years ago)

[svn] * Proper SVN structure

Original author: Neo2003
Date: 2008-10-02 16:23:55-05:00

Line 
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#ifndef __ZTSEMAPHOREIMPL_H__
24#define __ZTSEMAPHOREIMPL_H__
25
26#include "zthread/Guard.h"
27
28#include "Debug.h"
29#include "FastLock.h"
30#include "Scheduling.h"
31
32#include <assert.h>
33
34namespace ZThread {
35
36  class Monitor;
37
38  /**
39   * @class SemaphoreImpl
40   * @author Eric Crahen <http://www.code-foo.com>
41   * @date <2003-07-16T20:03:20-0400>
42   * @version 2.2.11
43   *
44   * The SemaphoreImpl template allows how waiter lists are sorted
45   * to be parameteized
46   */
47  template <typename List> 
48    class SemaphoreImpl {
49
50    //! List of waiting events
51    List _waiters;
52
53    //! Serialize access to this object
54    FastLock _lock;
55
56    //! Current count
57    volatile int _count;
58
59    //! Maximum count if any
60    volatile int _maxCount;
61 
62    //! Flag for bounded or unbounded count
63    volatile bool _checked;
64
65    //! Entry count
66    volatile int _entryCount;
67
68    public:
69   
70 
71    /**
72     * Create a new SemaphoreImpl. Initialzes one pthreads mutex for
73     * internal use.
74     *
75     * @exception Initialization_Exception thrown if resources could not be
76     * properly allocated
77     */
78    SemaphoreImpl(int count, unsigned int maxCount, bool checked) 
79      : _count(count), _maxCount(maxCount), _checked(checked), _entryCount(0) { }
80
81
82    ~SemaphoreImpl();
83
84    void acquire();
85 
86    void release();
87
88    bool tryAcquire(unsigned long timeout);
89 
90    int count();
91
92  }; 
93
94
95  /**
96   * Destroy this SemaphoreImpl and release its resources.
97   */
98  template <typename List> 
99    SemaphoreImpl<List>::~SemaphoreImpl() {
100
101#ifndef NDEBUG
102
103    if(!_waiters.empty()) { 
104
105      ZTDEBUG("** You are destroying a semaphore which is blocking %d threads. **\n", _waiters.size());
106      assert(0); // Destroyed semaphore while in use
107
108    }
109
110#endif
111
112  }
113
114
115  /**
116   * Get the count for the Semaphore
117   *
118   * @return int
119   */
120  template <typename List> 
121    int SemaphoreImpl<List>::count() {
122
123    Guard<FastLock> g(_lock);
124    return _count;
125 
126  }
127
128  /**
129   * Decrement the count, blocking when that count becomes 0 or less.
130   *
131   * @exception Interrupted_Exception thrown when the caller status is interrupted
132   * @exception Synchronization_Exception thrown if there is some other error.
133   */
134  template <typename List> 
135    void SemaphoreImpl<List>::acquire() {
136
137    // Get the monitor for the current thread
138    ThreadImpl* self = ThreadImpl::current();
139    Monitor& m = self->getMonitor();
140
141    Monitor::STATE state;
142
143    Guard<FastLock> g1(_lock);
144
145    // Update the count without waiting if possible.
146    if(_count > 0 && _entryCount == 0)
147      _count--;
148
149    // Otherwise, wait() for the lock by placing the waiter in the list
150    else {
151
152      ++_entryCount;
153      _waiters.insert(self);
154
155      m.acquire();
156
157      {
158     
159        Guard<FastLock, UnlockedScope> g2(g1);
160        state = m.wait();
161     
162      }
163
164      m.release();
165       
166      // Remove from waiter list, regarless of weather release() is called or
167      // not. The monitor is sticky, so its possible a state 'stuck' from a
168      // previous operation and will leave the wait() w/o release() having
169      // been called.
170      typename List::iterator i = std::find(_waiters.begin(), _waiters.end(), self);
171      if(i != _waiters.end())
172        _waiters.erase(i);
173   
174      --_entryCount;
175
176      switch(state) {
177        // If awoke due to a notify(), update the count
178        case Monitor::SIGNALED:
179           
180          _count--;           
181          break;
182           
183        case Monitor::INTERRUPTED:
184          throw Interrupted_Exception();
185           
186        default:
187          throw Synchronization_Exception();
188      } 
189   
190    }
191
192  }
193
194  /**
195   * Decrement the count, blocking when it that count is 0 or less. If the timeout
196   * expires before the count is raise above 0, the thread will stop blocking
197   * and return.
198   *
199   * @exception Interrupted_Exception thrown when the caller status is interrupted
200   * @exception Synchronization_Exception thrown if there is some other error.
201   */
202  template <typename List> 
203    bool SemaphoreImpl<List>::tryAcquire(unsigned long timeout) {
204 
205    // Get the monitor for the current thread
206    ThreadImpl* self = ThreadImpl::current();
207    Monitor& m = self->getMonitor();
208
209    Guard<FastLock> g1(_lock);
210
211    // Update the count without waiting if possible.
212    if(_count > 0 && _entryCount == 0)
213      _count--;
214
215    // Otherwise, wait() for the lock by placing the waiter in the list
216    else {
217   
218      ++_entryCount;
219      _waiters.push_back(self);
220
221      Monitor::STATE state = Monitor::TIMEDOUT;
222
223      // Don't bother waiting if the timeout is 0
224      if(timeout) {
225       
226        m.acquire();
227
228        {
229       
230          Guard<FastLock, UnlockedScope> g2(g1);
231          state = m.wait(timeout);
232       
233        }
234
235        m.release();
236       
237      }
238       
239      // Remove from waiter list, regarless of weather release() is called or
240      // not. The monitor is sticky, so its possible a state 'stuck' from a
241      // previous operation and will leave the wait() w/o release() having
242      // been called.
243      typename List::iterator i = std::find(_waiters.begin(), _waiters.end(), self);
244      if(i != _waiters.end())
245        _waiters.erase(i);
246   
247      --_entryCount;
248
249      switch(state) {
250        // If awoke due to a notify(), update the count
251        case Monitor::SIGNALED:
252           
253          _count--;           
254          break;
255           
256        case Monitor::INTERRUPTED:
257          throw Interrupted_Exception();
258           
259        case Monitor::TIMEDOUT:
260          return false;
261
262        default:
263          throw Synchronization_Exception();
264      } 
265   
266    }
267
268    return true;
269
270  }
271
272  /**
273   * Increment the count and release a waiter if there are any. If the semaphore
274   * is checked, then an exception will be raised if the maximum count is about to
275   * be exceeded.
276   *
277   * @exception InvalidOp_Exception thrown if the maximum count is exceeded while
278   * the checked flag is set.
279   */
280  template <typename List> 
281    void SemaphoreImpl<List>::release()  {
282
283    Guard<FastLock> g1(_lock);
284
285    // Make sure the operation is valid
286    if(_checked && _count == _maxCount) 
287      throw InvalidOp_Exception();
288
289    // Increment the count
290    _count++;
291
292    // Try to find a waiter with a backoff & retry scheme
293    for(;;) {
294   
295      // Go through the list, attempt to notify() a waiter.
296      for(typename List::iterator i = _waiters.begin(); i != _waiters.end();) {
297
298        // Try the monitor lock, if it cant be locked skip to the next waiter
299        ThreadImpl* impl = *i;
300        Monitor& m = impl->getMonitor();
301
302        if(m.tryAcquire()) {
303       
304          // Notify the monitor & remove from the waiter list so time isn't
305          // wasted checking it again.
306          i = _waiters.erase(i);
307       
308          // If notify() is not sucessful, it is because the wait() has already
309          // been ended (killed/interrupted/notify'd)
310          bool woke = m.notify();
311       
312          m.release();
313       
314          // Once notify() succeeds, return
315          if(woke) 
316            return;
317       
318        } else ++i;
319     
320      }
321   
322      if(_waiters.empty())
323        return;
324   
325      { // Backoff and try again
326     
327        Guard<FastLock, UnlockedScope> g2(g1);
328        ThreadImpl::yield();
329
330      }
331
332    }
333 
334  }
335
336  class FifoSemaphoreImpl : public SemaphoreImpl<fifo_list> { 
337  public:
338
339    FifoSemaphoreImpl(int count, unsigned int maxCount, bool checked) 
340      /* throw(Synchronization_Exception) */
341      : SemaphoreImpl<fifo_list>(count, maxCount, checked) { }
342
343  };
344
345
346} // namespace ZThread
347
348#endif //  __ZTSEMAPHOREIMPL_H__
Note: See TracBrowser for help on using the browser.