14ee2ad04344446e610172a0e73949212923014dfSebastian Redl/*
22cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
32cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor *
42cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor *  Use of this source code is governed by a BSD-style license
52cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor *  that can be found in the LICENSE file in the root of the source
62cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor *  tree. An additional intellectual property rights grant can be found
72cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor *  in the file PATENTS.  All contributing project authors may
82cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor *  be found in the AUTHORS file in the root of the source tree.
92cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor */
10a4232eb646d89e7d52424bb42eb87d9061f39e63Sebastian Redl
112cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor#include "webrtc/base/event.h"
122cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor
132cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor#if defined(WEBRTC_WIN)
147faa2ec03a7ef120ac165bb45b6c70a8b20c9f1cSebastian Redl#include <windows.h>
15e737f5041a36d0befb39ffeed8d50ba15916d3daDouglas Gregor#elif defined(WEBRTC_POSIX)
16e737f5041a36d0befb39ffeed8d50ba15916d3daDouglas Gregor#include <pthread.h>
172cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor#include <sys/time.h>
182cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor#include <time.h>
192cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor#else
200b7489194f9f89fac39d57211c1e7953ae50251fDouglas Gregor#error "Must define either WEBRTC_WIN or WEBRTC_POSIX."
212cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor#endif
22a1ee0c548b8aa4aaf93d1917e304e3da13171a08John McCall
236ab7cd853e9c15cf986a8a7c3db1f8d20e275409Sebastian Redlnamespace rtc {
247c5d24efcd2e505b5739f7def08dfe25ce59a1b2Chris Lattner
256a5a23f8e7fb65e028c8092bc1d1a1d9dfe2e9bcDouglas Gregor#if defined(WEBRTC_WIN)
267c5d24efcd2e505b5739f7def08dfe25ce59a1b2Chris Lattner
2783d63c78810556d26b62ac4cbae2eda6cdd2570cSteve NaroffEvent::Event(bool manual_reset, bool initially_signaled)
2814f79002e58556798e86168c63e48d533287eda5Douglas Gregor    : is_manual_reset_(manual_reset),
293251ceb90b3fec68e86d6dcfa58836e20a7205c3Douglas Gregor      is_initially_signaled_(initially_signaled) {
3014f79002e58556798e86168c63e48d533287eda5Douglas Gregor  event_handle_ = ::CreateEvent(NULL,                 // Security attributes.
31bd94500d3aa60092fb0f1e90f53fb0d03fa502a8Douglas Gregor                                is_manual_reset_,
322bec0410d268779f601bd509e0302a500af7ac6aDouglas Gregor                                is_initially_signaled_,
33ab41e63821dc60ad144d0684df8d79a9eef86b75Douglas Gregor                                NULL);                // Name.
3417fc223395d51be582fc666bb6ea21bd1dff26dcDouglas Gregor  ASSERT(event_handle_ != NULL);
3517fc223395d51be582fc666bb6ea21bd1dff26dcDouglas Gregor}
362596e429a61602312bdd149786045b8a90cd2d10Daniel Dunbar
372cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas GregorEvent::~Event() {
3814f79002e58556798e86168c63e48d533287eda5Douglas Gregor  CloseHandle(event_handle_);
39b64c19365deab788753d29c9bc881253c3f16f37Douglas Gregor}
403c304bd9ec2b4611572d4cbae9e1727bbecb5dc9Chris Lattner
412cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregorvoid Event::Set() {
428538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl  SetEvent(event_handle_);
432cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor}
44ade5000c8763f4bec41f452d7efa3a9b2a6d4712Sebastian Redl
45ade5000c8763f4bec41f452d7efa3a9b2a6d4712Sebastian Redlvoid Event::Reset() {
46ade5000c8763f4bec41f452d7efa3a9b2a6d4712Sebastian Redl  ResetEvent(event_handle_);
47ade5000c8763f4bec41f452d7efa3a9b2a6d4712Sebastian Redl}
48ade5000c8763f4bec41f452d7efa3a9b2a6d4712Sebastian Redl
49ade5000c8763f4bec41f452d7efa3a9b2a6d4712Sebastian Redlbool Event::Wait(int cms) {
50ade5000c8763f4bec41f452d7efa3a9b2a6d4712Sebastian Redl  DWORD ms = (cms == kForever)? INFINITE : cms;
51ade5000c8763f4bec41f452d7efa3a9b2a6d4712Sebastian Redl  return (WaitForSingleObject(event_handle_, ms) == WAIT_OBJECT_0);
52ade5000c8763f4bec41f452d7efa3a9b2a6d4712Sebastian Redl}
532cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor
542cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor#elif defined(WEBRTC_POSIX)
552cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor
5612b1c7615d4f9a2edc544be499f895f16ac100edChris LattnerEvent::Event(bool manual_reset, bool initially_signaled)
572cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    : is_manual_reset_(manual_reset),
583397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl      event_status_(initially_signaled) {
59a4232eb646d89e7d52424bb42eb87d9061f39e63Sebastian Redl  VERIFY(pthread_mutex_init(&event_mutex_, NULL) == 0);
60a4232eb646d89e7d52424bb42eb87d9061f39e63Sebastian Redl  VERIFY(pthread_cond_init(&event_cond_, NULL) == 0);
612cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor}
622cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor
632cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas GregorEvent::~Event() {
648538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl  pthread_mutex_destroy(&event_mutex_);
652cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor  pthread_cond_destroy(&event_cond_);
663397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl}
678538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl
682cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregorvoid Event::Set() {
692cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor  pthread_mutex_lock(&event_mutex_);
702cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor  event_status_ = true;
712cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor  pthread_cond_broadcast(&event_cond_);
722cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor  pthread_mutex_unlock(&event_mutex_);
732cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor}
742cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor
752cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregorvoid Event::Reset() {
762cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor  pthread_mutex_lock(&event_mutex_);
772cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor  event_status_ = false;
782cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor  pthread_mutex_unlock(&event_mutex_);
793397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl}
802cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor
812cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregorbool Event::Wait(int cms) {
822cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor  pthread_mutex_lock(&event_mutex_);
833397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl  int error = 0;
842cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor
858538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl  if (cms != kForever) {
862cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    // Converting from seconds and microseconds (1e-6) plus
872cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    // milliseconds (1e-3) to seconds and nanoseconds (1e-9).
883397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl
892cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    struct timespec ts;
908538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl#if HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
912cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    // Use relative time version, which tends to be more efficient for
922cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    // pthread implementations where provided (like on Android).
933397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl    ts.tv_sec = cms / 1000;
941eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump    ts.tv_nsec = (cms % 1000) * 1000000;
958538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl#else
962cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    struct timeval tv;
972cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    gettimeofday(&tv, NULL);
983397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl
992cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    ts.tv_sec = tv.tv_sec + (cms / 1000);
1008538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl    ts.tv_nsec = tv.tv_usec * 1000 + (cms % 1000) * 1000000;
1012cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor
1022cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    // Handle overflow.
1033397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl    if (ts.tv_nsec >= 1000000000) {
1042cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor      ts.tv_sec++;
1058538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl      ts.tv_nsec -= 1000000000;
1062cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    }
1072cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor#endif
1083397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl
1091eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump    while (!event_status_ && error == 0) {
1101eb4433ac451dc16f4133a88af2d002ac26c58efMike Stump#if HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE
1118538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl      error = pthread_cond_timedwait_relative_np(
1122cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor          &event_cond_, &event_mutex_, &ts);
1132cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor#else
1143397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl      error = pthread_cond_timedwait(&event_cond_, &event_mutex_, &ts);
1152cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor#endif
1162cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    }
1170953e767ff7817f97b3ab20896b229891eeff45bJohn McCall  } else {
1182cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor    while (!event_status_ && error == 0)
1192cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor      error = pthread_cond_wait(&event_cond_, &event_mutex_);
1203397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl  }
1212cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor
1222cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor  // NOTE(liulk): Exactly one thread will auto-reset this event. All
1238538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl  // the other threads will think it's unsignaled.  This seems to be
1242cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor  // consistent with auto-reset events in WEBRTC_WIN
1252cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor  if (error == 0 && !is_manual_reset_)
1263397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl    event_status_ = false;
1272cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor
1288538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl  pthread_mutex_unlock(&event_mutex_);
1292cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor
1302cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor  return (error == 0);
1313397c5570369f19b2d6c52e898f708d75ceede1fSebastian Redl}
1322cf2634ffdb4f7c8d46cef3f8e60a55993f1c57aDouglas Gregor
1337e7eb3da052a6d80ddf2377cab0384c798f73f75Douglas Gregor#endif
1347e7eb3da052a6d80ddf2377cab0384c798f73f75Douglas Gregor
135c9490c000f515c29f200a1215328d8ab9a0f3818Douglas Gregor}  // namespace rtc
1368538e8d43a3a9bd439c987c0de37bcbf035dd391Sebastian Redl