craigdo@3425: /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ craigdo@3425: /* craigdo@3425: * Copyright (c) 2008 University of Washington craigdo@3425: * craigdo@3425: * This program is free software; you can redistribute it and/or modify craigdo@3425: * it under the terms of the GNU General Public License version 2 as craigdo@3425: * published by the Free Software Foundation; craigdo@3425: * craigdo@3425: * This program is distributed in the hope that it will be useful, craigdo@3425: * but WITHOUT ANY WARRANTY; without even the implied warranty of craigdo@3425: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the craigdo@3425: * GNU General Public License for more details. craigdo@3425: * craigdo@3425: * You should have received a copy of the GNU General Public License craigdo@3425: * along with this program; if not, write to the Free Software craigdo@3425: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA craigdo@3425: */ craigdo@3425: craigdo@3425: #include craigdo@3425: #include craigdo@3425: #include craigdo@3425: #include "fatal-error.h" craigdo@3425: #include "system-condition.h" craigdo@3425: #include "log.h" craigdo@3425: craigdo@3425: NS_LOG_COMPONENT_DEFINE ("SystemCondition"); craigdo@3425: craigdo@3425: namespace ns3 { craigdo@3425: craigdo@3425: class SystemConditionPrivate { craigdo@3425: public: craigdo@3425: static const uint64_t NS_PER_SEC = (uint64_t)1000000000; craigdo@3425: craigdo@3425: SystemConditionPrivate (); craigdo@3425: ~SystemConditionPrivate (); craigdo@3425: craigdo@3425: void SetCondition (bool condition); craigdo@3425: bool GetCondition (void); craigdo@3425: void Signal (void); craigdo@3425: void Broadcast (void); craigdo@3425: void Wait (void); craigdo@3425: bool TimedWait (uint64_t ns); craigdo@3425: craigdo@3425: private: craigdo@3425: pthread_mutex_t m_mutex; craigdo@3425: pthread_cond_t m_cond; craigdo@3425: bool m_condition; craigdo@3425: }; craigdo@3425: craigdo@3425: SystemConditionPrivate::SystemConditionPrivate () craigdo@3425: { craigdo@3425: NS_LOG_FUNCTION_NOARGS (); craigdo@3425: craigdo@3425: m_condition = false; craigdo@3425: craigdo@3425: pthread_mutexattr_t mAttr; craigdo@3425: pthread_mutexattr_init (&mAttr); craigdo@3434: // craigdo@3434: // Linux and OS X (at least) have, of course chosen different names for the craigdo@3434: // error checking flags just to make life difficult. craigdo@3434: // craigdo@3434: #if defined (PTHREAD_MUTEX_ERRORCHECK_NP) craigdo@3425: pthread_mutexattr_settype (&mAttr, PTHREAD_MUTEX_ERRORCHECK_NP); craigdo@3434: #else craigdo@3434: pthread_mutexattr_settype (&mAttr, PTHREAD_MUTEX_ERRORCHECK); craigdo@3434: #endif craigdo@3425: pthread_mutex_init (&m_mutex, &mAttr); craigdo@3425: craigdo@3425: pthread_condattr_t cAttr; craigdo@3425: pthread_condattr_init (&cAttr); craigdo@3425: pthread_condattr_setpshared (&cAttr, PTHREAD_PROCESS_PRIVATE); craigdo@3425: pthread_cond_init (&m_cond, &cAttr); craigdo@3425: } craigdo@3425: craigdo@3425: SystemConditionPrivate::~SystemConditionPrivate() craigdo@3425: { craigdo@3425: NS_LOG_FUNCTION_NOARGS (); craigdo@3425: pthread_mutex_destroy (&m_mutex); craigdo@3425: pthread_cond_destroy (&m_cond); craigdo@3425: } craigdo@3425: craigdo@3425: void craigdo@3425: SystemConditionPrivate::SetCondition (bool condition) craigdo@3425: { craigdo@3425: NS_LOG_FUNCTION_NOARGS (); craigdo@3425: m_condition = condition; craigdo@3425: } craigdo@3425: craigdo@3425: bool craigdo@3425: SystemConditionPrivate::GetCondition (void) craigdo@3425: { craigdo@3425: NS_LOG_FUNCTION_NOARGS (); craigdo@3425: return m_condition; craigdo@3425: } craigdo@3425: craigdo@3425: void craigdo@3425: SystemConditionPrivate::Signal (void) craigdo@3425: { craigdo@3425: NS_LOG_FUNCTION_NOARGS (); craigdo@3425: craigdo@3425: pthread_mutex_lock (&m_mutex); craigdo@3425: pthread_cond_signal (&m_cond); craigdo@3425: pthread_mutex_unlock (&m_mutex); craigdo@3425: } craigdo@3425: craigdo@3425: void craigdo@3425: SystemConditionPrivate::Broadcast (void) craigdo@3425: { craigdo@3425: NS_LOG_FUNCTION_NOARGS (); craigdo@3425: craigdo@3425: pthread_mutex_lock (&m_mutex); craigdo@3425: pthread_cond_broadcast (&m_cond); craigdo@3425: pthread_mutex_unlock (&m_mutex); craigdo@3425: } craigdo@3425: craigdo@3425: void craigdo@3425: SystemConditionPrivate::Wait (void) craigdo@3425: { craigdo@3425: NS_LOG_FUNCTION_NOARGS (); craigdo@3425: craigdo@3425: pthread_mutex_lock (&m_mutex); craigdo@3425: m_condition = false; craigdo@3425: while (m_condition == false) craigdo@3425: { craigdo@3425: pthread_cond_wait (&m_cond, &m_mutex); craigdo@3425: } craigdo@3425: pthread_mutex_unlock (&m_mutex); craigdo@3425: } craigdo@3425: craigdo@3425: bool craigdo@3425: SystemConditionPrivate::TimedWait (uint64_t ns) craigdo@3425: { craigdo@3425: NS_LOG_FUNCTION_NOARGS (); craigdo@3425: craigdo@3425: struct timespec ts; craigdo@3425: ts.tv_sec = ns / NS_PER_SEC; craigdo@3425: ts.tv_nsec = ns % NS_PER_SEC; craigdo@3425: craigdo@3425: struct timeval tv; craigdo@3425: gettimeofday(&tv, NULL); craigdo@3425: craigdo@3425: ts.tv_sec += tv.tv_sec; craigdo@3425: ts.tv_nsec += tv.tv_usec * 1000; craigdo@3425: if (ts.tv_nsec > (int64_t)NS_PER_SEC) craigdo@3425: { craigdo@3425: ++ts.tv_sec; craigdo@3425: ts.tv_nsec %= NS_PER_SEC; craigdo@3425: } craigdo@3425: craigdo@3425: int rc; craigdo@3425: craigdo@3425: pthread_mutex_lock (&m_mutex); craigdo@3425: while (m_condition == false) craigdo@3425: { craigdo@3425: rc = pthread_cond_timedwait (&m_cond, &m_mutex, &ts); craigdo@3425: if (rc == ETIMEDOUT) craigdo@3425: { craigdo@3425: pthread_mutex_unlock (&m_mutex); craigdo@3425: return true; craigdo@3425: } craigdo@3425: } craigdo@3425: pthread_mutex_unlock (&m_mutex); craigdo@3425: return false; craigdo@3425: } craigdo@3425: craigdo@3425: SystemCondition::SystemCondition() craigdo@3425: : m_priv (new SystemConditionPrivate ()) craigdo@3425: { craigdo@3425: NS_LOG_FUNCTION_NOARGS (); craigdo@3425: } craigdo@3425: craigdo@3425: SystemCondition::~SystemCondition () craigdo@3425: { craigdo@3425: NS_LOG_FUNCTION_NOARGS (); craigdo@3425: delete m_priv; craigdo@3425: } craigdo@3425: craigdo@3425: void craigdo@3425: SystemCondition::SetCondition (bool condition) craigdo@3425: { craigdo@3425: NS_LOG_FUNCTION_NOARGS (); craigdo@3425: m_priv->SetCondition (condition); craigdo@3425: } craigdo@3425: craigdo@3425: bool craigdo@3425: SystemCondition::GetCondition (void) craigdo@3425: { craigdo@3425: NS_LOG_FUNCTION_NOARGS (); craigdo@3425: return m_priv->GetCondition (); craigdo@3425: } craigdo@3425: craigdo@3425: void craigdo@3425: SystemCondition::Signal (void) craigdo@3425: { craigdo@3425: NS_LOG_FUNCTION_NOARGS (); craigdo@3425: m_priv->Signal (); craigdo@3425: } craigdo@3425: craigdo@3425: void craigdo@3425: SystemCondition::Broadcast (void) craigdo@3425: { craigdo@3425: NS_LOG_FUNCTION_NOARGS (); craigdo@3425: m_priv->Broadcast (); craigdo@3425: } craigdo@3425: craigdo@3425: void craigdo@3425: SystemCondition::Wait (void) craigdo@3425: { craigdo@3425: NS_LOG_FUNCTION_NOARGS (); craigdo@3425: m_priv->Wait (); craigdo@3425: } craigdo@3425: craigdo@3425: bool craigdo@3425: SystemCondition::TimedWait (uint64_t ns) craigdo@3425: { craigdo@3425: NS_LOG_FUNCTION_NOARGS (); craigdo@3425: return m_priv->TimedWait (ns); craigdo@3425: } craigdo@3425: craigdo@3425: } // namespace ns3