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_posix.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 21namespace webrtc { 22const long int E6 = 1000000; 23const long int E9 = 1000 * E6; 24 25EventWrapper* EventPosix::Create() 26{ 27 EventPosix* ptr = new EventPosix; 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 43EventPosix::EventPosix() 44 : _timerThread(0), 45 _timerEvent(0), 46 _periodic(false), 47 _time(0), 48 _count(0), 49 _state(kDown) 50{ 51} 52 53int EventPosix::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 95EventPosix::~EventPosix() 96{ 97 StopTimer(); 98 pthread_cond_destroy(&cond); 99 pthread_mutex_destroy(&mutex); 100} 101 102bool EventPosix::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 113bool EventPosix::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 126EventTypeWrapper EventPosix::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 181EventTypeWrapper EventPosix::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 208bool EventPosix::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<EventPosix*>(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 240bool EventPosix::Run(ThreadObj obj) 241{ 242 return static_cast<EventPosix*>(obj)->Process(); 243} 244 245bool EventPosix::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 293bool EventPosix::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