00001 /******************************************************************************* 00002 * Copyright (C) 2003-2004 Vintela, Inc. All rights reserved. 00003 * 00004 * Redistribution and use in source and binary forms, with or without 00005 * modification, are permitted provided that the following conditions are met: 00006 * 00007 * - Redistributions of source code must retain the above copyright notice, 00008 * this list of conditions and the following disclaimer. 00009 * 00010 * - Redistributions in binary form must reproduce the above copyright notice, 00011 * this list of conditions and the following disclaimer in the documentation 00012 * and/or other materials provided with the distribution. 00013 * 00014 * - Neither the name of Vintela, Inc. nor the names of its 00015 * contributors may be used to endorse or promote products derived from this 00016 * software without specific prior written permission. 00017 * 00018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' 00019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00020 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00021 * ARE DISCLAIMED. IN NO EVENT SHALL Vintela, Inc. OR THE CONTRIBUTORS 00022 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00023 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00024 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00025 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00026 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00027 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00028 * POSSIBILITY OF SUCH DAMAGE. 00029 *******************************************************************************/ 00030 00035 #include "OW_config.h" 00036 #include "OW_ThreadBarrier.hpp" 00037 #include "OW_Assertion.hpp" 00038 #include "OW_Format.hpp" 00039 #include "OW_ExceptionIds.hpp" 00040 #include "OW_IntrusiveCountableBase.hpp" 00041 00042 #if defined(OW_USE_PTHREAD) && defined(OW_HAVE_PTHREAD_BARRIER) && !defined(OW_VALGRIND_SUPPORT) 00043 #include <pthread.h> 00044 #else 00045 // This is for the generic less-efficient version 00046 #include "OW_Condition.hpp" 00047 #include "OW_NonRecursiveMutex.hpp" 00048 #include "OW_NonRecursiveMutexLock.hpp" 00049 #endif 00050 00052 namespace OW_NAMESPACE 00053 { 00054 00055 OW_DEFINE_EXCEPTION_WITH_ID(ThreadBarrier); 00056 00057 #if defined(OW_USE_PTHREAD) && defined(OW_HAVE_PTHREAD_BARRIER) && !defined(OW_VALGRIND_SUPPORT) // valgrind doesn't support pthread_barrier_*() 00058 class ThreadBarrierImpl : public IntrusiveCountableBase 00059 { 00060 public: 00061 ThreadBarrierImpl(UInt32 threshold) 00062 { 00063 OW_ASSERT(threshold != 0); 00064 int res = pthread_barrier_init(&barrier, NULL, threshold); 00065 if (res != 0) 00066 { 00067 OW_THROW(ThreadBarrierException, Format("pthread_barrier_init failed: %1(%2)", res, strerror(res)).c_str()); 00068 } 00069 } 00070 ~ThreadBarrierImpl() 00071 { 00072 int res = pthread_barrier_destroy(&barrier); 00073 if (res != 0) 00074 { 00075 // can't throw... just log it or something... 00076 } 00077 } 00078 00079 void wait() 00080 { 00081 int res = pthread_barrier_wait(&barrier); 00082 if (res != 0 && res != PTHREAD_BARRIER_SERIAL_THREAD) 00083 { 00084 OW_THROW(ThreadBarrierException, Format("pthread_barrier_wait failed: %1(%2)", res, strerror(res)).c_str()); 00085 } 00086 } 00087 private: 00088 pthread_barrier_t barrier; 00089 }; 00090 00091 #else 00092 00093 // This is the generic less-efficient version 00094 00095 class ThreadBarrierImpl : public IntrusiveCountableBase 00096 { 00097 public: 00108 struct SubBarrier 00109 { 00110 SubBarrier() : m_waitingCount(0) {} 00112 UInt32 m_waitingCount; 00114 Condition m_cond; 00115 }; 00116 ThreadBarrierImpl(UInt32 threshold) 00117 : m_threshold(threshold) 00118 , m_curSubBarrier(0) 00119 { 00120 } 00121 void wait() 00122 { 00123 NonRecursiveMutexLock l(m_mutex); 00124 // Select the current SubBarrier 00125 SubBarrier& curBarrier = m_curSubBarrier?m_subBarrier0:m_subBarrier1; 00126 ++curBarrier.m_waitingCount; 00127 if (curBarrier.m_waitingCount == m_threshold) 00128 { 00129 // reset the sub barrier so it can be reused 00130 curBarrier.m_waitingCount = 0; 00131 // swap current barriers 00132 m_curSubBarrier = 1 - m_curSubBarrier; 00133 // now wake up all the threads that were stopped 00134 curBarrier.m_cond.notifyAll(); 00135 } 00136 else 00137 { 00138 // because of spurious wake-ups we need to put this in a loop. 00139 // we need to wait until the count is 0, which will only happen 00140 // once m_threshold threads have called wait() 00141 while (curBarrier.m_waitingCount != 0) 00142 { 00143 curBarrier.m_cond.wait(l); 00144 } 00145 } 00146 } 00147 private: 00149 UInt32 m_threshold; 00152 int m_curSubBarrier; 00153 NonRecursiveMutex m_mutex; 00154 SubBarrier m_subBarrier0; 00155 SubBarrier m_subBarrier1; 00156 }; 00157 00158 #endif 00159 00161 ThreadBarrier::ThreadBarrier(UInt32 threshold) 00162 : m_impl(new ThreadBarrierImpl(threshold)) 00163 { 00164 OW_ASSERT(threshold != 0); 00165 } 00167 void ThreadBarrier::wait() 00168 { 00169 m_impl->wait(); 00170 } 00172 ThreadBarrier::~ThreadBarrier() 00173 { 00174 } 00176 ThreadBarrier::ThreadBarrier(const ThreadBarrier& x) 00177 : m_impl(x.m_impl) 00178 { 00179 } 00181 ThreadBarrier& ThreadBarrier::operator=(const ThreadBarrier& x) 00182 { 00183 m_impl = x.m_impl; 00184 return *this; 00185 } 00186 00187 } // end namespace OW_NAMESPACE 00188