blob: 80f0a246129fcc0ad872ff4afa1bb9f02dd248cb [file] [log] [blame]
// Copyright 2021 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 "src/sys/fuzzing/common/sync-wait.h"
#include <lib/backtrace-request/backtrace-request.h>
#include <lib/syslog/cpp/macros.h>
#include <lib/zx/clock.h>
namespace fuzzing {
using Waiter = fit::function<zx_status_t(zx::time)>;
zx_duration_t gThreshold = ZX_SEC(30);
// Waiter functions
zx_status_t WaitFor(const char* what, Waiter* waiter) {
if (gThreshold <= 0) {
return (*waiter)(zx::time::infinite());
}
zx::duration threshold(gThreshold);
auto deadline = zx::deadline_after(threshold);
auto status = (*waiter)(deadline);
if (status != ZX_ERR_TIMED_OUT) {
return status;
}
auto elapsed = threshold / zx::sec(1);
FX_LOGS(WARNING) << "Still waiting for " << what << " after " << elapsed << " seconds...";
if (gThreshold >= ZX_SEC(30)) {
backtrace_request();
}
auto start = zx::clock::get_monotonic() - threshold;
status = (*waiter)(zx::time::infinite());
elapsed = (zx::clock::get_monotonic() - start) / zx::sec(1);
FX_LOGS(WARNING) << "Done waiting for " << what << " after " << elapsed << " seconds.";
return status;
}
zx_status_t PollFor(const char* what, Waiter* waiter, zx::duration interval) {
Waiter wrapper = [waiter, interval](zx::time deadline) {
while (true) {
auto step = zx::deadline_after(interval);
auto status = (*waiter)(step);
if (status != ZX_ERR_TIMED_OUT) {
return status;
}
if (deadline < zx::clock::get_monotonic()) {
return ZX_ERR_TIMED_OUT;
}
}
};
return WaitFor(what, &wrapper);
}
void SetThreshold(zx::duration threshold) { gThreshold = threshold.get(); }
void ResetThreshold() { gThreshold = ZX_SEC(30); }
void DisableSlowWaitLogging() { gThreshold = 0; }
// SyncWait methods
SyncWait::SyncWait()
: waiter_([this](zx::time deadline) {
++waiters_;
auto status = sync_completion_wait_deadline(&sync_, deadline.get());
auto waiters = waiters_.fetch_sub(1);
FX_DCHECK(waiters != 0);
return status;
}) {}
SyncWait::~SyncWait() { FX_DCHECK(waiters_ == 0); }
void SyncWait::WaitFor(const char* what) { ::fuzzing::WaitFor(what, &waiter_); }
zx_status_t SyncWait::TimedWait(zx::duration duration) {
return waiter_(zx::deadline_after(duration));
}
zx_status_t SyncWait::WaitUntil(zx::time deadline) { return waiter_(deadline); }
void SyncWait::Signal() { sync_completion_signal(&sync_); }
void SyncWait::Reset() { sync_completion_reset(&sync_); }
} // namespace fuzzing