android: Implement Semaphore with a condition variable and mutex

Bionic uses negative values of a semaphore to represent contention.
`sem_timedwait` fails to restore the value to 0 on timeout resulting in
an error (EBUSY) upon calling `sem_destroy`.

Bug: crashpad:30
Change-Id: If1c73a54a879ebd003b0792ebb8f68ceb83ac8bb
Reviewed-on: https://chromium-review.googlesource.com/894106
Reviewed-by: Mark Mentovai <mark@chromium.org>
Commit-Queue: Joshua Peraza <jperaza@chromium.org>
This commit is contained in:
Joshua Peraza 2018-01-30 12:20:03 -08:00 committed by Commit Bot
parent c9244d58df
commit 441789be5b
3 changed files with 51 additions and 3 deletions

View File

@ -23,6 +23,9 @@
#include <dispatch/dispatch.h>
#elif defined(OS_WIN)
#include <windows.h>
#elif defined(OS_ANDROID)
#include <condition_variable>
#include <mutex>
#else
#include <semaphore.h>
#endif
@ -77,6 +80,10 @@ class Semaphore {
dispatch_semaphore_t semaphore_;
#elif defined(OS_WIN)
HANDLE semaphore_;
#elif defined(OS_ANDROID)
std::condition_variable cv_;
std::mutex mutex_;
int value_;
#else
sem_t semaphore_;
#endif

View File

@ -18,13 +18,51 @@
#include <math.h>
#include <time.h>
#include <chrono>
#include "base/logging.h"
#include "base/posix/eintr_wrapper.h"
#include "util/misc/time.h"
namespace crashpad {
#if !defined(OS_MACOSX)
#if defined(OS_ANDROID)
Semaphore::Semaphore(int value) : cv_(), mutex_(), value_(value) {}
Semaphore::~Semaphore() = default;
void Semaphore::Wait() {
std::unique_lock<std::mutex> lock(mutex_);
cv_.wait(lock, [this] { return this->value_ > 0; });
--value_;
}
bool Semaphore::TimedWait(double seconds) {
DCHECK_GE(seconds, 0.0);
if (isinf(seconds)) {
Wait();
return true;
}
std::unique_lock<std::mutex> lock(mutex_);
if (!cv_.wait_for(lock, std::chrono::duration<double>(seconds), [this] {
return this->value_ > 0;
})) {
return false;
}
--value_;
return true;
}
void Semaphore::Signal() {
std::lock_guard<std::mutex> lock(mutex_);
++value_;
cv_.notify_one();
}
#elif !defined(OS_MACOSX)
Semaphore::Semaphore(int value) {
PCHECK(sem_init(&semaphore_, 0, value) == 0) << "sem_init";
@ -65,6 +103,6 @@ void Semaphore::Signal() {
PCHECK(sem_post(&semaphore_) == 0) << "sem_post";
}
#endif
#endif // OS_ANDROID
} // namespace crashpad

View File

@ -41,7 +41,10 @@ TEST(Semaphore, TimedWait) {
TEST(Semaphore, TimedWaitTimeout) {
Semaphore semaphore(0);
EXPECT_FALSE(semaphore.TimedWait(0.01)); // 10ms
semaphore.Signal();
constexpr double kTenMs = 0.01;
EXPECT_TRUE(semaphore.TimedWait(kTenMs));
EXPECT_FALSE(semaphore.TimedWait(kTenMs));
}
TEST(Semaphore, TimedWaitInfinite_0) {