325 lines
6.5 KiB
C++
325 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 "event_linux.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* EventLinux::Create()
|
||
|
{
|
||
|
EventLinux* ptr = new EventLinux;
|
||
|
if (!ptr)
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
const int error = ptr->Construct();
|
||
|
if (error)
|
||
|
{
|
||
|
delete ptr;
|
||
|
return NULL;
|
||
|
}
|
||
|
return ptr;
|
||
|
}
|
||
|
|
||
|
|
||
|
EventLinux::EventLinux()
|
||
|
: _timerThread(0),
|
||
|
_timerEvent(0),
|
||
|
_periodic(false),
|
||
|
_time(0),
|
||
|
_count(0),
|
||
|
_state(kDown)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
int EventLinux::Construct()
|
||
|
{
|
||
|
// Set start time to zero
|
||
|
memset(&_tCreate, 0, sizeof(_tCreate));
|
||
|
|
||
|
int result = pthread_mutex_init(&mutex, 0);
|
||
|
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 condAttr;
|
||
|
result = pthread_condattr_init(&condAttr);
|
||
|
if (result != 0)
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
result = pthread_condattr_setclock(&condAttr, CLOCK_MONOTONIC);
|
||
|
if (result != 0)
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
result = pthread_cond_init(&cond, &condAttr);
|
||
|
if (result != 0)
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
result = pthread_condattr_destroy(&condAttr);
|
||
|
if (result != 0)
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
#endif
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
EventLinux::~EventLinux()
|
||
|
{
|
||
|
StopTimer();
|
||
|
pthread_cond_destroy(&cond);
|
||
|
pthread_mutex_destroy(&mutex);
|
||
|
}
|
||
|
|
||
|
bool EventLinux::Reset()
|
||
|
{
|
||
|
if (0 != pthread_mutex_lock(&mutex))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
_state = kDown;
|
||
|
pthread_mutex_unlock(&mutex);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool EventLinux::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 EventLinux::Wait(unsigned long timeout)
|
||
|
{
|
||
|
int retVal = 0;
|
||
|
if (0 != pthread_mutex_lock(&mutex))
|
||
|
{
|
||
|
return kEventError;
|
||
|
}
|
||
|
|
||
|
if (kDown == _state)
|
||
|
{
|
||
|
if (WEBRTC_EVENT_INFINITE != timeout)
|
||
|
{
|
||
|
timespec tEnd;
|
||
|
#ifndef WEBRTC_MAC
|
||
|
#ifdef WEBRTC_CLOCK_TYPE_REALTIME
|
||
|
clock_gettime(CLOCK_REALTIME, &tEnd);
|
||
|
#else
|
||
|
clock_gettime(CLOCK_MONOTONIC, &tEnd);
|
||
|
#endif
|
||
|
#else
|
||
|
timeval tVal;
|
||
|
struct timezone tZone;
|
||
|
tZone.tz_minuteswest = 0;
|
||
|
tZone.tz_dsttime = 0;
|
||
|
gettimeofday(&tVal,&tZone);
|
||
|
TIMEVAL_TO_TIMESPEC(&tVal,&tEnd);
|
||
|
#endif
|
||
|
tEnd.tv_sec += timeout / 1000;
|
||
|
tEnd.tv_nsec += (timeout - (timeout / 1000) * 1000) * E6;
|
||
|
|
||
|
if (tEnd.tv_nsec >= E9)
|
||
|
{
|
||
|
tEnd.tv_sec++;
|
||
|
tEnd.tv_nsec -= E9;
|
||
|
}
|
||
|
retVal = pthread_cond_timedwait(&cond, &mutex, &tEnd);
|
||
|
} else {
|
||
|
retVal = pthread_cond_wait(&cond, &mutex);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
_state = kDown;
|
||
|
pthread_mutex_unlock(&mutex);
|
||
|
|
||
|
switch(retVal)
|
||
|
{
|
||
|
case 0:
|
||
|
return kEventSignaled;
|
||
|
case ETIMEDOUT:
|
||
|
return kEventTimeout;
|
||
|
default:
|
||
|
return kEventError;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
EventTypeWrapper EventLinux::Wait(timespec& tPulse)
|
||
|
{
|
||
|
int retVal = 0;
|
||
|
if (0 != pthread_mutex_lock(&mutex))
|
||
|
{
|
||
|
return kEventError;
|
||
|
}
|
||
|
|
||
|
if (kUp != _state)
|
||
|
{
|
||
|
retVal = pthread_cond_timedwait(&cond, &mutex, &tPulse);
|
||
|
}
|
||
|
_state = kDown;
|
||
|
|
||
|
pthread_mutex_unlock(&mutex);
|
||
|
|
||
|
switch(retVal)
|
||
|
{
|
||
|
case 0:
|
||
|
return kEventSignaled;
|
||
|
case ETIMEDOUT:
|
||
|
return kEventTimeout;
|
||
|
default:
|
||
|
return kEventError;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool EventLinux::StartTimer(bool periodic, unsigned long time)
|
||
|
{
|
||
|
if (_timerThread)
|
||
|
{
|
||
|
if(_periodic)
|
||
|
{
|
||
|
// Timer already started.
|
||
|
return false;
|
||
|
} else {
|
||
|
// New one shot timer
|
||
|
_time = time;
|
||
|
_tCreate.tv_sec = 0;
|
||
|
_timerEvent->Set();
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Start the timer thread
|
||
|
_timerEvent = static_cast<EventLinux*>(EventWrapper::Create());
|
||
|
const char* threadName = "WebRtc_event_timer_thread";
|
||
|
_timerThread = ThreadWrapper::CreateThread(Run, this, kRealtimePriority,
|
||
|
threadName);
|
||
|
_periodic = periodic;
|
||
|
_time = time;
|
||
|
unsigned int id = 0;
|
||
|
if (_timerThread->Start(id))
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool EventLinux::Run(ThreadObj obj)
|
||
|
{
|
||
|
return static_cast<EventLinux*>(obj)->Process();
|
||
|
}
|
||
|
|
||
|
bool EventLinux::Process()
|
||
|
{
|
||
|
if (_tCreate.tv_sec == 0)
|
||
|
{
|
||
|
#ifndef WEBRTC_MAC
|
||
|
#ifdef WEBRTC_CLOCK_TYPE_REALTIME
|
||
|
clock_gettime(CLOCK_REALTIME, &_tCreate);
|
||
|
#else
|
||
|
clock_gettime(CLOCK_MONOTONIC, &_tCreate);
|
||
|
#endif
|
||
|
#else
|
||
|
timeval tVal;
|
||
|
struct timezone tZone;
|
||
|
tZone.tz_minuteswest = 0;
|
||
|
tZone.tz_dsttime = 0;
|
||
|
gettimeofday(&tVal,&tZone);
|
||
|
TIMEVAL_TO_TIMESPEC(&tVal,&_tCreate);
|
||
|
#endif
|
||
|
_count=0;
|
||
|
}
|
||
|
|
||
|
timespec tEnd;
|
||
|
unsigned long long time = _time * ++_count;
|
||
|
tEnd.tv_sec = _tCreate.tv_sec + time/1000;
|
||
|
tEnd.tv_nsec = _tCreate.tv_nsec + (time - (time/1000)*1000)*E6;
|
||
|
|
||
|
if ( tEnd.tv_nsec >= E9 )
|
||
|
{
|
||
|
tEnd.tv_sec++;
|
||
|
tEnd.tv_nsec -= E9;
|
||
|
}
|
||
|
|
||
|
switch(_timerEvent->Wait(tEnd))
|
||
|
{
|
||
|
case kEventSignaled:
|
||
|
return true;
|
||
|
case kEventError:
|
||
|
return false;
|
||
|
case kEventTimeout:
|
||
|
break;
|
||
|
}
|
||
|
if(_periodic || _count==1)
|
||
|
{
|
||
|
Set();
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool EventLinux::StopTimer()
|
||
|
{
|
||
|
if(_timerThread)
|
||
|
{
|
||
|
_timerThread->SetNotAlive();
|
||
|
}
|
||
|
if (_timerEvent)
|
||
|
{
|
||
|
_timerEvent->Set();
|
||
|
}
|
||
|
if (_timerThread)
|
||
|
{
|
||
|
if(!_timerThread->Stop())
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
delete _timerThread;
|
||
|
_timerThread = 0;
|
||
|
}
|
||
|
if (_timerEvent)
|
||
|
{
|
||
|
delete _timerEvent;
|
||
|
_timerEvent = 0;
|
||
|
}
|
||
|
|
||
|
// Set time to zero to force new reference time for the timer.
|
||
|
memset(&_tCreate, 0, sizeof(_tCreate));
|
||
|
_count=0;
|
||
|
return true;
|
||
|
}
|
||
|
} // namespace webrtc
|