1 ///////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2005, Industrial Light & Magic, a division of Lucas
4 // Digital Ltd. LLC
5 //
6 // All rights reserved.
7 //
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions are
10 // met:
11 // *       Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 // *       Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
16 // distribution.
17 // *       Neither the name of Industrial Light & Magic nor the names of
18 // its contributors may be used to endorse or promote products derived
19 // from this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 //
33 ///////////////////////////////////////////////////////////////////////////
34 
35 //-----------------------------------------------------------------------------
36 //
37 //	class Semaphore -- implementation for for platforms that do
38 //	support Posix threads but do not support Posix semaphores,
39 //	for example, OS X
40 //
41 //-----------------------------------------------------------------------------
42 
43 #include "IlmBaseConfig.h"
44 
45 #if HAVE_PTHREAD && !HAVE_POSIX_SEMAPHORES
46 
47 #include "IlmThreadSemaphore.h"
48 #include "Iex.h"
49 #include <assert.h>
50 
51 namespace IlmThread {
52 
53 
Semaphore(unsigned int value)54 Semaphore::Semaphore (unsigned int value)
55 {
56     if (int error = ::pthread_mutex_init (&_semaphore.mutex, 0))
57         Iex::throwErrnoExc ("Cannot initialize mutex (%T).", error);
58 
59     if (int error = ::pthread_cond_init (&_semaphore.nonZero, 0))
60         Iex::throwErrnoExc ("Cannot initialize condition variable (%T).",
61                             error);
62 
63     _semaphore.count = value;
64     _semaphore.numWaiting = 0;
65 }
66 
67 
~Semaphore()68 Semaphore::~Semaphore ()
69 {
70     int error = ::pthread_cond_destroy (&_semaphore.nonZero);
71     assert (error == 0);
72     error = ::pthread_mutex_destroy (&_semaphore.mutex);
73     assert (error == 0);
74 }
75 
76 
77 void
wait()78 Semaphore::wait ()
79 {
80     ::pthread_mutex_lock (&_semaphore.mutex);
81 
82     _semaphore.numWaiting++;
83 
84     while (_semaphore.count == 0)
85     {
86         if (int error = ::pthread_cond_wait (&_semaphore.nonZero,
87                                              &_semaphore.mutex))
88     {
89             ::pthread_mutex_unlock (&_semaphore.mutex);
90 
91             Iex::throwErrnoExc ("Cannot wait on condition variable (%T).",
92                                 error);
93     }
94     }
95 
96     _semaphore.numWaiting--;
97     _semaphore.count--;
98 
99     ::pthread_mutex_unlock (&_semaphore.mutex);
100 }
101 
102 
103 bool
tryWait()104 Semaphore::tryWait ()
105 {
106     ::pthread_mutex_lock (&_semaphore.mutex);
107 
108     if (_semaphore.count == 0)
109     {
110         ::pthread_mutex_unlock (&_semaphore.mutex);
111         return false;
112     }
113     else
114     {
115         _semaphore.count--;
116         ::pthread_mutex_unlock (&_semaphore.mutex);
117         return true;
118     }
119 }
120 
121 
122 void
post()123 Semaphore::post ()
124 {
125     ::pthread_mutex_lock (&_semaphore.mutex);
126 
127     if (_semaphore.numWaiting > 0)
128     {
129         if (int error = ::pthread_cond_signal (&_semaphore.nonZero))
130     {
131             ::pthread_mutex_unlock (&_semaphore.mutex);
132 
133             Iex::throwErrnoExc ("Cannot signal condition variable (%T).",
134                                 error);
135     }
136     }
137 
138     _semaphore.count++;
139     ::pthread_mutex_unlock (&_semaphore.mutex);
140 }
141 
142 
143 int
value() const144 Semaphore::value () const
145 {
146     ::pthread_mutex_lock (&_semaphore.mutex);
147     int value = _semaphore.count;
148     ::pthread_mutex_unlock (&_semaphore.mutex);
149     return value;
150 }
151 
152 
153 } // namespace IlmThread
154 
155 #endif
156