1 /* 2 * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "event_linux.h" 12 13 #include <errno.h> 14 #include <pthread.h> 15 #include <signal.h> 16 #include <stdio.h> 17 #include <string.h> 18 #include <sys/time.h> 19 #include <unistd.h> 20 21 namespace webrtc { 22 const long int E6 = 1000000; 23 const long int E9 = 1000 * E6; 24 25 EventWrapper* EventLinux::Create() 26 { 27 EventLinux* ptr = new EventLinux; 28 if (!ptr) 29 { 30 return NULL; 31 } 32 33 const int error = ptr->Construct(); 34 if (error) 35 { 36 delete ptr; 37 return NULL; 38 } 39 return ptr; 40 } 41 42 43 EventLinux::EventLinux() 44 : _timerThread(0), 45 _timerEvent(0), 46 _periodic(false), 47 _time(0), 48 _count(0), 49 _state(kDown) 50 { 51 } 52 53 int EventLinux::Construct() 54 { 55 // Set start time to zero 56 memset(&_tCreate, 0, sizeof(_tCreate)); 57 58 int result = pthread_mutex_init(&mutex, 0); 59 if (result != 0) 60 { 61 return -1; 62 } 63 #ifdef WEBRTC_CLOCK_TYPE_REALTIME 64 result = pthread_cond_init(&cond, 0); 65 if (result != 0) 66 { 67 return -1; 68 } 69 #else 70 pthread_condattr_t condAttr; 71 result = pthread_condattr_init(&condAttr); 72 if (result != 0) 73 { 74 return -1; 75 } 76 result = pthread_condattr_setclock(&condAttr, CLOCK_MONOTONIC); 77 if (result != 0) 78 { 79 return -1; 80 } 81 result = pthread_cond_init(&cond, &condAttr); 82 if (result != 0) 83 { 84 return -1; 85 } 86 result = pthread_condattr_destroy(&condAttr); 87 if (result != 0) 88 { 89 return -1; 90 } 91 #endif 92 return 0; 93 } 94 95 EventLinux::~EventLinux() 96 { 97 StopTimer(); 98 pthread_cond_destroy(&cond); 99 pthread_mutex_destroy(&mutex); 100 } 101 102 bool EventLinux::Reset() 103 { 104 if (0 != pthread_mutex_lock(&mutex)) 105 { 106 return false; 107 } 108 _state = kDown; 109 pthread_mutex_unlock(&mutex); 110 return true; 111 } 112 113 bool EventLinux::Set() 114 { 115 if (0 != pthread_mutex_lock(&mutex)) 116 { 117 return false; 118 } 119 _state = kUp; 120 // Release all waiting threads 121 pthread_cond_broadcast(&cond); 122 pthread_mutex_unlock(&mutex); 123 return true; 124 } 125 126 EventTypeWrapper EventLinux::Wait(unsigned long timeout) 127 { 128 int retVal = 0; 129 if (0 != pthread_mutex_lock(&mutex)) 130 { 131 return kEventError; 132 } 133 134 if (kDown == _state) 135 { 136 if (WEBRTC_EVENT_INFINITE != timeout) 137 { 138 timespec tEnd; 139 #ifndef WEBRTC_MAC 140 #ifdef WEBRTC_CLOCK_TYPE_REALTIME 141 clock_gettime(CLOCK_REALTIME, &tEnd); 142 #else 143 clock_gettime(CLOCK_MONOTONIC, &tEnd); 144 #endif 145 #else 146 timeval tVal; 147 struct timezone tZone; 148 tZone.tz_minuteswest = 0; 149 tZone.tz_dsttime = 0; 150 gettimeofday(&tVal,&tZone); 151 TIMEVAL_TO_TIMESPEC(&tVal,&tEnd); 152 #endif 153 tEnd.tv_sec += timeout / 1000; 154 tEnd.tv_nsec += (timeout - (timeout / 1000) * 1000) * E6; 155 156 if (tEnd.tv_nsec >= E9) 157 { 158 tEnd.tv_sec++; 159 tEnd.tv_nsec -= E9; 160 } 161 retVal = pthread_cond_timedwait(&cond, &mutex, &tEnd); 162 } else { 163 retVal = pthread_cond_wait(&cond, &mutex); 164 } 165 } 166 167 _state = kDown; 168 pthread_mutex_unlock(&mutex); 169 170 switch(retVal) 171 { 172 case 0: 173 return kEventSignaled; 174 case ETIMEDOUT: 175 return kEventTimeout; 176 default: 177 return kEventError; 178 } 179 } 180 181 EventTypeWrapper EventLinux::Wait(timespec& tPulse) 182 { 183 int retVal = 0; 184 if (0 != pthread_mutex_lock(&mutex)) 185 { 186 return kEventError; 187 } 188 189 if (kUp != _state) 190 { 191 retVal = pthread_cond_timedwait(&cond, &mutex, &tPulse); 192 } 193 _state = kDown; 194 195 pthread_mutex_unlock(&mutex); 196 197 switch(retVal) 198 { 199 case 0: 200 return kEventSignaled; 201 case ETIMEDOUT: 202 return kEventTimeout; 203 default: 204 return kEventError; 205 } 206 } 207 208 bool EventLinux::StartTimer(bool periodic, unsigned long time) 209 { 210 if (_timerThread) 211 { 212 if(_periodic) 213 { 214 // Timer already started. 215 return false; 216 } else { 217 // New one shot timer 218 _time = time; 219 _tCreate.tv_sec = 0; 220 _timerEvent->Set(); 221 return true; 222 } 223 } 224 225 // Start the timer thread 226 _timerEvent = static_cast<EventLinux*>(EventWrapper::Create()); 227 const char* threadName = "WebRtc_event_timer_thread"; 228 _timerThread = ThreadWrapper::CreateThread(Run, this, kRealtimePriority, 229 threadName); 230 _periodic = periodic; 231 _time = time; 232 unsigned int id = 0; 233 if (_timerThread->Start(id)) 234 { 235 return true; 236 } 237 return false; 238 } 239 240 bool EventLinux::Run(ThreadObj obj) 241 { 242 return static_cast<EventLinux*>(obj)->Process(); 243 } 244 245 bool EventLinux::Process() 246 { 247 if (_tCreate.tv_sec == 0) 248 { 249 #ifndef WEBRTC_MAC 250 #ifdef WEBRTC_CLOCK_TYPE_REALTIME 251 clock_gettime(CLOCK_REALTIME, &_tCreate); 252 #else 253 clock_gettime(CLOCK_MONOTONIC, &_tCreate); 254 #endif 255 #else 256 timeval tVal; 257 struct timezone tZone; 258 tZone.tz_minuteswest = 0; 259 tZone.tz_dsttime = 0; 260 gettimeofday(&tVal,&tZone); 261 TIMEVAL_TO_TIMESPEC(&tVal,&_tCreate); 262 #endif 263 _count=0; 264 } 265 266 timespec tEnd; 267 unsigned long long time = _time * ++_count; 268 tEnd.tv_sec = _tCreate.tv_sec + time/1000; 269 tEnd.tv_nsec = _tCreate.tv_nsec + (time - (time/1000)*1000)*E6; 270 271 if ( tEnd.tv_nsec >= E9 ) 272 { 273 tEnd.tv_sec++; 274 tEnd.tv_nsec -= E9; 275 } 276 277 switch(_timerEvent->Wait(tEnd)) 278 { 279 case kEventSignaled: 280 return true; 281 case kEventError: 282 return false; 283 case kEventTimeout: 284 break; 285 } 286 if(_periodic || _count==1) 287 { 288 Set(); 289 } 290 return true; 291 } 292 293 bool EventLinux::StopTimer() 294 { 295 if(_timerThread) 296 { 297 _timerThread->SetNotAlive(); 298 } 299 if (_timerEvent) 300 { 301 _timerEvent->Set(); 302 } 303 if (_timerThread) 304 { 305 if(!_timerThread->Stop()) 306 { 307 return false; 308 } 309 310 delete _timerThread; 311 _timerThread = 0; 312 } 313 if (_timerEvent) 314 { 315 delete _timerEvent; 316 _timerEvent = 0; 317 } 318 319 // Set time to zero to force new reference time for the timer. 320 memset(&_tCreate, 0, sizeof(_tCreate)); 321 _count=0; 322 return true; 323 } 324 } // namespace webrtc 325