/* +----------------------------------------------------------------------+ | HipHop for PHP | +----------------------------------------------------------------------+ | Copyright (c) 2010-2013 Facebook, Inc. (http://www.facebook.com) | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | | available through the world-wide-web at the following url: | | http://www.php.net/license/3_01.txt | | If you did not receive a copy of the PHP license and are unable to | | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ */ #include "hphp/util/synchronizable_multi.h" #include "hphp/util/compatibility.h" #include "hphp/util/timer.h" namespace HPHP { /////////////////////////////////////////////////////////////////////////////// SynchronizableMulti::SynchronizableMulti(int size) : m_mutex(RankLeaf) { assert(size > 0); m_conds.resize(size); for (unsigned int i = 0; i < m_conds.size(); i++) { pthread_cond_init(&m_conds[i], nullptr); } } SynchronizableMulti::~SynchronizableMulti() { for (unsigned int i = 0; i < m_conds.size(); i++) { pthread_cond_destroy(&m_conds[i]); } } void SynchronizableMulti::wait(int id, bool front) { waitImpl(id, front, nullptr); } bool SynchronizableMulti::wait(int id, bool front, long seconds) { return wait(id, front, seconds, 0); } bool SynchronizableMulti::wait(int id, bool front, long seconds, long long nanosecs) { struct timespec ts; Timer::GetRealtimeTime(ts); ts.tv_sec += seconds; ts.tv_nsec += nanosecs; return waitImpl(id, front, &ts); } bool SynchronizableMulti::waitImpl(int id, bool front, timespec *ts) { assert(id >= 0); int index = id % m_conds.size(); pthread_cond_t *cond = &m_conds[index]; if (front) { m_cond_list.push_front(cond); m_cond_map.insert(make_pair(cond, m_cond_list.begin())); } else { m_cond_list.push_back(cond); m_cond_map.insert(make_pair(cond, --m_cond_list.end())); } int ret; if (ts) { ret = pthread_cond_timedwait(cond, &m_mutex.getRaw(), ts); } else { ret = pthread_cond_wait(cond, &m_mutex.getRaw()); } assert(ret != EPERM); // did you lock the mutex? if (ret) { CondIterMap::iterator iter = m_cond_map.find(cond); if (iter != m_cond_map.end()) { m_cond_list.erase(iter->second); m_cond_map.erase(iter); } } return ret != ETIMEDOUT; } void SynchronizableMulti::notify() { if (!m_cond_list.empty()) { pthread_cond_t *cond = m_cond_list.front(); pthread_cond_signal(cond); m_cond_list.pop_front(); m_cond_map.erase(cond); } } void SynchronizableMulti::notifyAll() { while (!m_cond_list.empty()) { pthread_cond_signal(m_cond_list.front()); m_cond_list.pop_front(); } m_cond_map.clear(); } /////////////////////////////////////////////////////////////////////////////// }