blob: 75252ea65d8e19c91a53f48ba6f453fe2794ae93 [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <lib/syslog/cpp/macros.h>
#include <pthread.h>
#include <thread>
#include <perftest/perftest.h>
#include "test_runner.h"
namespace {
// Test the round trip time for waking up threads using pthread condition
// variables (condvars). Condvars are implemented using futexes, so we
// expect this to be a bit slower than FutexTest due to the overhead that
// pthread's condvar implementation adds.
class PthreadCondvarTest {
public:
PthreadCondvarTest() {
FX_CHECK(pthread_mutex_init(&mutex_, nullptr) == 0);
FX_CHECK(pthread_cond_init(&condvar1_, nullptr) == 0);
FX_CHECK(pthread_cond_init(&condvar2_, nullptr) == 0);
thread_ = std::thread([this]() { ThreadFunc(); });
}
~PthreadCondvarTest() {
// Tell the thread to shut down.
FX_CHECK(pthread_mutex_lock(&mutex_) == 0);
state_ = EXIT;
FX_CHECK(pthread_cond_signal(&condvar1_) == 0);
FX_CHECK(pthread_mutex_unlock(&mutex_) == 0);
thread_.join();
FX_CHECK(pthread_cond_destroy(&condvar1_) == 0);
FX_CHECK(pthread_cond_destroy(&condvar2_) == 0);
FX_CHECK(pthread_mutex_destroy(&mutex_) == 0);
}
void Run() {
FX_CHECK(pthread_mutex_lock(&mutex_) == 0);
// Wake the child.
state_ = WAKE_CHILD;
FX_CHECK(pthread_cond_signal(&condvar1_) == 0);
// Wait for the reply.
while (state_ != REPLY_TO_PARENT)
FX_CHECK(pthread_cond_wait(&condvar2_, &mutex_) == 0);
FX_CHECK(pthread_mutex_unlock(&mutex_) == 0);
}
private:
void ThreadFunc() {
FX_CHECK(pthread_mutex_lock(&mutex_) == 0);
for (;;) {
if (state_ == EXIT)
break;
if (state_ == WAKE_CHILD) {
state_ = REPLY_TO_PARENT;
FX_CHECK(pthread_cond_signal(&condvar2_) == 0);
}
FX_CHECK(pthread_cond_wait(&condvar1_, &mutex_) == 0);
}
FX_CHECK(pthread_mutex_unlock(&mutex_) == 0);
}
std::thread thread_;
pthread_mutex_t mutex_;
pthread_cond_t condvar1_; // Signals from parent to child.
pthread_cond_t condvar2_; // Signals from child to parent.
enum { INITIAL, WAKE_CHILD, REPLY_TO_PARENT, EXIT } state_ = INITIAL;
};
void RegisterTests() {
fbenchmark::RegisterTest<PthreadCondvarTest>("RoundTrip_PthreadCondvar_SingleProcess");
}
PERFTEST_CTOR(RegisterTests)
} // namespace