source: Sophya/trunk/SophyaExt/JThreadsC++/JTCSrc/Cond.cpp

Last change on this file was 1016, checked in by ansari, 25 years ago

Creation du module JThreadsC++, importation du code des classes
de Thread a la Java de Object Oriented Concepts Inc - Reza 19/5/2000

File size: 8.0 KB
Line 
1// **********************************************************************
2//
3// Copyright (c) 2000
4// Object Oriented Concepts, Inc.
5// Billerica, MA, USA
6//
7// All Rights Reserved
8//
9// **********************************************************************
10
11#include <JTC/Types.h>
12#include <JTC/Syscall.h>
13#include <JTC/Mutex.h>
14#include <JTC/Event.h>
15#include <JTC/Cond.h>
16#include <JTC/Handle.h>
17#include <JTC/HandleI.h>
18#include <JTC/Thread.h>
19#include <JTC/Monitor.h>
20#include <JTC/ThreadGroup.h>
21#include <JTC/Runnable.h>
22#include <JTC/Sync.h>
23
24#include <errno.h>
25
26#if defined(HAVE_POSIX_THREADS)
27#include <unistd.h>
28#include <sys/time.h>
29#endif
30
31#ifdef HAVE_STD_IOSTREAM
32using namespace std;
33#endif
34
35#ifndef WIN32
36//
37// This helper class is used to re-acquire the the recursive mutex.
38// It's in place to help with robustness in the event of
39// pthread_cancel.
40//
41class JTCCondHelper
42{
43 JTCRecursiveMutex& mut_;
44 int count_;
45
46public:
47
48 JTCCondHelper(JTCRecursiveMutex& m,
49 int c)
50 : mut_(m), count_(c)
51 {
52 }
53
54 ~JTCCondHelper()
55 {
56 //
57 // We need to acquire the mutex rationally... We unlock the
58 // mutexes critical section, and lock the mutex. Restore
59 // saved information. NOTE: It's not correct to set the count
60 // and the owner of the mutex, the lock API method MUST be
61 // called.
62 //
63 pthread_mutex_unlock(&mut_.crit_);
64 mut_.lock(count_);
65 }
66};
67#endif
68
69// ----------------------------------------------------------------------
70// JTCCond private member implementation
71// ----------------------------------------------------------------------
72
73//
74// Wait for the condition variable to be signalled. The posix threads
75// and NT threads implementation are essentially the same, except that
76// the NT threads implementation uses an NT semaphore instead of a
77// native condition variable.
78//
79// A timeout value of -1 means wait forever. Otherwise, only wait for
80// timeout milliseconds.
81//
82void
83JTCCond::_wait(long timeout)
84{
85#if defined(HAVE_POSIX_THREADS) || defined(HAVE_DCE_THREADS)
86 //
87 // The mutex is locked at this point. We need to acquire internal,
88 // save count. The cond_wait will unlock the mutexes critical
89 // section.
90 //
91 // To see that this code is correct, consider the following cases:
92 //
93 // - If no thread is currently attempting to lock the mutex then code
94 // code is correct.
95 //
96 // - If another thread is attempting to unlock the mutex the
97 // application is in error, since the thread calling wait owns the
98 // mutex.
99 //
100 // - If thread B is attempting to lock the mutex, while thread A
101 // is calling wait then the following cases need to be considered:
102 //
103 // - Thread B obtains lock on internal first. The mutex count
104 // will be 0, the owner will be nullThreadId. (set below)
105 // Thread B unlocks internal. Thread A can now obtain it's lock
106 // on internal. It locks internal, discovers count is 0,
107 // increments count, sets owner, and attempts to lock
108 // crit_. This lock cannot proceed until pthread_cond_wait below
109 // is called.
110 //
111 // - Thread A obtains lock on internal first. Count is non-zero,
112 // and thread A does not own the mutex. Thread A attempts to
113 // lock crit_, which blocks until pthread_cond_wait below is
114 // called.
115 //
116
117 int count;
118 {
119 JTCSynchronized guard(mutex_.internal_);
120
121 //
122 // Save internal state information to be restored on method
123 // exit.
124 //
125 count = mutex_.count_;
126 mutex_.count_ = 0;
127 mutex_.owner_ = JTCThreadId();
128 }
129
130 //
131 // Calculate the timeout period.
132 //
133 struct timespec abstime;
134 if(timeout >= 0)
135 {
136 struct timeval tv;
137 gettimeofday(&tv, 0);
138 //123456789 - 10^9
139 const long oneBillion = 1000000000;
140 abstime.tv_sec = tv.tv_sec + (timeout/1000);
141 abstime.tv_nsec = (tv.tv_usec * 1000) + ((timeout%1000) * 1000000);
142 if(abstime.tv_nsec > oneBillion)
143 {
144 ++abstime.tv_sec;
145 abstime.tv_nsec -= oneBillion;
146 }
147 }
148
149 try
150 {
151 JTCCondHelper unlock(mutex_, count);
152
153 if(timeout < 0)
154 {
155 JTC_SYSCALL_2(pthread_cond_wait, &cond_, &mutex_.crit_, < 0);
156 }
157 else
158 {
159 JTC_SYSCALL_3(pthread_cond_timedwait, &cond_, &mutex_.crit_,
160 &abstime, < 0);
161 }
162 }
163 catch(const JTCSystemCallException& e)
164 {
165 //
166 // EINTR is translated to InterruptedException.
167 //
168 if(e.getError() == EINTR)
169 throw JTCInterruptedException();
170 //
171 // EAGAIN means that the wait time has passed.
172 //
173 else if (e.getError() == EAGAIN)
174 return;
175
176 //
177 // Rethrow caught exception.
178 //
179 throw;
180 }
181
182#endif
183#if defined(HAVE_WIN32_THREADS)
184
185 {
186 JTCSynchronized guard(waitersMutex_);
187 //
188 // mutex_ is locked on entry.
189 //
190 ++waiters_;
191 }
192
193 int count;
194
195 if(timeout < 0)
196 timeout = INFINITE;
197
198 //
199 // Save state information.
200 //
201 {
202 JTCSynchronized guard(mutex_.internal_);
203
204 count = mutex_.count_;
205 mutex_.count_ = 0;
206 mutex_.owner_ = JTCThreadId();
207 LeaveCriticalSection(&mutex_.crit_);
208 }
209
210 try
211 {
212 JTC_SYSCALL_2(WaitForSingleObject, sema_, timeout, == WAIT_ABANDONED);
213 }
214 catch(const JTCSystemCallException&)
215 {
216 //
217 // Restore the mutex lock count times.
218 //
219 {
220 JTCSynchronized guard(waitersMutex_);
221 --waiters_;
222 }
223 mutex_.lock(count);
224 throw;
225 }
226
227 //
228 // Restore the mutex lock count times.
229 //
230 {
231 JTCSynchronized guard(waitersMutex_);
232 --waiters_;
233 if (waiters_ == 0 && haveBroadcast_)
234 broadcastEvent_.post();
235 }
236 mutex_.lock(count);
237#endif
238}
239
240
241// ----------------------------------------------------------------------
242// JTCCond constructor and destructor
243// ----------------------------------------------------------------------
244
245JTCCond::JTCCond(JTCRecursiveMutex& mut)
246 : mutex_(mut)
247{
248#if defined(HAVE_POSIX_THREADS)
249 JTC_SYSCALL_2(pthread_cond_init, &cond_, 0, != 0)
250#endif
251#if defined(HAVE_DCE_THREADS)
252 JTC_SYSCALL_2(pthread_cond_init, &cond_, pthread_condattr_default, != 0)
253#endif
254#if defined(HAVE_WIN32_THREADS)
255 haveBroadcast_ = false;
256 waiters_ = 0;
257 JTC_SYSCALL_4(sema_ = CreateSemaphore, 0, 0, 0x7fffffff, 0, == INVALID_HANDLE_VALUE)
258#endif
259}
260
261JTCCond::~JTCCond()
262{
263#if defined(HAVE_POSIX_THREADS) || defined(HAVE_DCE_THREADS)
264 pthread_cond_destroy(&cond_);
265#endif
266#if defined(HAVE_WIN32_THREADS)
267 CloseHandle(sema_);
268#endif
269}
270
271// ----------------------------------------------------------------------
272// JTCMonitor public member implementation
273// ----------------------------------------------------------------------
274
275//
276// Wait to be signalled for timeout milliseconds.
277//
278void
279JTCCond::wait(long timeout)
280{
281 if(timeout < 0)
282 throw JTCIllegalArgumentException("timeout value is negative");
283 _wait(timeout);
284}
285
286//
287// Wait to be signalled.
288//
289void
290JTCCond::wait()
291{
292 _wait(-1);
293}
294
295//
296// Wake one waiting thread.
297//
298void
299JTCCond::signal()
300{
301#if defined(HAVE_POSIX_THREADS) || defined(HAVE_DCE_THREADS)
302 JTC_SYSCALL_1(pthread_cond_signal,&cond_, != 0)
303#endif
304#if defined(HAVE_WIN32_THREADS)
305 bool haveWaiters;
306 {
307 JTCSynchronized guard(waitersMutex_);
308 haveWaiters = (waiters_ > 0);
309 }
310 if (haveWaiters)
311 {
312 JTC_SYSCALL_3(ReleaseSemaphore, sema_, 1, 0, == 0)
313 }
314#endif
315}
316
317//
318// Wake all waiting threads.
319//
320void
321JTCCond::broadcast()
322{
323#if defined(HAVE_POSIX_THREADS) || defined(HAVE_DCE_THREADS)
324 JTC_SYSCALL_1(pthread_cond_broadcast,&cond_, != 0)
325#endif
326#if defined(HAVE_WIN32_THREADS)
327 bool haveWaiters;
328 int numWaiters;
329 {
330 JTCSynchronized guard(waitersMutex_);
331 haveWaiters = (waiters_ > 0);
332 numWaiters = waiters_;
333 }
334 if (haveWaiters)
335 {
336 //
337 // This is a broadcast event, so set the flag and reset
338 // the Event synchronization object.
339 //
340 haveBroadcast_ = true;
341 broadcastEvent_.reset();
342
343 //
344 // Release the semaphore waiters_ times.
345 //
346 JTC_SYSCALL_3(ReleaseSemaphore, sema_, numWaiters, 0, == 0)
347
348 //
349 // Wait for each thread to wake.
350 // After reset the haveBroadcast_ flag.
351 //
352 broadcastEvent_.wait();
353 haveBroadcast_ = false;
354 }
355#endif
356}
Note: See TracBrowser for help on using the repository browser.