00001 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ 00002 /* 00003 * Copyright (c) 2008 University of Washington 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation; 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software 00016 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00017 */ 00018 00019 #include <pthread.h> 00020 #include <errno.h> 00021 #include <sys/time.h> 00022 #include "fatal-error.h" 00023 #include "system-condition.h" 00024 #include "log.h" 00025 00026 NS_LOG_COMPONENT_DEFINE ("SystemCondition"); 00027 00028 namespace ns3 { 00029 00030 class SystemConditionPrivate { 00031 public: 00032 static const uint64_t NS_PER_SEC = (uint64_t)1000000000; 00033 00034 SystemConditionPrivate (); 00035 ~SystemConditionPrivate (); 00036 00037 void SetCondition (bool condition); 00038 bool GetCondition (void); 00039 void Signal (void); 00040 void Broadcast (void); 00041 void Wait (void); 00042 bool TimedWait (uint64_t ns); 00043 00044 private: 00045 pthread_mutex_t m_mutex; 00046 pthread_cond_t m_cond; 00047 bool m_condition; 00048 }; 00049 00050 SystemConditionPrivate::SystemConditionPrivate () 00051 { 00052 NS_LOG_FUNCTION_NOARGS (); 00053 00054 m_condition = false; 00055 00056 pthread_mutexattr_t mAttr; 00057 pthread_mutexattr_init (&mAttr); 00058 // 00059 // Linux and OS X (at least) have, of course chosen different names for the 00060 // error checking flags just to make life difficult. 00061 // 00062 #if defined (PTHREAD_MUTEX_ERRORCHECK_NP) 00063 pthread_mutexattr_settype (&mAttr, PTHREAD_MUTEX_ERRORCHECK_NP); 00064 #else 00065 pthread_mutexattr_settype (&mAttr, PTHREAD_MUTEX_ERRORCHECK); 00066 #endif 00067 pthread_mutex_init (&m_mutex, &mAttr); 00068 00069 pthread_condattr_t cAttr; 00070 pthread_condattr_init (&cAttr); 00071 pthread_condattr_setpshared (&cAttr, PTHREAD_PROCESS_PRIVATE); 00072 pthread_cond_init (&m_cond, &cAttr); 00073 } 00074 00075 SystemConditionPrivate::~SystemConditionPrivate() 00076 { 00077 NS_LOG_FUNCTION_NOARGS (); 00078 pthread_mutex_destroy (&m_mutex); 00079 pthread_cond_destroy (&m_cond); 00080 } 00081 00082 void 00083 SystemConditionPrivate::SetCondition (bool condition) 00084 { 00085 NS_LOG_FUNCTION_NOARGS (); 00086 m_condition = condition; 00087 } 00088 00089 bool 00090 SystemConditionPrivate::GetCondition (void) 00091 { 00092 NS_LOG_FUNCTION_NOARGS (); 00093 return m_condition; 00094 } 00095 00096 void 00097 SystemConditionPrivate::Signal (void) 00098 { 00099 NS_LOG_FUNCTION_NOARGS (); 00100 00101 pthread_mutex_lock (&m_mutex); 00102 pthread_cond_signal (&m_cond); 00103 pthread_mutex_unlock (&m_mutex); 00104 } 00105 00106 void 00107 SystemConditionPrivate::Broadcast (void) 00108 { 00109 NS_LOG_FUNCTION_NOARGS (); 00110 00111 pthread_mutex_lock (&m_mutex); 00112 pthread_cond_broadcast (&m_cond); 00113 pthread_mutex_unlock (&m_mutex); 00114 } 00115 00116 void 00117 SystemConditionPrivate::Wait (void) 00118 { 00119 NS_LOG_FUNCTION_NOARGS (); 00120 00121 pthread_mutex_lock (&m_mutex); 00122 m_condition = false; 00123 while (m_condition == false) 00124 { 00125 pthread_cond_wait (&m_cond, &m_mutex); 00126 } 00127 pthread_mutex_unlock (&m_mutex); 00128 } 00129 00130 bool 00131 SystemConditionPrivate::TimedWait (uint64_t ns) 00132 { 00133 NS_LOG_FUNCTION_NOARGS (); 00134 00135 struct timespec ts; 00136 ts.tv_sec = ns / NS_PER_SEC; 00137 ts.tv_nsec = ns % NS_PER_SEC; 00138 00139 struct timeval tv; 00140 gettimeofday(&tv, NULL); 00141 00142 ts.tv_sec += tv.tv_sec; 00143 ts.tv_nsec += tv.tv_usec * 1000; 00144 if (ts.tv_nsec > (int64_t)NS_PER_SEC) 00145 { 00146 ++ts.tv_sec; 00147 ts.tv_nsec %= NS_PER_SEC; 00148 } 00149 00150 int rc; 00151 00152 pthread_mutex_lock (&m_mutex); 00153 while (m_condition == false) 00154 { 00155 rc = pthread_cond_timedwait (&m_cond, &m_mutex, &ts); 00156 if (rc == ETIMEDOUT) 00157 { 00158 pthread_mutex_unlock (&m_mutex); 00159 return true; 00160 } 00161 } 00162 pthread_mutex_unlock (&m_mutex); 00163 return false; 00164 } 00165 00166 SystemCondition::SystemCondition() 00167 : m_priv (new SystemConditionPrivate ()) 00168 { 00169 NS_LOG_FUNCTION_NOARGS (); 00170 } 00171 00172 SystemCondition::~SystemCondition () 00173 { 00174 NS_LOG_FUNCTION_NOARGS (); 00175 delete m_priv; 00176 } 00177 00178 void 00179 SystemCondition::SetCondition (bool condition) 00180 { 00181 NS_LOG_FUNCTION_NOARGS (); 00182 m_priv->SetCondition (condition); 00183 } 00184 00185 bool 00186 SystemCondition::GetCondition (void) 00187 { 00188 NS_LOG_FUNCTION_NOARGS (); 00189 return m_priv->GetCondition (); 00190 } 00191 00192 void 00193 SystemCondition::Signal (void) 00194 { 00195 NS_LOG_FUNCTION_NOARGS (); 00196 m_priv->Signal (); 00197 } 00198 00199 void 00200 SystemCondition::Broadcast (void) 00201 { 00202 NS_LOG_FUNCTION_NOARGS (); 00203 m_priv->Broadcast (); 00204 } 00205 00206 void 00207 SystemCondition::Wait (void) 00208 { 00209 NS_LOG_FUNCTION_NOARGS (); 00210 m_priv->Wait (); 00211 } 00212 00213 bool 00214 SystemCondition::TimedWait (uint64_t ns) 00215 { 00216 NS_LOG_FUNCTION_NOARGS (); 00217 return m_priv->TimedWait (ns); 00218 } 00219 00220 } // namespace ns3