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
 |