You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			295 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C++
		
	
			
		
		
	
	
			295 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C++
		
	
| /*
 | |
|  *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
 | |
|  *
 | |
|  *  Use of this source code is governed by a BSD-style license
 | |
|  *  that can be found in the LICENSE file in the root of the source
 | |
|  *  tree. An additional intellectual property rights grant can be found
 | |
|  *  in the file PATENTS.  All contributing project authors may
 | |
|  *  be found in the AUTHORS file in the root of the source tree.
 | |
|  */
 | |
| 
 | |
| #include "webrtc/system_wrappers/source/event_posix.h"
 | |
| 
 | |
| #include <errno.h>
 | |
| #include <pthread.h>
 | |
| #include <signal.h>
 | |
| #include <stdio.h>
 | |
| #include <string.h>
 | |
| #include <sys/time.h>
 | |
| #include <unistd.h>
 | |
| 
 | |
| namespace webrtc {
 | |
| 
 | |
| const long int E6 = 1000000;
 | |
| const long int E9 = 1000 * E6;
 | |
| 
 | |
| EventWrapper* EventPosix::Create() {
 | |
|   EventPosix* ptr = new EventPosix;
 | |
|   if (!ptr) {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   const int error = ptr->Construct();
 | |
|   if (error) {
 | |
|     delete ptr;
 | |
|     return NULL;
 | |
|   }
 | |
|   return ptr;
 | |
| }
 | |
| 
 | |
| EventPosix::EventPosix()
 | |
|     : timer_thread_(0),
 | |
|       timer_event_(0),
 | |
|       periodic_(false),
 | |
|       time_(0),
 | |
|       count_(0),
 | |
|       state_(kDown) {
 | |
| }
 | |
| 
 | |
| int EventPosix::Construct() {
 | |
|   // Set start time to zero
 | |
|   memset(&created_at_, 0, sizeof(created_at_));
 | |
| 
 | |
|   pthread_mutexattr_t attr;
 | |
|   pthread_mutexattr_init(&attr);
 | |
|   pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
 | |
|   int result = pthread_mutex_init(&mutex_, &attr);
 | |
|   if (result != 0) {
 | |
|     return -1;
 | |
|   }
 | |
| #ifdef WEBRTC_CLOCK_TYPE_REALTIME
 | |
|   result = pthread_cond_init(&cond_, 0);
 | |
|   if (result != 0) {
 | |
|     return -1;
 | |
|   }
 | |
| #else
 | |
|   pthread_condattr_t cond_attr;
 | |
|   result = pthread_condattr_init(&cond_attr);
 | |
|   if (result != 0) {
 | |
|     return -1;
 | |
|   }
 | |
|   result = pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
 | |
|   if (result != 0) {
 | |
|     return -1;
 | |
|   }
 | |
|   result = pthread_cond_init(&cond_, &cond_attr);
 | |
|   if (result != 0) {
 | |
|     return -1;
 | |
|   }
 | |
|   result = pthread_condattr_destroy(&cond_attr);
 | |
|   if (result != 0) {
 | |
|     return -1;
 | |
|   }
 | |
| #endif
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| EventPosix::~EventPosix() {
 | |
|   StopTimer();
 | |
|   pthread_cond_destroy(&cond_);
 | |
|   pthread_mutex_destroy(&mutex_);
 | |
| }
 | |
| 
 | |
| bool EventPosix::Reset() {
 | |
|   if (0 != pthread_mutex_lock(&mutex_)) {
 | |
|     return false;
 | |
|   }
 | |
|   state_ = kDown;
 | |
|   pthread_mutex_unlock(&mutex_);
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool EventPosix::Set() {
 | |
|   if (0 != pthread_mutex_lock(&mutex_)) {
 | |
|     return false;
 | |
|   }
 | |
|   state_ = kUp;
 | |
|   // Release all waiting threads
 | |
|   pthread_cond_broadcast(&cond_);
 | |
|   pthread_mutex_unlock(&mutex_);
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| EventTypeWrapper EventPosix::Wait(unsigned long timeout) {
 | |
|   int ret_val = 0;
 | |
|   if (0 != pthread_mutex_lock(&mutex_)) {
 | |
|     return kEventError;
 | |
|   }
 | |
| 
 | |
|   if (kDown == state_) {
 | |
|     if (WEBRTC_EVENT_INFINITE != timeout) {
 | |
|       timespec end_at;
 | |
| #ifndef WEBRTC_MAC
 | |
| #ifdef WEBRTC_CLOCK_TYPE_REALTIME
 | |
|       clock_gettime(CLOCK_REALTIME, &end_at);
 | |
| #else
 | |
|       clock_gettime(CLOCK_MONOTONIC, &end_at);
 | |
| #endif
 | |
| #else
 | |
|       timeval value;
 | |
|       struct timezone time_zone;
 | |
|       time_zone.tz_minuteswest = 0;
 | |
|       time_zone.tz_dsttime = 0;
 | |
|       gettimeofday(&value, &time_zone);
 | |
|       TIMEVAL_TO_TIMESPEC(&value, &end_at);
 | |
| #endif
 | |
|       end_at.tv_sec  += timeout / 1000;
 | |
|       end_at.tv_nsec += (timeout - (timeout / 1000) * 1000) * E6;
 | |
| 
 | |
|       if (end_at.tv_nsec >= E9) {
 | |
|         end_at.tv_sec++;
 | |
|         end_at.tv_nsec -= E9;
 | |
|       }
 | |
|       ret_val = pthread_cond_timedwait(&cond_, &mutex_, &end_at);
 | |
|     } else {
 | |
|       ret_val = pthread_cond_wait(&cond_, &mutex_);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   state_ = kDown;
 | |
|   pthread_mutex_unlock(&mutex_);
 | |
| 
 | |
|   switch (ret_val) {
 | |
|     case 0:
 | |
|       return kEventSignaled;
 | |
|     case ETIMEDOUT:
 | |
|       return kEventTimeout;
 | |
|     default:
 | |
|       return kEventError;
 | |
|   }
 | |
| }
 | |
| 
 | |
| EventTypeWrapper EventPosix::Wait(timespec& wake_at) {
 | |
|   int ret_val = 0;
 | |
|   if (0 != pthread_mutex_lock(&mutex_)) {
 | |
|     return kEventError;
 | |
|   }
 | |
| 
 | |
|   if (kUp != state_) {
 | |
|     ret_val = pthread_cond_timedwait(&cond_, &mutex_, &wake_at);
 | |
|   }
 | |
|   state_ = kDown;
 | |
| 
 | |
|   pthread_mutex_unlock(&mutex_);
 | |
| 
 | |
|   switch (ret_val) {
 | |
|     case 0:
 | |
|       return kEventSignaled;
 | |
|     case ETIMEDOUT:
 | |
|       return kEventTimeout;
 | |
|     default:
 | |
|       return kEventError;
 | |
|   }
 | |
| }
 | |
| 
 | |
| bool EventPosix::StartTimer(bool periodic, unsigned long time) {
 | |
|   pthread_mutex_lock(&mutex_);
 | |
|   if (timer_thread_) {
 | |
|     if (periodic_) {
 | |
|       // Timer already started.
 | |
|       pthread_mutex_unlock(&mutex_);
 | |
|       return false;
 | |
|     } else  {
 | |
|       // New one shot timer
 | |
|       time_ = time;
 | |
|       created_at_.tv_sec = 0;
 | |
|       timer_event_->Set();
 | |
|       pthread_mutex_unlock(&mutex_);
 | |
|       return true;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // Start the timer thread
 | |
|   timer_event_ = static_cast<EventPosix*>(EventWrapper::Create());
 | |
|   const char* thread_name = "WebRtc_event_timer_thread";
 | |
|   timer_thread_ = ThreadWrapper::CreateThread(Run, this, kRealtimePriority,
 | |
|                                               thread_name);
 | |
|   periodic_ = periodic;
 | |
|   time_ = time;
 | |
|   unsigned int id = 0;
 | |
|   bool started = timer_thread_->Start(id);
 | |
|   pthread_mutex_unlock(&mutex_);
 | |
| 
 | |
|   return started;
 | |
| }
 | |
| 
 | |
| bool EventPosix::Run(ThreadObj obj) {
 | |
|   return static_cast<EventPosix*>(obj)->Process();
 | |
| }
 | |
| 
 | |
| bool EventPosix::Process() {
 | |
|   pthread_mutex_lock(&mutex_);
 | |
|   if (created_at_.tv_sec == 0) {
 | |
| #ifndef WEBRTC_MAC
 | |
| #ifdef WEBRTC_CLOCK_TYPE_REALTIME
 | |
|     clock_gettime(CLOCK_REALTIME, &created_at_);
 | |
| #else
 | |
|     clock_gettime(CLOCK_MONOTONIC, &created_at_);
 | |
| #endif
 | |
| #else
 | |
|     timeval value;
 | |
|     struct timezone time_zone;
 | |
|     time_zone.tz_minuteswest = 0;
 | |
|     time_zone.tz_dsttime = 0;
 | |
|     gettimeofday(&value, &time_zone);
 | |
|     TIMEVAL_TO_TIMESPEC(&value, &created_at_);
 | |
| #endif
 | |
|     count_ = 0;
 | |
|   }
 | |
| 
 | |
|   timespec end_at;
 | |
|   unsigned long long time = time_ * ++count_;
 | |
|   end_at.tv_sec  = created_at_.tv_sec + time / 1000;
 | |
|   end_at.tv_nsec = created_at_.tv_nsec + (time - (time / 1000) * 1000) * E6;
 | |
| 
 | |
|   if (end_at.tv_nsec >= E9) {
 | |
|     end_at.tv_sec++;
 | |
|     end_at.tv_nsec -= E9;
 | |
|   }
 | |
| 
 | |
|   pthread_mutex_unlock(&mutex_);
 | |
|   switch (timer_event_->Wait(end_at)) {
 | |
|     case kEventSignaled:
 | |
|       return true;
 | |
|     case kEventError:
 | |
|       return false;
 | |
|     case kEventTimeout:
 | |
|       break;
 | |
|   }
 | |
| 
 | |
|   pthread_mutex_lock(&mutex_);
 | |
|   if (periodic_ || count_ == 1)
 | |
|     Set();
 | |
|   pthread_mutex_unlock(&mutex_);
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| bool EventPosix::StopTimer() {
 | |
|   if (timer_thread_) {
 | |
|     timer_thread_->SetNotAlive();
 | |
|   }
 | |
|   if (timer_event_) {
 | |
|     timer_event_->Set();
 | |
|   }
 | |
|   if (timer_thread_) {
 | |
|     if (!timer_thread_->Stop()) {
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     delete timer_thread_;
 | |
|     timer_thread_ = 0;
 | |
|   }
 | |
|   if (timer_event_) {
 | |
|     delete timer_event_;
 | |
|     timer_event_ = 0;
 | |
|   }
 | |
| 
 | |
|   // Set time to zero to force new reference time for the timer.
 | |
|   memset(&created_at_, 0, sizeof(created_at_));
 | |
|   count_ = 0;
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| }  // namespace webrtc
 |