trace: Port trace to Rust

This commit is contained in:
Clemens Wasser 2023-03-28 17:59:51 +02:00 committed by Peter Ammon
parent bc04abe3ec
commit 3ae16a5b95
14 changed files with 111 additions and 83 deletions

View file

@ -123,8 +123,7 @@ set(FISH_SRCS
src/pager.cpp src/parse_execution.cpp src/parse_tree.cpp src/parse_util.cpp
src/parser.cpp src/parser_keywords.cpp src/path.cpp src/postfork.cpp
src/proc.cpp src/re.cpp src/reader.cpp src/screen.cpp
src/signals.cpp src/tinyexpr.cpp
src/trace.cpp src/utf8.cpp
src/signals.cpp src/tinyexpr.cpp src/utf8.cpp
src/wcstringutil.cpp src/wgetopt.cpp src/wildcard.cpp
src/wutil.cpp src/fds.cpp src/rustffi.cpp
)

View file

@ -39,6 +39,7 @@ fn main() -> miette::Result<()> {
"src/timer.rs",
"src/tokenizer.rs",
"src/topic_monitor.rs",
"src/trace.rs",
"src/util.rs",
"src/wait_handle.rs",
"src/builtins/shared.rs",

View file

@ -56,6 +56,7 @@ include_cpp! {
generate!("valid_var_name_char")
generate!("get_flog_file_fd")
generate!("log_extra_to_flog_file")
generate!("parse_util_unescape_wildcards")

View file

@ -28,6 +28,7 @@ mod ffi_init;
mod ffi_tests;
mod flog;
mod future_feature_flags;
mod global_safety;
mod job_group;
mod locale;
mod nix;
@ -42,6 +43,7 @@ mod threads;
mod timer;
mod tokenizer;
mod topic_monitor;
mod trace;
mod util;
mod wait_handle;
mod wchar;

74
fish-rust/src/trace.rs Normal file
View file

@ -0,0 +1,74 @@
use crate::{
common::{escape_string, EscapeStringStyle},
ffi::{self, parser_t, wcharz_t},
global_safety::RelaxedAtomicBool,
wchar::{self, wstr, L},
wchar_ffi::WCharToFFI,
};
#[cxx::bridge]
mod trace_ffi {
extern "C++" {
include!("wutil.h");
include!("parser.h");
type wcharz_t = super::wcharz_t;
type parser_t = super::parser_t;
}
extern "Rust" {
fn trace_set_enabled(do_enable: bool);
fn trace_enabled(parser: &parser_t) -> bool;
#[cxx_name = "trace_argv"]
fn trace_argv_ffi(parser: &parser_t, command: wcharz_t, args: &Vec<wcharz_t>);
}
}
static DO_TRACE: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
pub fn trace_set_enabled(do_enable: bool) {
DO_TRACE.store(do_enable);
}
/// return whether tracing is enabled.
pub fn trace_enabled(parser: &parser_t) -> bool {
let ld = parser.ffi_libdata_pod_const();
if ld.suppress_fish_trace {
return false;
}
DO_TRACE.load()
}
/// Trace an "argv": a list of arguments where the first is the command.
// Allow the `&Vec` parameter as this function only exists temporarily for the FFI
#[allow(clippy::ptr_arg)]
fn trace_argv_ffi(parser: &parser_t, command: wcharz_t, args: &Vec<wcharz_t>) {
let command: wchar::WString = command.into();
let args: Vec<wchar::WString> = args.iter().map(Into::into).collect();
let args_ref: Vec<&wstr> = args.iter().map(wchar::WString::as_utfstr).collect();
trace_argv(parser, command.as_utfstr(), &args_ref);
}
pub fn trace_argv(parser: &parser_t, command: &wstr, args: &[&wstr]) {
// Format into a string to prevent interleaving with flog in other threads.
// Add the + prefix.
let mut trace_text = L!("-").repeat(parser.blocks_size() - 1);
trace_text.push('>');
if !command.is_empty() {
trace_text.push(' ');
trace_text.push_utfstr(command);
}
for arg in args {
trace_text.push(' ');
trace_text.push_utfstr(&escape_string(arg, EscapeStringStyle::default()));
}
trace_text.push('\n');
ffi::log_extra_to_flog_file(&trace_text.to_ffi());
}
/// Convenience helper to trace a single string if tracing is enabled.
pub fn trace_if_enabled(parser: &parser_t, command: &wstr, args: &[&wstr]) {
if trace_enabled(parser) {
trace_argv(parser, command, args);
}
}

View file

@ -59,6 +59,7 @@
#include "cxx.h"
#include "cxxgen.h"
#include "fallback.h" // IWYU pragma: keep
#include "ffi.h"
#include "flog.h"
#include "io.h"
#include "null_terminated_array.h"
@ -565,13 +566,8 @@ static maybe_t<RustBuiltin> try_get_rust_builtin(const wcstring &cmd) {
static maybe_t<int> builtin_run_rust(parser_t &parser, io_streams_t &streams,
const wcstring_list_t &argv, RustBuiltin builtin) {
::rust::Vec<wcharz_t> rust_argv;
for (const wcstring &arg : argv) {
rust_argv.emplace_back(arg.c_str());
}
int status_code;
bool update_status = rust_run_builtin(parser, streams, rust_argv, builtin, status_code);
bool update_status = rust_run_builtin(parser, streams, to_rust_string_vec(argv), builtin, status_code);
if (update_status) {
return status_code;
} else {

View file

@ -47,7 +47,7 @@
#include "reader.h"
#include "screen.h"
#include "termsize.h"
#include "trace.h"
#include "trace.rs.h"
#include "wcstringutil.h"
#include "wutil.h"

View file

@ -7,6 +7,7 @@
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include "trace.rs.h"
#ifdef HAVE_SIGINFO_H
#include <siginfo.h>
#endif
@ -33,6 +34,7 @@
#include "exec.h"
#include "fallback.h" // IWYU pragma: keep
#include "fds.h"
#include "ffi.h"
#include "flog.h"
#include "function.h"
#include "global_safety.h"
@ -48,7 +50,7 @@
#include "reader.h"
#include "redirection.h"
#include "timer.rs.h"
#include "trace.h"
#include "trace.rs.h"
#include "wcstringutil.h"
#include "wutil.h" // IWYU pragma: keep
@ -827,9 +829,7 @@ static launch_result_t exec_process_in_job(parser_t &parser, process_t *p,
// Maybe trace this process.
// TODO: 'and' and 'or' will not show.
if (trace_enabled(parser)) {
trace_argv(parser, nullptr, p->argv());
}
trace_if_enabled(parser, L"", p->argv());
// The IO chain for this process.
io_chain_t process_net_io_chain = block_io;

View file

@ -2,6 +2,7 @@
#include <memory>
#include "cxx.h"
#include "trace.rs.h"
#if INCLUDE_RUST_HEADERS
// For some unknown reason, the definition of rust::Box is in this particular header:
#include "parse_constants.rs.h"
@ -13,3 +14,19 @@ inline std::shared_ptr<T> box_to_shared_ptr(rust::Box<T> &&value) {
std::shared_ptr<T> shared(ptr, [](T *ptr) { rust::Box<T>::from_raw(ptr); });
return shared;
}
inline static rust::Vec<wcharz_t> to_rust_string_vec(const wcstring_list_t &strings) {
rust::Vec<wcharz_t> rust_strings;
rust_strings.reserve(strings.size());
for (const wcstring &string : strings) {
rust_strings.emplace_back(string.c_str());
}
return rust_strings;
}
inline static void trace_if_enabled(const parser_t &parser, wcharz_t command,
const wcstring_list_t &args = {}) {
if (trace_enabled(parser)) {
trace_argv(parser, command, to_rust_string_vec(args));
}
}

View file

@ -42,7 +42,7 @@
#include "reader.h"
#include "timer.rs.h"
#include "tokenizer.h"
#include "trace.h"
#include "trace.rs.h"
#include "wildcard.h"
#include "wutil.h"
@ -390,6 +390,7 @@ end_execution_reason_t parse_execution_context_t::run_function_statement(
if (result != end_execution_reason_t::ok) {
return result;
}
trace_if_enabled(*parser, L"function", arguments);
null_output_stream_t outs;
string_output_stream_t errs;
@ -537,7 +538,8 @@ end_execution_reason_t parse_execution_context_t::run_switch_statement(
}
end_execution_reason_t result = end_execution_reason_t::ok;
if (trace_enabled(*parser)) trace_argv(*parser, L"switch", {switch_value_expanded});
trace_if_enabled(*parser, L"switch", {switch_value_expanded});
block_t *sb = parser->push_block(block_t::switch_block());
// Expand case statements.

View file

@ -514,6 +514,7 @@ job_t *parser_t::job_get_from_pid(int64_t pid, size_t &job_pos) const {
library_data_pod_t *parser_t::ffi_libdata_pod() { return &library_data; }
job_t *parser_t::ffi_job_get_from_pid(int pid) const { return job_get_from_pid(pid); }
const library_data_pod_t &parser_t::ffi_libdata_pod_const() const { return library_data; }
profile_item_t *parser_t::create_profile_item() {
if (g_profiling_active) {

View file

@ -383,6 +383,8 @@ class parser_t : public std::enable_shared_from_this<parser_t> {
/// Return the list of blocks. The first block is at the top.
const std::deque<block_t> &blocks() const { return block_list; }
size_t blocks_size() const { return block_list.size(); }
/// Get the list of jobs.
job_list_t &jobs() { return job_list; }
const job_list_t &jobs() const { return job_list; }
@ -500,6 +502,7 @@ class parser_t : public std::enable_shared_from_this<parser_t> {
RustFFIJobList ffi_jobs() const;
library_data_pod_t *ffi_libdata_pod();
job_t *ffi_job_get_from_pid(int pid) const;
const library_data_pod_t &ffi_libdata_pod_const() const;
/// autocxx junk.
bool ffi_has_funtion_block() const;

View file

@ -1,43 +0,0 @@
#include "config.h" // IWYU pragma: keep
#include "trace.h"
#include <deque>
#include <string>
#include "common.h"
#include "flog.h"
#include "parser.h"
static bool do_trace = false;
void trace_set_enabled(bool do_enable) { do_trace = do_enable; }
bool trace_enabled(const parser_t &parser) {
const auto &ld = parser.libdata();
if (ld.suppress_fish_trace) return false;
return do_trace;
}
/// Trace an "argv": a list of arguments where the first is the command.
void trace_argv(const parser_t &parser, const wchar_t *command, const wcstring_list_t &argv) {
// Format into a string to prevent interleaving with flog in other threads.
// Add the + prefix.
wcstring trace_text(parser.blocks().size() - 1, L'-');
trace_text.push_back(L'>');
if (command && command[0]) {
trace_text.push_back(L' ');
trace_text.append(command);
}
for (const wcstring &arg : argv) {
trace_text.push_back(L' ');
trace_text.append(escape_string(arg));
}
trace_text.push_back(L'\n');
log_extra_to_flog_file(trace_text);
}
void trace_if_enabled(const parser_t &parser, const wchar_t *command, const wcstring_list_t &argv) {
if (trace_enabled(parser)) trace_argv(parser, command, argv);
}

View file

@ -1,25 +0,0 @@
/// Support for fish_trace.
#ifndef FISH_TRACE_H
#define FISH_TRACE_H
#include "config.h" // IWYU pragma: keep
#include "common.h"
class parser_t;
/// Trace an "argv": a list of arguments. Each argument is escaped.
/// If \p command is not null, it is traced first (and not escaped)
void trace_argv(const parser_t &parser, const wchar_t *command, const wcstring_list_t &argv);
/// \return whether tracing is enabled.
bool trace_enabled(const parser_t &parser);
/// Enable or disable tracing.
void trace_set_enabled(bool do_enable);
/// Convenience helper to trace a single string if tracing is enabled.
void trace_if_enabled(const parser_t &parser, const wchar_t *command,
const wcstring_list_t &argv = {});
#endif