8
# include <sys/syscall.h>
12
#include "rutil/compat.hxx"
13
#include "rutil/Condition.hxx"
14
#include "rutil/Mutex.hxx"
15
#include "rutil/Timer.hxx"
17
#ifdef _RESIP_MONOTONIC_CLOCK
19
#undef _RESIP_MONOTONIC_CLOCK
20
#warning Mac OS X does not support POSIX monotonic timers.
24
using namespace resip;
26
Condition::Condition()
28
//std::cerr << this << " Condition::Condition" << std::endl;
31
# ifdef RESIP_CONDITION_WIN32_CONFORMANCE_TO_POSIX
35
m_gate = reinterpret_cast<void*>(CreateSemaphore(0, 1, 1, 0));
36
m_queue = reinterpret_cast<void*>(CreateSemaphore(0, 0, LONG_MAX, 0));
37
m_mutex = reinterpret_cast<void*>(CreateMutex(0, 0, 0));
39
if (!m_gate || !m_queue || !m_mutex)
44
res = CloseHandle(reinterpret_cast<HANDLE>(m_gate));
49
res = CloseHandle(reinterpret_cast<HANDLE>(m_queue));
54
res = CloseHandle(reinterpret_cast<HANDLE>(m_mutex));
62
NULL, //LPSECURITY_ATTRIBUTES lpEventAttributes,
63
// pointer to security attributes
64
FALSE, // BOOL bManualReset, // flag for manual-reset event
65
FALSE, //BOOL bInitialState, // flag for initial state
66
NULL //LPCTSTR lpName // pointer to event-object name
71
#ifdef _RESIP_MONOTONIC_CLOCK
72
pthread_condattr_t attr;
73
struct timespec dummy;
74
int ret = pthread_condattr_init( &attr );
77
// if((syscall( __NR_clock_getres, CLOCK_MONOTONIC, &dummy ) == 0) &&
78
if((clock_getres( CLOCK_MONOTONIC, &dummy ) == 0) &&
79
(pthread_condattr_setclock( &attr, CLOCK_MONOTONIC ) == 0))
81
ret = pthread_cond_init( &mId, &attr );
83
pthread_condattr_destroy( &attr );
86
pthread_condattr_destroy( &attr );
88
int rc = pthread_cond_init(&mId,0);
95
Condition::~Condition ()
98
# ifdef RESIP_CONDITION_WIN32_CONFORMANCE_TO_POSIX
100
res = CloseHandle(reinterpret_cast<HANDLE>(m_gate));
102
res = CloseHandle(reinterpret_cast<HANDLE>(m_queue));
104
res = CloseHandle(reinterpret_cast<HANDLE>(m_mutex));
107
BOOL ok = CloseHandle(mId);
111
if (pthread_cond_destroy(&mId) == EBUSY)
118
#if defined(WIN32) && defined(RESIP_CONDITION_WIN32_CONFORMANCE_TO_POSIX)
120
Condition::enterWait ()
123
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
124
assert(res == WAIT_OBJECT_0);
126
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
132
Condition::wait (Mutex& mutex)
134
//std::cerr << "Condition::wait " << mutex << std::endl;
136
# ifdef RESIP_CONDITION_WIN32_CONFORMANCE_TO_POSIX
145
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE);
146
assert(res == WAIT_OBJECT_0);
148
unsigned was_waiting=0;
151
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
152
assert(res == WAIT_OBJECT_0);
153
was_waiting = m_waiting;
155
if (was_waiting != 0)
157
if (--m_waiting == 0)
161
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0); // open m_gate
165
else if (m_gone != 0)
169
else if (++m_gone == (ULONG_MAX / 2))
171
// timeout occured, normalize the m_gone count
172
// this may occur if many calls to wait with a timeout are made and
173
// no call to notify_* is made
174
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
175
assert(res == WAIT_OBJECT_0);
177
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
181
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
184
if (was_waiting == 1)
186
for (/* */ ; was_gone; --was_gone)
188
// better now than spurious later
189
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),
191
assert(res == WAIT_OBJECT_0);
193
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
198
// Reacquire the mutex
202
// FixMe: Race condition between time we get mId and when we
203
// re-acquire the mutex.
205
WaitForSingleObject(mId,INFINITE);
209
int ret = pthread_cond_wait(&mId, mutex.getId());
216
Condition::wait (Mutex* mutex)
222
Condition::wait(Mutex& mutex,
232
# ifdef RESIP_CONDITION_WIN32_CONFORMANCE_TO_POSIX
240
unsigned int res = 0;
242
#if 0 /* unnecessary time stuff - used in BOOST implementation because expiry time is provided to do_timed_wait - we pass in an interval */
243
UInt64 start = Timer::getTimeMs();
247
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),
249
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
250
ret = (res == WAIT_OBJECT_0);
251
if (res == WAIT_TIMEOUT)
253
UInt64 now = Timer::getTimeMs();
254
unsigned int elapsed = (unsigned int)(now - start);
266
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),ms);
267
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
268
ret = (res == WAIT_OBJECT_0);
270
unsigned was_waiting=0;
273
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
274
assert(res == WAIT_OBJECT_0);
275
was_waiting = m_waiting;
277
if (was_waiting != 0)
284
++m_gone; // count spurious wakeups
286
if (--m_waiting == 0)
290
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0); // open m_gate
294
else if (m_gone != 0)
298
else if (++m_gone == (ULONG_MAX / 2))
300
// timeout occured, normalize the m_gone count
301
// this may occur if many calls to wait with a timeout are made and
302
// no call to notify_* is made
303
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
304
assert(res == WAIT_OBJECT_0);
306
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
310
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
313
if (was_waiting == 1)
315
for (/* */ ; was_gone; --was_gone)
317
// better now than spurious later
318
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE);
319
assert(res == WAIT_OBJECT_0);
321
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
325
// Reacquire the mutex
331
// FixMe: Race condition between time we get mId and when we
332
// re-acquire the mutex.
334
// SLG: A Note about the Win32 Implementation of Conditions
336
// I have investigated a fix for this. A solution to this problem is
337
// non-trivial. Please read http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
338
// for a full explanation. This is an implementation of the SetEvent solution
339
// discussed in that article. This solution has the following issues:
340
// 1. Unfairness - ie. First thread to call wait may not be first thread
341
// to be released from condition.
342
// 2. Incorrectness due to a race condition when a broadcast occurs
343
// (see the link for more details on these issues)
345
// There is a solution that corrects these two problem, but also introduces 2 more.
346
// This solution (also discussed in the link) requires the use of a primitive only
347
// available in WinNT and above. It also requires that the Mutex passed in be
348
// implemented using windows Mutexes instead of CriticalSections - they are less
349
// efficient. Thus the problems with this SignalObjectAndWait solution are:
350
// 1. Not portable to all versions of windows - ie. will not work with Win98/Me
351
// 2. Less efficient than tthe SetEvent solution
353
// I have choosen to stick with the SetEvent Solution for the following reasons:
354
// 1. Speed is important.
355
// 2. The Unfairness issue is not really a big problem since the stack currently
356
// does not call a wait function from two different threads. (assuming the
357
// hosting application always calls process() from the same thread). The only
358
// time multi-threading comes into the picture is when the transports queue
359
// messages from the wire onto the stateMacFifo - but they are retrieved off the
360
// Fifo by a single thread.
361
// 3. The Incorrectness issue is also not a big problem, since the stack currently
362
// doesn't use the broadcast member of this class.
364
// Note: The implementation of broadcast remains incomplete - since it is currently
365
// unused and would require an additional CriticalSection Enter and Leave to
366
// keep track of a counter (see the above link for more info). This can be
367
// easily added in the future if required.
369
DWORD ret = WaitForSingleObject(mId, ms);
371
assert(ret != WAIT_FAILED);
372
return (ret == WAIT_OBJECT_0);
375
UInt64 expires64 = Timer::getTimeMs() + ms;
377
expiresTS.tv_sec = expires64 / 1000;
378
expiresTS.tv_nsec = (expires64 % 1000) * 1000000L;
380
assert( expiresTS.tv_nsec < 1000000000L );
382
//std::cerr << "Condition::wait " << mutex << "ms=" << ms << " expire=" << expiresTS.tv_sec << " " << expiresTS.tv_nsec << std::endl;
383
int ret = pthread_cond_timedwait(&mId, mutex.getId(), &expiresTS);
385
if (ret == EINTR || ret == ETIMEDOUT)
391
//std::cerr << this << " pthread_cond_timedwait failed " << ret << " mutex=" << mutex << std::endl;
400
Condition::wait (Mutex* mutex, unsigned int ms)
402
return this->wait(*mutex, ms);
409
# ifdef RESIP_CONDITION_WIN32_CONFORMANCE_TO_POSIX
410
unsigned signals = 0;
413
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
414
assert(res == WAIT_OBJECT_0);
416
if (m_waiting != 0) // the m_gate is already closed
420
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
431
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
432
assert(res == WAIT_OBJECT_0);
433
if (m_blocked > m_gone)
440
signals = m_waiting = 1;
445
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
450
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
455
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals, 0);
460
mId // HANDLE hEvent // handle to event object
465
int ret = pthread_cond_signal(&mId);
473
Condition::broadcast()
476
# ifdef RESIP_CONDITION_WIN32_CONFORMANCE_TO_POSIX
477
unsigned signals = 0;
480
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
481
assert(res == WAIT_OBJECT_0);
483
if (m_waiting != 0) // the m_gate is already closed
487
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
492
m_waiting += (signals = m_blocked);
497
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
498
assert(res == WAIT_OBJECT_0);
499
if (m_blocked > m_gone)
506
signals = m_waiting = m_blocked;
511
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
516
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
521
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals, 0);
528
pthread_cond_broadcast(&mId);
532
/* ====================================================================
533
* The Vovida Software License, Version 1.0
535
* Copyright (c) 2000-2005 Vovida Networks, Inc. All rights reserved.
537
* Redistribution and use in source and binary forms, with or without
538
* modification, are permitted provided that the following conditions
541
* 1. Redistributions of source code must retain the above copyright
542
* notice, this list of conditions and the following disclaimer.
544
* 2. Redistributions in binary form must reproduce the above copyright
545
* notice, this list of conditions and the following disclaimer in
546
* the documentation and/or other materials provided with the
549
* 3. The names "VOCAL", "Vovida Open Communication Application Library",
550
* and "Vovida Open Communication Application Library (VOCAL)" must
551
* not be used to endorse or promote products derived from this
552
* software without prior written permission. For written
553
* permission, please contact vocal@vovida.org.
555
* 4. Products derived from this software may not be called "VOCAL", nor
556
* may "VOCAL" appear in their name, without prior written
557
* permission of Vovida Networks, Inc.
559
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
560
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
561
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
562
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
563
* NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
564
* IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
565
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
566
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
567
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
568
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
569
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
570
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
573
* ====================================================================
575
* This software consists of voluntary contributions made by Vovida
576
* Networks, Inc. and many individuals on behalf of Vovida Networks,
577
* Inc. For more information on Vovida Networks, Inc., please see
578
* <http://www.vovida.org/>.