blob: 85e6439a8fbe02699d763ebe1240c88db66420a9 [file] [log] [blame]
// Copyright 2018 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 "garnet/lib/debugger_utils/threads.h"
#include <algorithm>
#include <lib/fxl/logging.h>
#include "garnet/lib/debugger_utils/jobs.h"
#include "garnet/lib/debugger_utils/util.h"
namespace debugger_utils {
zx_status_t WithThreadSuspended(
const zx::thread& thread, zx::duration thread_suspend_timeout,
const WithThreadSuspendedFunction& function) {
zx::suspend_token suspend_token;
auto status = thread.suspend(&suspend_token);
if (status != ZX_OK) {
FXL_LOG(ERROR) << "unable to suspend thread "
<< GetKoid(thread)
<< ": " << ZxErrorString(status);
return status;
}
zx_signals_t pending;
status = thread.wait_one(ZX_THREAD_SUSPENDED | ZX_THREAD_TERMINATED,
zx::deadline_after(thread_suspend_timeout),
&pending);
if (status != ZX_OK) {
FXL_LOG(ERROR) << "error waiting for thread "
<< GetKoid(thread)
<< " to suspend: "
<< ZxErrorString(status);
return status;
}
if (pending & ZX_THREAD_TERMINATED) {
FXL_LOG(WARNING) << "thread "
<< GetKoid(thread)
<< " terminated";
return ZX_ERR_NOT_FOUND;
}
return function(thread);
}
zx_status_t WithAllThreadsSuspended(
const std::vector<zx::thread>& threads,
zx::duration thread_suspend_timeout,
const WithThreadSuspendedFunction& function) {
std::vector<zx::suspend_token> suspend_tokens;
for (const auto& thread : threads) {
zx::suspend_token suspend_token;
auto status = thread.suspend(&suspend_token);
if (status != ZX_OK) {
FXL_LOG(WARNING) << "unable to suspend thread "
<< GetKoid(thread)
<< ": " << ZxErrorString(status);
suspend_tokens.emplace_back(zx::suspend_token{});
} else {
suspend_tokens.emplace_back(std::move(suspend_token));
}
}
for (size_t i = 0; i < threads.size(); ++i) {
if (!suspend_tokens[i].is_valid())
continue;
zx_signals_t pending;
const zx::thread& thread{threads[i]};
auto status = thread.wait_one(ZX_THREAD_SUSPENDED | ZX_THREAD_TERMINATED,
zx::deadline_after(thread_suspend_timeout),
&pending);
if (status != ZX_OK) {
FXL_LOG(ERROR) << "error waiting for thread "
<< GetKoid(thread)
<< " to suspend: "
<< ZxErrorString(status);
return status;
}
if (pending & ZX_THREAD_TERMINATED) {
FXL_LOG(WARNING) << "thread "
<< GetKoid(thread)
<< " terminated";
suspend_tokens[i].reset();
continue;
}
}
for (size_t i = 0; i < threads.size(); ++i) {
if (suspend_tokens[i].is_valid()) {
const zx::thread& thread{threads[i]};
auto status = function(thread);
if (status != ZX_OK)
return status;
}
}
return ZX_OK;
}
} // namespace debugger_utils