Note: We no longer publish the latest version of our code here. We primarily use a kumc-bmi github organization. The heron ETL repository, in particular, is not public. Peers in the informatics community should see MultiSiteDev for details on requesting access.

source: webrtc/webrtc/system_wrappers/source/event_posix.cc @ 0:4bda6873e34c

pub_scrub_3792 tip
Last change on this file since 0:4bda6873e34c was 0:4bda6873e34c, checked in by Michael Prittie <mprittie@…>, 6 years ago

Scrubbed password for publication.

File size: 6.5 KB
Line 
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 "webrtc/system_wrappers/source/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
21namespace webrtc {
22
23const long int E6 = 1000000;
24const long int E9 = 1000 * E6;
25
26EventWrapper* EventPosix::Create() {
27  EventPosix* ptr = new EventPosix;
28  if (!ptr) {
29    return NULL;
30  }
31
32  const int error = ptr->Construct();
33  if (error) {
34    delete ptr;
35    return NULL;
36  }
37  return ptr;
38}
39
40EventPosix::EventPosix()
41    : timer_thread_(0),
42      timer_event_(0),
43      periodic_(false),
44      time_(0),
45      count_(0),
46      state_(kDown) {
47}
48
49int EventPosix::Construct() {
50  // Set start time to zero
51  memset(&created_at_, 0, sizeof(created_at_));
52
53  pthread_mutexattr_t attr;
54  pthread_mutexattr_init(&attr);
55  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
56  int result = pthread_mutex_init(&mutex_, &attr);
57  if (result != 0) {
58    return -1;
59  }
60#ifdef WEBRTC_CLOCK_TYPE_REALTIME
61  result = pthread_cond_init(&cond_, 0);
62  if (result != 0) {
63    return -1;
64  }
65#else
66  pthread_condattr_t cond_attr;
67  result = pthread_condattr_init(&cond_attr);
68  if (result != 0) {
69    return -1;
70  }
71  result = pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
72  if (result != 0) {
73    return -1;
74  }
75  result = pthread_cond_init(&cond_, &cond_attr);
76  if (result != 0) {
77    return -1;
78  }
79  result = pthread_condattr_destroy(&cond_attr);
80  if (result != 0) {
81    return -1;
82  }
83#endif
84  return 0;
85}
86
87EventPosix::~EventPosix() {
88  StopTimer();
89  pthread_cond_destroy(&cond_);
90  pthread_mutex_destroy(&mutex_);
91}
92
93bool EventPosix::Reset() {
94  if (0 != pthread_mutex_lock(&mutex_)) {
95    return false;
96  }
97  state_ = kDown;
98  pthread_mutex_unlock(&mutex_);
99  return true;
100}
101
102bool EventPosix::Set() {
103  if (0 != pthread_mutex_lock(&mutex_)) {
104    return false;
105  }
106  state_ = kUp;
107  // Release all waiting threads
108  pthread_cond_broadcast(&cond_);
109  pthread_mutex_unlock(&mutex_);
110  return true;
111}
112
113EventTypeWrapper EventPosix::Wait(unsigned long timeout) {
114  int ret_val = 0;
115  if (0 != pthread_mutex_lock(&mutex_)) {
116    return kEventError;
117  }
118
119  if (kDown == state_) {
120    if (WEBRTC_EVENT_INFINITE != timeout) {
121      timespec end_at;
122#ifndef WEBRTC_MAC
123#ifdef WEBRTC_CLOCK_TYPE_REALTIME
124      clock_gettime(CLOCK_REALTIME, &end_at);
125#else
126      clock_gettime(CLOCK_MONOTONIC, &end_at);
127#endif
128#else
129      timeval value;
130      struct timezone time_zone;
131      time_zone.tz_minuteswest = 0;
132      time_zone.tz_dsttime = 0;
133      gettimeofday(&value, &time_zone);
134      TIMEVAL_TO_TIMESPEC(&value, &end_at);
135#endif
136      end_at.tv_sec  += timeout / 1000;
137      end_at.tv_nsec += (timeout - (timeout / 1000) * 1000) * E6;
138
139      if (end_at.tv_nsec >= E9) {
140        end_at.tv_sec++;
141        end_at.tv_nsec -= E9;
142      }
143      ret_val = pthread_cond_timedwait(&cond_, &mutex_, &end_at);
144    } else {
145      ret_val = pthread_cond_wait(&cond_, &mutex_);
146    }
147  }
148
149  state_ = kDown;
150  pthread_mutex_unlock(&mutex_);
151
152  switch (ret_val) {
153    case 0:
154      return kEventSignaled;
155    case ETIMEDOUT:
156      return kEventTimeout;
157    default:
158      return kEventError;
159  }
160}
161
162EventTypeWrapper EventPosix::Wait(timespec& wake_at) {
163  int ret_val = 0;
164  if (0 != pthread_mutex_lock(&mutex_)) {
165    return kEventError;
166  }
167
168  if (kUp != state_) {
169    ret_val = pthread_cond_timedwait(&cond_, &mutex_, &wake_at);
170  }
171  state_ = kDown;
172
173  pthread_mutex_unlock(&mutex_);
174
175  switch (ret_val) {
176    case 0:
177      return kEventSignaled;
178    case ETIMEDOUT:
179      return kEventTimeout;
180    default:
181      return kEventError;
182  }
183}
184
185bool EventPosix::StartTimer(bool periodic, unsigned long time) {
186  pthread_mutex_lock(&mutex_);
187  if (timer_thread_) {
188    if (periodic_) {
189      // Timer already started.
190      pthread_mutex_unlock(&mutex_);
191      return false;
192    } else  {
193      // New one shot timer
194      time_ = time;
195      created_at_.tv_sec = 0;
196      timer_event_->Set();
197      pthread_mutex_unlock(&mutex_);
198      return true;
199    }
200  }
201
202  // Start the timer thread
203  timer_event_ = static_cast<EventPosix*>(EventWrapper::Create());
204  const char* thread_name = "WebRtc_event_timer_thread";
205  timer_thread_ = ThreadWrapper::CreateThread(Run, this, kRealtimePriority,
206                                              thread_name);
207  periodic_ = periodic;
208  time_ = time;
209  unsigned int id = 0;
210  bool started = timer_thread_->Start(id);
211  pthread_mutex_unlock(&mutex_);
212
213  return started;
214}
215
216bool EventPosix::Run(ThreadObj obj) {
217  return static_cast<EventPosix*>(obj)->Process();
218}
219
220bool EventPosix::Process() {
221  pthread_mutex_lock(&mutex_);
222  if (created_at_.tv_sec == 0) {
223#ifndef WEBRTC_MAC
224#ifdef WEBRTC_CLOCK_TYPE_REALTIME
225    clock_gettime(CLOCK_REALTIME, &created_at_);
226#else
227    clock_gettime(CLOCK_MONOTONIC, &created_at_);
228#endif
229#else
230    timeval value;
231    struct timezone time_zone;
232    time_zone.tz_minuteswest = 0;
233    time_zone.tz_dsttime = 0;
234    gettimeofday(&value, &time_zone);
235    TIMEVAL_TO_TIMESPEC(&value, &created_at_);
236#endif
237    count_ = 0;
238  }
239
240  timespec end_at;
241  unsigned long long time = time_ * ++count_;
242  end_at.tv_sec  = created_at_.tv_sec + time / 1000;
243  end_at.tv_nsec = created_at_.tv_nsec + (time - (time / 1000) * 1000) * E6;
244
245  if (end_at.tv_nsec >= E9) {
246    end_at.tv_sec++;
247    end_at.tv_nsec -= E9;
248  }
249
250  pthread_mutex_unlock(&mutex_);
251  switch (timer_event_->Wait(end_at)) {
252    case kEventSignaled:
253      return true;
254    case kEventError:
255      return false;
256    case kEventTimeout:
257      break;
258  }
259
260  pthread_mutex_lock(&mutex_);
261  if (periodic_ || count_ == 1)
262    Set();
263  pthread_mutex_unlock(&mutex_);
264
265  return true;
266}
267
268bool EventPosix::StopTimer() {
269  if (timer_thread_) {
270    timer_thread_->SetNotAlive();
271  }
272  if (timer_event_) {
273    timer_event_->Set();
274  }
275  if (timer_thread_) {
276    if (!timer_thread_->Stop()) {
277      return false;
278    }
279
280    delete timer_thread_;
281    timer_thread_ = 0;
282  }
283  if (timer_event_) {
284    delete timer_event_;
285    timer_event_ = 0;
286  }
287
288  // Set time to zero to force new reference time for the timer.
289  memset(&created_at_, 0, sizeof(created_at_));
290  count_ = 0;
291  return true;
292}
293
294}  // namespace webrtc
Note: See TracBrowser for help on using the repository browser.