diff options
Diffstat (limited to 'cpp/src/Ice/CountDownLatch.cpp')
-rw-r--r-- | cpp/src/Ice/CountDownLatch.cpp | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/cpp/src/Ice/CountDownLatch.cpp b/cpp/src/Ice/CountDownLatch.cpp new file mode 100644 index 00000000000..cbdd4d5bcf2 --- /dev/null +++ b/cpp/src/Ice/CountDownLatch.cpp @@ -0,0 +1,184 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2016 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +#include <IceUtil/CountDownLatch.h> +#include <IceUtil/ThreadException.h> + +IceUtilInternal::CountDownLatch::CountDownLatch(int count) : + _count(count) +{ + if(count < 0) + { + throw IceUtil::Exception(__FILE__, __LINE__); + } + +#ifdef _WIN32 +# ifndef ICE_OS_WINRT + _event = CreateEvent(0, TRUE, FALSE, 0); +# else + _event = CreateEventExW(0, 0, CREATE_EVENT_MANUAL_RESET, SEMAPHORE_ALL_ACCESS); +# endif + if(_event == 0) + { + throw IceUtil::ThreadSyscallException(__FILE__, __LINE__, GetLastError()); + } +#else + int rc = pthread_mutex_init(&_mutex, 0); + if(rc != 0) + { + throw IceUtil::ThreadSyscallException(__FILE__, __LINE__, rc); + } + + rc = pthread_cond_init(&_cond, 0); + if(rc != 0) + { + throw IceUtil::ThreadSyscallException(__FILE__, __LINE__, rc); + } +#endif +} + +IceUtilInternal::CountDownLatch::~CountDownLatch() +{ +#ifdef _WIN32 + CloseHandle(_event); +#else +# ifndef NDEBUG + int rc = pthread_mutex_destroy(&_mutex); + assert(rc == 0); + rc = pthread_cond_destroy(&_cond); + assert(rc == 0); +# else + pthread_mutex_destroy(&_mutex); + pthread_cond_destroy(&_cond); +# endif +#endif +} + +void +IceUtilInternal::CountDownLatch::await() const +{ +#ifdef _WIN32 + while(InterlockedExchangeAdd(&_count, 0) > 0) + { +# ifndef ICE_OS_WINRT + DWORD rc = WaitForSingleObject(_event, INFINITE); +# else + DWORD rc = WaitForSingleObjectEx(_event, INFINITE, false); +# endif + assert(rc == WAIT_OBJECT_0 || rc == WAIT_FAILED); + + if(rc == WAIT_FAILED) + { + throw IceUtil::ThreadSyscallException(__FILE__, __LINE__, GetLastError()); + } + } +#else + lock(); + while(_count > 0) + { + int rc = pthread_cond_wait(&_cond, &_mutex); + if(rc != 0) + { + pthread_mutex_unlock(&_mutex); + throw IceUtil::ThreadSyscallException(__FILE__, __LINE__, rc); + } + } + unlock(); + +#endif +} + +void +IceUtilInternal::CountDownLatch::countDown() +{ +#ifdef _WIN32 + if(InterlockedDecrement(&_count) == 0) + { + if(SetEvent(_event) == 0) + { + throw IceUtil::ThreadSyscallException(__FILE__, __LINE__, GetLastError()); + } + } +#else + bool broadcast = false; + + lock(); + if(_count > 0 && --_count == 0) + { + broadcast = true; + } +#if defined(__APPLE__) + // + // On OS X we do the broadcast with the mutex held. This seems to + // be necessary to prevent the broadcast call to hang (spinning in + // an infinite loop). + // + if(broadcast) + { + int rc = pthread_cond_broadcast(&_cond); + if(rc != 0) + { + pthread_mutex_unlock(&_mutex); + throw IceUtil::ThreadSyscallException(__FILE__, __LINE__, rc); + } + } + unlock(); + +#else + unlock(); + + if(broadcast) + { + int rc = pthread_cond_broadcast(&_cond); + if(rc != 0) + { + throw IceUtil::ThreadSyscallException(__FILE__, __LINE__, rc); + } + } +#endif + +#endif +} + +int +IceUtilInternal::CountDownLatch::getCount() const +{ +#ifdef _WIN32 + int count = InterlockedExchangeAdd(&_count, 0); + return count > 0 ? count : 0; +#else + lock(); + int result = _count; + unlock(); + return result; +#endif +} + +#ifndef _WIN32 +void +IceUtilInternal::CountDownLatch::lock() const +{ + int rc = pthread_mutex_lock(&_mutex); + if(rc != 0) + { + throw IceUtil::ThreadSyscallException(__FILE__, __LINE__, rc); + } +} + +void +IceUtilInternal::CountDownLatch::unlock() const +{ + int rc = pthread_mutex_unlock(&_mutex); + if(rc != 0) + { + throw IceUtil::ThreadSyscallException(__FILE__, __LINE__, rc); + } +} + +#endif |