aboutsummaryrefslogtreecommitdiff
path: root/src/system_wrappers/source/event_linux.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/system_wrappers/source/event_linux.cc')
-rw-r--r--src/system_wrappers/source/event_linux.cc324
1 files changed, 324 insertions, 0 deletions
diff --git a/src/system_wrappers/source/event_linux.cc b/src/system_wrappers/source/event_linux.cc
new file mode 100644
index 0000000000..dddd31c15c
--- /dev/null
+++ b/src/system_wrappers/source/event_linux.cc
@@ -0,0 +1,324 @@
+/*
+ * 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