git-svn-id: http://webrtc.googlecode.com/svn/trunk@6 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/system_wrappers/source/event_linux.cc b/system_wrappers/source/event_linux.cc
new file mode 100644
index 0000000..dddd31c
--- /dev/null
+++ b/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