mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-27 18:27:43 +00:00
295 lines
6.5 KiB
C++
295 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 "webrtc/system_wrappers/source/event_posix.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* EventPosix::Create() {
|
||
|
EventPosix* ptr = new EventPosix;
|
||
|
if (!ptr) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
const int error = ptr->Construct();
|
||
|
if (error) {
|
||
|
delete ptr;
|
||
|
return NULL;
|
||
|
}
|
||
|
return ptr;
|
||
|
}
|
||
|
|
||
|
EventPosix::EventPosix()
|
||
|
: timer_thread_(0),
|
||
|
timer_event_(0),
|
||
|
periodic_(false),
|
||
|
time_(0),
|
||
|
count_(0),
|
||
|
state_(kDown) {
|
||
|
}
|
||
|
|
||
|
int EventPosix::Construct() {
|
||
|
// Set start time to zero
|
||
|
memset(&created_at_, 0, sizeof(created_at_));
|
||
|
|
||
|
pthread_mutexattr_t attr;
|
||
|
pthread_mutexattr_init(&attr);
|
||
|
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||
|
int result = pthread_mutex_init(&mutex_, &attr);
|
||
|
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 cond_attr;
|
||
|
result = pthread_condattr_init(&cond_attr);
|
||
|
if (result != 0) {
|
||
|
return -1;
|
||
|
}
|
||
|
result = pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
|
||
|
if (result != 0) {
|
||
|
return -1;
|
||
|
}
|
||
|
result = pthread_cond_init(&cond_, &cond_attr);
|
||
|
if (result != 0) {
|
||
|
return -1;
|
||
|
}
|
||
|
result = pthread_condattr_destroy(&cond_attr);
|
||
|
if (result != 0) {
|
||
|
return -1;
|
||
|
}
|
||
|
#endif
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
EventPosix::~EventPosix() {
|
||
|
StopTimer();
|
||
|
pthread_cond_destroy(&cond_);
|
||
|
pthread_mutex_destroy(&mutex_);
|
||
|
}
|
||
|
|
||
|
bool EventPosix::Reset() {
|
||
|
if (0 != pthread_mutex_lock(&mutex_)) {
|
||
|
return false;
|
||
|
}
|
||
|
state_ = kDown;
|
||
|
pthread_mutex_unlock(&mutex_);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool EventPosix::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 EventPosix::Wait(unsigned long timeout) {
|
||
|
int ret_val = 0;
|
||
|
if (0 != pthread_mutex_lock(&mutex_)) {
|
||
|
return kEventError;
|
||
|
}
|
||
|
|
||
|
if (kDown == state_) {
|
||
|
if (WEBRTC_EVENT_INFINITE != timeout) {
|
||
|
timespec end_at;
|
||
|
#ifndef WEBRTC_MAC
|
||
|
#ifdef WEBRTC_CLOCK_TYPE_REALTIME
|
||
|
clock_gettime(CLOCK_REALTIME, &end_at);
|
||
|
#else
|
||
|
clock_gettime(CLOCK_MONOTONIC, &end_at);
|
||
|
#endif
|
||
|
#else
|
||
|
timeval value;
|
||
|
struct timezone time_zone;
|
||
|
time_zone.tz_minuteswest = 0;
|
||
|
time_zone.tz_dsttime = 0;
|
||
|
gettimeofday(&value, &time_zone);
|
||
|
TIMEVAL_TO_TIMESPEC(&value, &end_at);
|
||
|
#endif
|
||
|
end_at.tv_sec += timeout / 1000;
|
||
|
end_at.tv_nsec += (timeout - (timeout / 1000) * 1000) * E6;
|
||
|
|
||
|
if (end_at.tv_nsec >= E9) {
|
||
|
end_at.tv_sec++;
|
||
|
end_at.tv_nsec -= E9;
|
||
|
}
|
||
|
ret_val = pthread_cond_timedwait(&cond_, &mutex_, &end_at);
|
||
|
} else {
|
||
|
ret_val = pthread_cond_wait(&cond_, &mutex_);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
state_ = kDown;
|
||
|
pthread_mutex_unlock(&mutex_);
|
||
|
|
||
|
switch (ret_val) {
|
||
|
case 0:
|
||
|
return kEventSignaled;
|
||
|
case ETIMEDOUT:
|
||
|
return kEventTimeout;
|
||
|
default:
|
||
|
return kEventError;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
EventTypeWrapper EventPosix::Wait(timespec& wake_at) {
|
||
|
int ret_val = 0;
|
||
|
if (0 != pthread_mutex_lock(&mutex_)) {
|
||
|
return kEventError;
|
||
|
}
|
||
|
|
||
|
if (kUp != state_) {
|
||
|
ret_val = pthread_cond_timedwait(&cond_, &mutex_, &wake_at);
|
||
|
}
|
||
|
state_ = kDown;
|
||
|
|
||
|
pthread_mutex_unlock(&mutex_);
|
||
|
|
||
|
switch (ret_val) {
|
||
|
case 0:
|
||
|
return kEventSignaled;
|
||
|
case ETIMEDOUT:
|
||
|
return kEventTimeout;
|
||
|
default:
|
||
|
return kEventError;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool EventPosix::StartTimer(bool periodic, unsigned long time) {
|
||
|
pthread_mutex_lock(&mutex_);
|
||
|
if (timer_thread_) {
|
||
|
if (periodic_) {
|
||
|
// Timer already started.
|
||
|
pthread_mutex_unlock(&mutex_);
|
||
|
return false;
|
||
|
} else {
|
||
|
// New one shot timer
|
||
|
time_ = time;
|
||
|
created_at_.tv_sec = 0;
|
||
|
timer_event_->Set();
|
||
|
pthread_mutex_unlock(&mutex_);
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Start the timer thread
|
||
|
timer_event_ = static_cast<EventPosix*>(EventWrapper::Create());
|
||
|
const char* thread_name = "WebRtc_event_timer_thread";
|
||
|
timer_thread_ = ThreadWrapper::CreateThread(Run, this, kRealtimePriority,
|
||
|
thread_name);
|
||
|
periodic_ = periodic;
|
||
|
time_ = time;
|
||
|
unsigned int id = 0;
|
||
|
bool started = timer_thread_->Start(id);
|
||
|
pthread_mutex_unlock(&mutex_);
|
||
|
|
||
|
return started;
|
||
|
}
|
||
|
|
||
|
bool EventPosix::Run(ThreadObj obj) {
|
||
|
return static_cast<EventPosix*>(obj)->Process();
|
||
|
}
|
||
|
|
||
|
bool EventPosix::Process() {
|
||
|
pthread_mutex_lock(&mutex_);
|
||
|
if (created_at_.tv_sec == 0) {
|
||
|
#ifndef WEBRTC_MAC
|
||
|
#ifdef WEBRTC_CLOCK_TYPE_REALTIME
|
||
|
clock_gettime(CLOCK_REALTIME, &created_at_);
|
||
|
#else
|
||
|
clock_gettime(CLOCK_MONOTONIC, &created_at_);
|
||
|
#endif
|
||
|
#else
|
||
|
timeval value;
|
||
|
struct timezone time_zone;
|
||
|
time_zone.tz_minuteswest = 0;
|
||
|
time_zone.tz_dsttime = 0;
|
||
|
gettimeofday(&value, &time_zone);
|
||
|
TIMEVAL_TO_TIMESPEC(&value, &created_at_);
|
||
|
#endif
|
||
|
count_ = 0;
|
||
|
}
|
||
|
|
||
|
timespec end_at;
|
||
|
unsigned long long time = time_ * ++count_;
|
||
|
end_at.tv_sec = created_at_.tv_sec + time / 1000;
|
||
|
end_at.tv_nsec = created_at_.tv_nsec + (time - (time / 1000) * 1000) * E6;
|
||
|
|
||
|
if (end_at.tv_nsec >= E9) {
|
||
|
end_at.tv_sec++;
|
||
|
end_at.tv_nsec -= E9;
|
||
|
}
|
||
|
|
||
|
pthread_mutex_unlock(&mutex_);
|
||
|
switch (timer_event_->Wait(end_at)) {
|
||
|
case kEventSignaled:
|
||
|
return true;
|
||
|
case kEventError:
|
||
|
return false;
|
||
|
case kEventTimeout:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pthread_mutex_lock(&mutex_);
|
||
|
if (periodic_ || count_ == 1)
|
||
|
Set();
|
||
|
pthread_mutex_unlock(&mutex_);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool EventPosix::StopTimer() {
|
||
|
if (timer_thread_) {
|
||
|
timer_thread_->SetNotAlive();
|
||
|
}
|
||
|
if (timer_event_) {
|
||
|
timer_event_->Set();
|
||
|
}
|
||
|
if (timer_thread_) {
|
||
|
if (!timer_thread_->Stop()) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
delete timer_thread_;
|
||
|
timer_thread_ = 0;
|
||
|
}
|
||
|
if (timer_event_) {
|
||
|
delete timer_event_;
|
||
|
timer_event_ = 0;
|
||
|
}
|
||
|
|
||
|
// Set time to zero to force new reference time for the timer.
|
||
|
memset(&created_at_, 0, sizeof(created_at_));
|
||
|
count_ = 0;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
} // namespace webrtc
|