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