blob: c7f1317c7c2c48f6a04a342af743d84a862b5a6a [file] [log] [blame] [edit]
// 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/runner.h"
#include <lib/syslog/cpp/macros.h>
#include <lib/zx/clock.h>
#include "src/sys/fuzzing/common/status.h"
namespace fuzzing {
namespace {
// This enum is used with |Pend| to schedule specific actions.
enum Action : uint8_t {
kExecute,
kMinimize,
kCleanse,
kFuzz,
kMerge,
kStop,
};
} // namespace
Runner::Runner() : action_(kStop) {
// Start the worker and ensure is up and running.
worker_ = std::thread([this]() { Worker(); });
bool idle = false;
do {
std::this_thread::yield();
{
std::lock_guard<std::mutex> lock(mutex_);
idle = idle_;
}
} while (!idle);
}
Runner::~Runner() {
{
std::lock_guard<std::mutex> lock(mutex_);
action_ = kStop;
}
sync_completion_signal(&worker_sync_);
worker_.join();
}
zx_status_t Runner::Configure(const std::shared_ptr<Options>& options) {
std::lock_guard<std::mutex> lock(mutex_);
if (!idle_) {
FX_LOGS(WARNING) << "Attempted to re-configure when fuzzing already in progress.";
return ZX_ERR_BAD_STATE;
}
ConfigureImpl(options);
return ZX_OK;
}
///////////////////////////////////////////////////////////////
// Dispatcher methods
void Runner::Pend(uint8_t action, Input input, fit::function<void(zx_status_t)> callback) {
std::lock_guard<std::mutex> lock(mutex_);
if (!idle_) {
FX_LOGS(WARNING) << "Attempted to perform action when fuzzing already in progress.";
callback(ZX_ERR_BAD_STATE);
return;
}
idle_ = false;
action_ = action;
input_ = std::move(input);
callback_ = std::move(callback);
sync_completion_signal(&worker_sync_);
}
void Runner::Execute(Input input, fit::function<void(zx_status_t)> callback) {
Pend(kExecute, std::move(input), std::move(callback));
}
void Runner::Minimize(Input input, fit::function<void(zx_status_t)> callback) {
Pend(kMinimize, std::move(input), std::move(callback));
}
void Runner::Cleanse(Input input, fit::function<void(zx_status_t)> callback) {
Pend(kCleanse, std::move(input), std::move(callback));
}
void Runner::Fuzz(fit::function<void(zx_status_t)> callback) {
Input input;
Pend(kFuzz, std::move(input), std::move(callback));
}
void Runner::Merge(fit::function<void(zx_status_t)> callback) {
Input input;
Pend(kMerge, std::move(input), std::move(callback));
}
void Runner::Worker() {
while (true) {
{
std::lock_guard<std::mutex> lock(mutex_);
idle_ = true;
}
// Wait indefinitely. Destroying this object will send |kStop|.
sync_completion_wait(&worker_sync_, ZX_TIME_INFINITE);
sync_completion_reset(&worker_sync_);
uint8_t action;
Input input;
fit::function<void(zx_status_t)> callback;
{
std::lock_guard<std::mutex> lock(mutex_);
action = action_;
input = std::move(input_);
callback = std::move(callback_);
}
if (action == kStop) {
return;
}
zx_status_t status = ZX_OK;
ClearErrors();
switch (action) {
case kExecute:
status = SyncExecute(input);
break;
case kMinimize:
status = SyncMinimize(input);
break;
case kCleanse:
status = SyncCleanse(input);
break;
case kFuzz:
status = SyncFuzz();
break;
case kMerge:
status = SyncMerge();
break;
default:
FX_NOTREACHED();
}
callback(status);
}
}
///////////////////////////////////////////////////////////////
// Status-related methods.
void Runner::AddMonitor(MonitorPtr monitor) {
std::lock_guard<std::mutex> lock(mutex_);
monitors_.push_back(std::move(monitor));
}
Status Runner::CollectStatus() {
std::lock_guard<std::mutex> lock(mutex_);
return CollectStatusLocked();
}
void Runner::UpdateMonitors(UpdateReason reason) {
std::lock_guard<std::mutex> lock(mutex_);
auto status = CollectStatusLocked();
for (auto& monitor : monitors_) {
auto copy = CopyStatus(status);
monitor->Update(reason, std::move(copy), []() {});
}
if (reason == UpdateReason::DONE) {
monitors_.clear();
}
}
void Runner::ClearErrors() {
result_ = Result::NO_ERRORS;
result_input_.Clear();
}
} // namespace fuzzing