LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/system_wrappers/source - event_timer_posix.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 120 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 12 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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 "webrtc/system_wrappers/source/event_timer_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             : 
      21             : #include "webrtc/base/checks.h"
      22             : 
      23             : namespace webrtc {
      24             : 
      25             : // static
      26           0 : EventTimerWrapper* EventTimerWrapper::Create() {
      27           0 :   return new EventTimerPosix();
      28             : }
      29             : 
      30             : const int64_t kNanosecondsPerMillisecond = 1000000;
      31             : const int64_t kNanosecondsPerSecond = 1000000000;
      32             : 
      33           0 : EventTimerPosix::EventTimerPosix()
      34             :     : event_set_(false),
      35             :       timer_thread_(nullptr),
      36             :       created_at_(),
      37             :       periodic_(false),
      38             :       time_ms_(0),
      39             :       count_(0),
      40           0 :       is_stopping_(false) {
      41             :   pthread_mutexattr_t attr;
      42           0 :   pthread_mutexattr_init(&attr);
      43           0 :   pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
      44           0 :   pthread_mutex_init(&mutex_, &attr);
      45             :   pthread_condattr_t cond_attr;
      46           0 :   pthread_condattr_init(&cond_attr);
      47             : // TODO(sprang): Remove HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC special case once
      48             : // all supported Android platforms support pthread_condattr_setclock.
      49             : // TODO(sprang): Add support for monotonic clock on Apple platforms.
      50             : #if !(defined(WEBRTC_MAC) || defined(WEBRTC_IOS)) && \
      51             :     !(defined(WEBRTC_ANDROID) &&                     \
      52             :       defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC))
      53           0 :   pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
      54             : #endif
      55           0 :   pthread_cond_init(&cond_, &cond_attr);
      56           0 :   pthread_condattr_destroy(&cond_attr);
      57           0 : }
      58             : 
      59           0 : EventTimerPosix::~EventTimerPosix() {
      60           0 :   StopTimer();
      61           0 :   pthread_cond_destroy(&cond_);
      62           0 :   pthread_mutex_destroy(&mutex_);
      63           0 : }
      64             : 
      65             : // TODO(pbos): Make this void.
      66           0 : bool EventTimerPosix::Set() {
      67           0 :   RTC_CHECK_EQ(0, pthread_mutex_lock(&mutex_));
      68           0 :   event_set_ = true;
      69           0 :   pthread_cond_signal(&cond_);
      70           0 :   pthread_mutex_unlock(&mutex_);
      71           0 :   return true;
      72             : }
      73             : 
      74           0 : EventTypeWrapper EventTimerPosix::Wait(unsigned long timeout_ms) {
      75           0 :   int ret_val = 0;
      76           0 :   RTC_CHECK_EQ(0, pthread_mutex_lock(&mutex_));
      77             : 
      78           0 :   if (!event_set_) {
      79           0 :     if (WEBRTC_EVENT_INFINITE != timeout_ms) {
      80             :       timespec end_at;
      81             : #ifndef WEBRTC_MAC
      82           0 :       clock_gettime(CLOCK_MONOTONIC, &end_at);
      83             : #else
      84             :       timeval value;
      85             :       struct timezone time_zone;
      86             :       time_zone.tz_minuteswest = 0;
      87             :       time_zone.tz_dsttime = 0;
      88             :       gettimeofday(&value, &time_zone);
      89             :       TIMEVAL_TO_TIMESPEC(&value, &end_at);
      90             : #endif
      91           0 :       end_at.tv_sec += timeout_ms / 1000;
      92           0 :       end_at.tv_nsec += (timeout_ms % 1000) * kNanosecondsPerMillisecond;
      93             : 
      94           0 :       if (end_at.tv_nsec >= kNanosecondsPerSecond) {
      95           0 :         end_at.tv_sec++;
      96           0 :         end_at.tv_nsec -= kNanosecondsPerSecond;
      97             :       }
      98           0 :       while (ret_val == 0 && !event_set_) {
      99             : #if defined(WEBRTC_ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)
     100             :         ret_val = pthread_cond_timedwait_monotonic_np(&cond_, &mutex_, &end_at);
     101             : #else
     102           0 :         ret_val = pthread_cond_timedwait(&cond_, &mutex_, &end_at);
     103             : #endif  // WEBRTC_ANDROID && HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC
     104             :       }
     105             :     } else {
     106           0 :       while (ret_val == 0 && !event_set_)
     107           0 :         ret_val = pthread_cond_wait(&cond_, &mutex_);
     108             :     }
     109             :   }
     110             : 
     111           0 :   RTC_DCHECK(ret_val == 0 || ret_val == ETIMEDOUT);
     112             : 
     113             :   // Reset and signal if set, regardless of why the thread woke up.
     114           0 :   if (event_set_) {
     115           0 :     ret_val = 0;
     116           0 :     event_set_ = false;
     117             :   }
     118           0 :   pthread_mutex_unlock(&mutex_);
     119             : 
     120           0 :   return ret_val == 0 ? kEventSignaled : kEventTimeout;
     121             : }
     122             : 
     123           0 : EventTypeWrapper EventTimerPosix::Wait(timespec* end_at, bool reset_event) {
     124           0 :   int ret_val = 0;
     125           0 :   RTC_CHECK_EQ(0, pthread_mutex_lock(&mutex_));
     126           0 :   if (reset_event) {
     127             :     // Only wake for new events or timeouts.
     128           0 :     event_set_ = false;
     129             :   }
     130             : 
     131           0 :   while (ret_val == 0 && !event_set_) {
     132             : #if defined(WEBRTC_ANDROID) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)
     133             :     ret_val = pthread_cond_timedwait_monotonic_np(&cond_, &mutex_, end_at);
     134             : #else
     135           0 :     ret_val = pthread_cond_timedwait(&cond_, &mutex_, end_at);
     136             : #endif  // WEBRTC_ANDROID && HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC
     137             :   }
     138             : 
     139           0 :   RTC_DCHECK(ret_val == 0 || ret_val == ETIMEDOUT);
     140             : 
     141             :   // Reset and signal if set, regardless of why the thread woke up.
     142           0 :   if (event_set_) {
     143           0 :     ret_val = 0;
     144           0 :     event_set_ = false;
     145             :   }
     146           0 :   pthread_mutex_unlock(&mutex_);
     147             : 
     148           0 :   return ret_val == 0 ? kEventSignaled : kEventTimeout;
     149             : }
     150             : 
     151           0 : rtc::PlatformThread* EventTimerPosix::CreateThread() {
     152           0 :   const char* kThreadName = "WebRtc_event_timer_thread";
     153           0 :   return new rtc::PlatformThread(Run, this, kThreadName);
     154             : }
     155             : 
     156           0 : bool EventTimerPosix::StartTimer(bool periodic, unsigned long time_ms) {
     157           0 :   pthread_mutex_lock(&mutex_);
     158           0 :   if (timer_thread_) {
     159           0 :     if (periodic_) {
     160             :       // Timer already started.
     161           0 :       pthread_mutex_unlock(&mutex_);
     162           0 :       return false;
     163             :     } else  {
     164             :       // New one shot timer.
     165           0 :       time_ms_ = time_ms;
     166           0 :       created_at_.tv_sec = 0;
     167           0 :       timer_event_->Set();
     168           0 :       pthread_mutex_unlock(&mutex_);
     169           0 :       return true;
     170             :     }
     171             :   }
     172             : 
     173             :   // Start the timer thread.
     174           0 :   timer_event_.reset(new EventTimerPosix());
     175           0 :   timer_thread_.reset(CreateThread());
     176           0 :   periodic_ = periodic;
     177           0 :   time_ms_ = time_ms;
     178           0 :   timer_thread_->Start();
     179           0 :   timer_thread_->SetPriority(rtc::kRealtimePriority);
     180           0 :   pthread_mutex_unlock(&mutex_);
     181             : 
     182           0 :   return true;
     183             : }
     184             : 
     185           0 : bool EventTimerPosix::Run(void* obj) {
     186           0 :   return static_cast<EventTimerPosix*>(obj)->Process();
     187             : }
     188             : 
     189           0 : bool EventTimerPosix::Process() {
     190           0 :   pthread_mutex_lock(&mutex_);
     191           0 :   if (is_stopping_) {
     192           0 :     pthread_mutex_unlock(&mutex_);
     193           0 :     return false;
     194             :   }
     195           0 :   if (created_at_.tv_sec == 0) {
     196             : #ifndef WEBRTC_MAC
     197           0 :     RTC_CHECK_EQ(0, clock_gettime(CLOCK_MONOTONIC, &created_at_));
     198             : #else
     199             :     timeval value;
     200             :     struct timezone time_zone;
     201             :     time_zone.tz_minuteswest = 0;
     202             :     time_zone.tz_dsttime = 0;
     203             :     gettimeofday(&value, &time_zone);
     204             :     TIMEVAL_TO_TIMESPEC(&value, &created_at_);
     205             : #endif
     206           0 :     count_ = 0;
     207             :   }
     208             : 
     209             :   timespec end_at;
     210           0 :   unsigned long long total_delta_ms = time_ms_ * ++count_;
     211           0 :   if (!periodic_ && count_ >= 1) {
     212             :     // No need to wake up often if we're not going to signal waiting threads.
     213           0 :     total_delta_ms =
     214           0 :         std::min<uint64_t>(total_delta_ms, 60 * kNanosecondsPerSecond);
     215             :   }
     216             : 
     217           0 :   end_at.tv_sec = created_at_.tv_sec + total_delta_ms / 1000;
     218           0 :   end_at.tv_nsec = created_at_.tv_nsec +
     219           0 :                    (total_delta_ms % 1000) * kNanosecondsPerMillisecond;
     220             : 
     221           0 :   if (end_at.tv_nsec >= kNanosecondsPerSecond) {
     222           0 :     end_at.tv_sec++;
     223           0 :     end_at.tv_nsec -= kNanosecondsPerSecond;
     224             :   }
     225             : 
     226           0 :   pthread_mutex_unlock(&mutex_);
     227             :   // Reset event on first call so that we don't immediately return here if this
     228             :   // thread was not blocked on timer_event_->Wait when the StartTimer() call
     229             :   // was made.
     230           0 :   if (timer_event_->Wait(&end_at, count_ == 1) == kEventSignaled)
     231           0 :     return true;
     232             : 
     233           0 :   pthread_mutex_lock(&mutex_);
     234           0 :   if (periodic_ || count_ == 1)
     235           0 :     Set();
     236           0 :   pthread_mutex_unlock(&mutex_);
     237             : 
     238           0 :   return true;
     239             : }
     240             : 
     241           0 : bool EventTimerPosix::StopTimer() {
     242           0 :   pthread_mutex_lock(&mutex_);
     243           0 :   is_stopping_ = true;
     244           0 :   pthread_mutex_unlock(&mutex_);
     245             : 
     246           0 :   if (timer_event_)
     247           0 :     timer_event_->Set();
     248             : 
     249           0 :   if (timer_thread_) {
     250           0 :     timer_thread_->Stop();
     251           0 :     timer_thread_.reset();
     252             :   }
     253           0 :   timer_event_.reset();
     254             : 
     255             :   // Set time to zero to force new reference time for the timer.
     256           0 :   memset(&created_at_, 0, sizeof(created_at_));
     257           0 :   count_ = 0;
     258           0 :   return true;
     259             : }
     260             : 
     261             : }  // namespace webrtc

Generated by: LCOV version 1.13