2016-05-03 04:41:17 +00:00
|
|
|
// Prototypes for utilities for keeping track of jobs, processes and subshells, as well as signal
|
|
|
|
// handling functions for tracking children. These functions do not themselves launch new processes,
|
|
|
|
// the exec library will call proc to create representations of the running jobs as needed.
|
2005-10-04 15:11:39 +00:00
|
|
|
#ifndef FISH_PROC_H
|
|
|
|
#define FISH_PROC_H
|
2016-04-21 06:00:54 +00:00
|
|
|
#include "config.h" // IWYU pragma: keep
|
2005-10-04 15:11:39 +00:00
|
|
|
|
2016-05-03 04:41:17 +00:00
|
|
|
#include <sys/time.h> // IWYU pragma: keep
|
2021-05-18 08:16:54 +00:00
|
|
|
#include <sys/wait.h> // IWYU pragma: keep
|
2017-02-11 02:47:02 +00:00
|
|
|
|
2022-08-21 06:14:48 +00:00
|
|
|
#include <atomic>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <cstdlib>
|
2018-12-31 05:53:26 +00:00
|
|
|
#include <deque>
|
2017-02-11 02:47:02 +00:00
|
|
|
#include <memory>
|
2022-08-21 06:14:48 +00:00
|
|
|
#include <string>
|
|
|
|
#include <utility>
|
2017-02-11 02:47:02 +00:00
|
|
|
#include <vector>
|
2005-10-04 15:11:39 +00:00
|
|
|
|
Port AST to Rust
The translation is fairly direct though it adds some duplication, for example
there are multiple "match" statements that mimic function overloading.
Rust has no overloading, and we cannot have generic methods in the Node trait
(due to a Rust limitation, the error is like "cannot be made into an object")
so we include the type name in method names.
Give clients like "indent_visitor_t" a Rust companion ("IndentVisitor")
that takes care of the AST traversal while the AST consumption remains
in C++ for now. In future, "IndentVisitor" should absorb the entirety of
"indent_visitor_t". This pattern requires that "fish_indent" be exposed
includable header to the CXX bridge.
Alternatively, we could define FFI wrappers for recursive AST traversal.
Rust requires we separate the AST visitors for "mut" and "const"
scenarios. Take this opportunity to concretize both visitors:
The only client that requires mutable access is the populator. To match the
structure of the C++ populator which makes heavy use of function overloading,
we need to add a bunch of functions to the trait. Since there is no other
mutable visit, this seems acceptable.
The "const" visitors never use "will_visit_fields_of()" or
"did_visit_fields_of()", so remove them (though this is debatable).
Like in the C++ implementation, the AST nodes themselves are largely defined
via macros. Union fields like "Statement" and "ArgumentOrRedirection"
do currently not use macros but may in future.
This commit also introduces a precedent for a type that is defined in one
CXX bridge and used in another one - "ParseErrorList". To make this work
we need to manually define "ExternType".
There is one annoyance with CXX: functions that take explicit lifetime
parameters require to be marked as unsafe. This makes little sense
because functions that return `&Foo` with implicit lifetime can be
misused the same way on the C++ side.
One notable change is that we cannot directly port "find_block_open_keyword()"
(which is used to compute an error) because it relies on the stack of visited
nodes. We cannot modify a stack of node references while we do the "mut"
walk. Happily, an idiomatic solution is easy: we can tell the AST visitor
to backtrack to the parent node and create the error there.
Since "node_t::accept_base" is no longer a template we don't need the
"node_visitation_t" trampoline anymore.
The added copying at the FFI boundary makes things slower (memcpy dominates
the profile) but it's not unusable, which is good news:
$ hyperfine ./fish.{old,new}" -c 'source ../share/completions/git.fish'"
Benchmark 1: ./fish.old -c 'source ../share/completions/git.fish'
Time (mean ± σ): 195.5 ms ± 2.9 ms [User: 190.1 ms, System: 4.4 ms]
Range (min … max): 193.2 ms … 205.1 ms 15 runs
Benchmark 2: ./fish.new -c 'source ../share/completions/git.fish'
Time (mean ± σ): 677.5 ms ± 62.0 ms [User: 665.4 ms, System: 10.0 ms]
Range (min … max): 611.7 ms … 805.5 ms 10 runs
Summary
'./fish.old -c 'source ../share/completions/git.fish'' ran
3.47 ± 0.32 times faster than './fish.new -c 'source ../share/completions/git.fish''
Leftovers:
- Enum variants are still snakecase; I didn't get around to changing this yet.
- "ast_type_to_string()" still returns a snakecase name. This could be
changed since it's not user visible.
2023-04-02 14:42:59 +00:00
|
|
|
#include "ast.h"
|
2012-01-30 06:06:58 +00:00
|
|
|
#include "common.h"
|
Port AST to Rust
The translation is fairly direct though it adds some duplication, for example
there are multiple "match" statements that mimic function overloading.
Rust has no overloading, and we cannot have generic methods in the Node trait
(due to a Rust limitation, the error is like "cannot be made into an object")
so we include the type name in method names.
Give clients like "indent_visitor_t" a Rust companion ("IndentVisitor")
that takes care of the AST traversal while the AST consumption remains
in C++ for now. In future, "IndentVisitor" should absorb the entirety of
"indent_visitor_t". This pattern requires that "fish_indent" be exposed
includable header to the CXX bridge.
Alternatively, we could define FFI wrappers for recursive AST traversal.
Rust requires we separate the AST visitors for "mut" and "const"
scenarios. Take this opportunity to concretize both visitors:
The only client that requires mutable access is the populator. To match the
structure of the C++ populator which makes heavy use of function overloading,
we need to add a bunch of functions to the trait. Since there is no other
mutable visit, this seems acceptable.
The "const" visitors never use "will_visit_fields_of()" or
"did_visit_fields_of()", so remove them (though this is debatable).
Like in the C++ implementation, the AST nodes themselves are largely defined
via macros. Union fields like "Statement" and "ArgumentOrRedirection"
do currently not use macros but may in future.
This commit also introduces a precedent for a type that is defined in one
CXX bridge and used in another one - "ParseErrorList". To make this work
we need to manually define "ExternType".
There is one annoyance with CXX: functions that take explicit lifetime
parameters require to be marked as unsafe. This makes little sense
because functions that return `&Foo` with implicit lifetime can be
misused the same way on the C++ side.
One notable change is that we cannot directly port "find_block_open_keyword()"
(which is used to compute an error) because it relies on the stack of visited
nodes. We cannot modify a stack of node references while we do the "mut"
walk. Happily, an idiomatic solution is easy: we can tell the AST visitor
to backtrack to the parent node and create the error there.
Since "node_t::accept_base" is no longer a template we don't need the
"node_visitation_t" trampoline anymore.
The added copying at the FFI boundary makes things slower (memcpy dominates
the profile) but it's not unusable, which is good news:
$ hyperfine ./fish.{old,new}" -c 'source ../share/completions/git.fish'"
Benchmark 1: ./fish.old -c 'source ../share/completions/git.fish'
Time (mean ± σ): 195.5 ms ± 2.9 ms [User: 190.1 ms, System: 4.4 ms]
Range (min … max): 193.2 ms … 205.1 ms 15 runs
Benchmark 2: ./fish.new -c 'source ../share/completions/git.fish'
Time (mean ± σ): 677.5 ms ± 62.0 ms [User: 665.4 ms, System: 10.0 ms]
Range (min … max): 611.7 ms … 805.5 ms 10 runs
Summary
'./fish.old -c 'source ../share/completions/git.fish'' ran
3.47 ± 0.32 times faster than './fish.new -c 'source ../share/completions/git.fish''
Leftovers:
- Enum variants are still snakecase; I didn't get around to changing this yet.
- "ast_type_to_string()" still returns a snakecase name. This could be
changed since it's not user visible.
2023-04-02 14:42:59 +00:00
|
|
|
#include "cxx.h"
|
2022-08-21 06:14:48 +00:00
|
|
|
#include "maybe.h"
|
2013-12-26 20:24:00 +00:00
|
|
|
#include "parse_tree.h"
|
2022-08-21 06:14:48 +00:00
|
|
|
#include "redirection.h"
|
2019-02-17 01:39:14 +00:00
|
|
|
#include "topic_monitor.h"
|
2021-05-11 19:01:08 +00:00
|
|
|
#include "wait_handle.h"
|
2005-10-04 15:11:39 +00:00
|
|
|
|
2022-08-21 06:14:48 +00:00
|
|
|
struct statuses_t;
|
|
|
|
|
2016-05-03 04:41:17 +00:00
|
|
|
/// Types of processes.
|
2021-10-31 10:51:16 +00:00
|
|
|
enum class process_type_t : uint8_t {
|
2016-05-03 04:41:17 +00:00
|
|
|
/// A regular external command.
|
2019-03-24 19:29:25 +00:00
|
|
|
external,
|
2016-05-03 04:41:17 +00:00
|
|
|
/// A builtin command.
|
2019-03-24 19:29:25 +00:00
|
|
|
builtin,
|
2016-05-03 04:41:17 +00:00
|
|
|
/// A shellscript function.
|
2019-03-24 19:29:25 +00:00
|
|
|
function,
|
2016-05-03 04:41:17 +00:00
|
|
|
/// A block of commands, represented as a node.
|
2019-03-24 19:29:25 +00:00
|
|
|
block_node,
|
2016-05-03 04:41:17 +00:00
|
|
|
/// The exec builtin.
|
2019-03-24 19:29:25 +00:00
|
|
|
exec,
|
2013-12-20 22:37:40 +00:00
|
|
|
};
|
2005-09-20 13:26:39 +00:00
|
|
|
|
2021-10-31 10:51:16 +00:00
|
|
|
enum class job_control_t : uint8_t {
|
2019-03-24 19:12:08 +00:00
|
|
|
all,
|
|
|
|
interactive,
|
|
|
|
none,
|
2016-05-03 04:41:17 +00:00
|
|
|
};
|
2012-11-18 10:23:22 +00:00
|
|
|
|
2022-05-07 22:08:12 +00:00
|
|
|
/// A number of clock ticks.
|
|
|
|
using clock_ticks_t = uint64_t;
|
|
|
|
|
|
|
|
/// \return clock ticks in seconds, or 0 on failure.
|
|
|
|
/// This uses sysconf(_SC_CLK_TCK) to convert to seconds.
|
|
|
|
double clock_ticks_to_seconds(clock_ticks_t ticks);
|
|
|
|
|
2023-02-25 22:42:45 +00:00
|
|
|
struct job_group_t;
|
2020-07-19 23:41:58 +00:00
|
|
|
using job_group_ref_t = std::shared_ptr<job_group_t>;
|
|
|
|
|
2019-02-25 18:05:42 +00:00
|
|
|
/// A proc_status_t is a value type that encapsulates logic around exited vs stopped vs signaled,
|
|
|
|
/// etc.
|
|
|
|
class proc_status_t {
|
|
|
|
int status_{};
|
|
|
|
|
2020-07-18 17:25:43 +00:00
|
|
|
/// If set, there is no actual status to report, e.g. background or variable assignment.
|
|
|
|
bool empty_{};
|
|
|
|
|
|
|
|
explicit proc_status_t(int status) : status_(status), empty_(false) {}
|
|
|
|
|
|
|
|
proc_status_t(int status, bool empty) : status_(status), empty_(empty) {}
|
2019-02-25 18:05:42 +00:00
|
|
|
|
|
|
|
/// Encode a return value \p ret and signal \p sig into a status value like waitpid() does.
|
|
|
|
static constexpr int w_exitcode(int ret, int sig) {
|
|
|
|
#ifdef W_EXITCODE
|
|
|
|
return W_EXITCODE(ret, sig);
|
2022-07-24 14:39:57 +00:00
|
|
|
#elif HAVE_WAITSTATUS_SIGNAL_RET
|
2022-07-23 21:13:32 +00:00
|
|
|
// It's encoded signal and then status
|
|
|
|
// The return status is in the lower byte.
|
|
|
|
return ((sig) << 8 | (ret));
|
2019-02-25 18:05:42 +00:00
|
|
|
#else
|
2022-07-23 21:13:32 +00:00
|
|
|
// The status is encoded in the upper byte.
|
2019-02-25 18:05:42 +00:00
|
|
|
return ((ret) << 8 | (sig));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
proc_status_t() = default;
|
|
|
|
|
|
|
|
/// Construct from a status returned from a waitpid call.
|
|
|
|
static proc_status_t from_waitpid(int status) { return proc_status_t(status); }
|
|
|
|
|
|
|
|
/// Construct directly from an exit code.
|
|
|
|
static proc_status_t from_exit_code(int ret) {
|
2023-01-14 22:56:24 +00:00
|
|
|
assert(ret >= 0 &&
|
|
|
|
"trying to create proc_status_t from failed wait{,id,pid}() call"
|
|
|
|
" or invalid builtin exit code!");
|
2022-09-25 17:19:55 +00:00
|
|
|
|
2019-02-25 18:05:42 +00:00
|
|
|
// Some paranoia.
|
|
|
|
constexpr int zerocode = w_exitcode(0, 0);
|
|
|
|
static_assert(WIFEXITED(zerocode), "Synthetic exit status not reported as exited");
|
2021-02-08 21:25:30 +00:00
|
|
|
|
|
|
|
assert(ret < 256);
|
2019-02-25 18:05:42 +00:00
|
|
|
return proc_status_t(w_exitcode(ret, 0 /* sig */));
|
|
|
|
}
|
|
|
|
|
2019-12-18 02:15:42 +00:00
|
|
|
/// Construct directly from a signal.
|
|
|
|
static proc_status_t from_signal(int sig) {
|
|
|
|
return proc_status_t(w_exitcode(0 /* ret */, sig));
|
|
|
|
}
|
|
|
|
|
2020-07-18 17:25:43 +00:00
|
|
|
/// Construct an empty status_t (e.g. `set foo bar`).
|
|
|
|
static proc_status_t empty() {
|
|
|
|
bool empty = true;
|
|
|
|
return proc_status_t(0, empty);
|
|
|
|
}
|
|
|
|
|
2019-02-25 18:05:42 +00:00
|
|
|
/// \return if we are stopped (as in SIGSTOP).
|
|
|
|
bool stopped() const { return WIFSTOPPED(status_); }
|
|
|
|
|
2020-03-27 19:21:32 +00:00
|
|
|
/// \return if we are continued (as in SIGCONT).
|
|
|
|
bool continued() const { return WIFCONTINUED(status_); }
|
|
|
|
|
2019-02-25 18:05:42 +00:00
|
|
|
/// \return if we exited normally (not a signal).
|
|
|
|
bool normal_exited() const { return WIFEXITED(status_); }
|
|
|
|
|
|
|
|
/// \return if we exited because of a signal.
|
|
|
|
bool signal_exited() const { return WIFSIGNALED(status_); }
|
|
|
|
|
|
|
|
/// \return the signal code, given that we signal exited.
|
|
|
|
int signal_code() const {
|
|
|
|
assert(signal_exited() && "Process is not signal exited");
|
|
|
|
return WTERMSIG(status_);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \return the exit code, given that we normal exited.
|
|
|
|
int exit_code() const {
|
|
|
|
assert(normal_exited() && "Process is not normal exited");
|
|
|
|
return WEXITSTATUS(status_);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \return if this status represents success.
|
|
|
|
bool is_success() const { return normal_exited() && exit_code() == EXIT_SUCCESS; }
|
|
|
|
|
2020-07-18 17:25:43 +00:00
|
|
|
/// \return if this status is empty.
|
|
|
|
bool is_empty() const { return empty_; }
|
|
|
|
|
2019-02-25 18:05:42 +00:00
|
|
|
/// \return the value appropriate to populate $status.
|
|
|
|
int status_value() const {
|
|
|
|
if (signal_exited()) {
|
|
|
|
return 128 + signal_code();
|
|
|
|
} else if (normal_exited()) {
|
|
|
|
return exit_code();
|
|
|
|
} else {
|
|
|
|
DIE("Process is not exited");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-02-13 23:17:07 +00:00
|
|
|
/// A structure representing a "process" internal to fish. This is backed by a pthread instead of a
|
|
|
|
/// separate process.
|
|
|
|
class internal_proc_t {
|
2019-05-28 16:38:45 +00:00
|
|
|
/// An identifier for internal processes.
|
|
|
|
/// This is used for logging purposes only.
|
|
|
|
const uint64_t internal_proc_id_;
|
|
|
|
|
2019-02-13 23:17:07 +00:00
|
|
|
/// Whether the process has exited.
|
|
|
|
std::atomic<bool> exited_{};
|
|
|
|
|
|
|
|
/// If the process has exited, its status code.
|
2019-02-25 18:05:42 +00:00
|
|
|
std::atomic<proc_status_t> status_{};
|
2019-02-13 23:17:07 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
/// \return if this process has exited.
|
2019-02-25 18:05:42 +00:00
|
|
|
bool exited() const { return exited_.load(std::memory_order_acquire); }
|
2019-02-13 23:17:07 +00:00
|
|
|
|
|
|
|
/// Mark this process as exited, with the given status.
|
2019-02-25 18:05:42 +00:00
|
|
|
void mark_exited(proc_status_t status);
|
2019-02-13 23:17:07 +00:00
|
|
|
|
2019-02-25 18:05:42 +00:00
|
|
|
proc_status_t get_status() const {
|
2019-02-13 23:17:07 +00:00
|
|
|
assert(exited() && "Process is not exited");
|
2019-02-25 18:05:42 +00:00
|
|
|
return status_.load(std::memory_order_relaxed);
|
2019-02-13 23:17:07 +00:00
|
|
|
}
|
2019-05-28 16:38:45 +00:00
|
|
|
|
|
|
|
uint64_t get_id() const { return internal_proc_id_; }
|
|
|
|
|
|
|
|
internal_proc_t();
|
2019-02-13 23:17:07 +00:00
|
|
|
};
|
|
|
|
|
2019-06-23 19:39:29 +00:00
|
|
|
/// 0 should not be used; although it is not a valid PGID in userspace,
|
|
|
|
/// the Linux kernel will use it for kernel processes.
|
|
|
|
/// -1 should not be used; it is a possible return value of the getpgid()
|
|
|
|
/// function
|
|
|
|
enum { INVALID_PID = -2 };
|
|
|
|
|
2022-02-13 21:12:18 +00:00
|
|
|
// Allows transferring the tty to a job group, while it runs.
|
|
|
|
class tty_transfer_t : nonmovable_t, noncopyable_t {
|
|
|
|
public:
|
|
|
|
tty_transfer_t() = default;
|
|
|
|
|
|
|
|
/// Transfer to the given job group, if it wants to own the terminal.
|
|
|
|
void to_job_group(const job_group_ref_t &jg);
|
|
|
|
|
|
|
|
/// Reclaim the tty if we transferred it.
|
|
|
|
void reclaim();
|
|
|
|
|
|
|
|
/// Save the current tty modes into the owning job group, if we are transferred.
|
|
|
|
void save_tty_modes();
|
|
|
|
|
|
|
|
/// The destructor will assert if reclaim() has not been called.
|
|
|
|
~tty_transfer_t();
|
|
|
|
|
|
|
|
private:
|
|
|
|
// Try transferring the tty to the given job group.
|
|
|
|
// \return true if we should reclaim it.
|
|
|
|
static bool try_transfer(const job_group_ref_t &jg);
|
|
|
|
|
|
|
|
// The job group which owns the tty, or empty if none.
|
|
|
|
job_group_ref_t owner_;
|
|
|
|
};
|
|
|
|
|
2016-05-03 04:41:17 +00:00
|
|
|
/// A structure representing a single fish process. Contains variables for tracking process state
|
|
|
|
/// and the process argument list. Actually, a fish process can be either a regular external
|
|
|
|
/// process, an internal builtin which may or may not spawn a fake IO process during execution, a
|
|
|
|
/// shellscript function or a block of commands to be evaluated by calling eval. Lastly, this
|
|
|
|
/// process can be the result of an exec command. The role of this process_t is determined by the
|
2019-03-24 19:29:25 +00:00
|
|
|
/// type field, which can be one of process_type_t::external, process_type_t::builtin,
|
|
|
|
/// process_type_t::function, process_type_t::exec.
|
2016-05-03 04:41:17 +00:00
|
|
|
///
|
|
|
|
/// The process_t contains information on how the process should be started, such as command name
|
|
|
|
/// and arguments, as well as runtime information on the status of the actual physical process which
|
|
|
|
/// represents it. Shellscript functions, builtins and blocks of code may all need to spawn an
|
|
|
|
/// external process that handles the piping and redirecting of IO for them.
|
|
|
|
///
|
2019-03-24 19:29:25 +00:00
|
|
|
/// If the process is of type process_type_t::external or process_type_t::exec, argv is the argument
|
|
|
|
/// array and actual_cmd is the absolute path of the command to execute.
|
2016-05-03 04:41:17 +00:00
|
|
|
///
|
2019-03-24 19:29:25 +00:00
|
|
|
/// If the process is of type process_type_t::builtin, argv is the argument vector, and argv[0] is
|
|
|
|
/// the name of the builtin command.
|
2016-05-03 04:41:17 +00:00
|
|
|
///
|
2019-03-24 19:29:25 +00:00
|
|
|
/// If the process is of type process_type_t::function, argv is the argument vector, and argv[0] is
|
|
|
|
/// the name of the shellscript function.
|
2023-03-14 02:23:31 +00:00
|
|
|
class process_t {
|
2016-05-03 04:41:17 +00:00
|
|
|
public:
|
2012-08-15 07:57:56 +00:00
|
|
|
process_t();
|
2017-01-23 17:28:34 +00:00
|
|
|
|
2019-02-16 09:20:08 +00:00
|
|
|
/// Note whether we are the first and/or last in the job
|
2018-02-11 03:16:35 +00:00
|
|
|
bool is_first_in_job{false};
|
|
|
|
bool is_last_in_job{false};
|
2012-11-18 10:23:22 +00:00
|
|
|
|
2019-03-24 19:29:25 +00:00
|
|
|
/// Type of process.
|
|
|
|
process_type_t type{process_type_t::external};
|
2014-01-15 09:40:40 +00:00
|
|
|
|
2020-07-03 18:16:51 +00:00
|
|
|
/// For internal block processes only, the node of the statement.
|
2018-02-11 03:16:35 +00:00
|
|
|
/// This is always either block, ifs, or switchs, never boolean or decorated.
|
Port AST to Rust
The translation is fairly direct though it adds some duplication, for example
there are multiple "match" statements that mimic function overloading.
Rust has no overloading, and we cannot have generic methods in the Node trait
(due to a Rust limitation, the error is like "cannot be made into an object")
so we include the type name in method names.
Give clients like "indent_visitor_t" a Rust companion ("IndentVisitor")
that takes care of the AST traversal while the AST consumption remains
in C++ for now. In future, "IndentVisitor" should absorb the entirety of
"indent_visitor_t". This pattern requires that "fish_indent" be exposed
includable header to the CXX bridge.
Alternatively, we could define FFI wrappers for recursive AST traversal.
Rust requires we separate the AST visitors for "mut" and "const"
scenarios. Take this opportunity to concretize both visitors:
The only client that requires mutable access is the populator. To match the
structure of the C++ populator which makes heavy use of function overloading,
we need to add a bunch of functions to the trait. Since there is no other
mutable visit, this seems acceptable.
The "const" visitors never use "will_visit_fields_of()" or
"did_visit_fields_of()", so remove them (though this is debatable).
Like in the C++ implementation, the AST nodes themselves are largely defined
via macros. Union fields like "Statement" and "ArgumentOrRedirection"
do currently not use macros but may in future.
This commit also introduces a precedent for a type that is defined in one
CXX bridge and used in another one - "ParseErrorList". To make this work
we need to manually define "ExternType".
There is one annoyance with CXX: functions that take explicit lifetime
parameters require to be marked as unsafe. This makes little sense
because functions that return `&Foo` with implicit lifetime can be
misused the same way on the C++ side.
One notable change is that we cannot directly port "find_block_open_keyword()"
(which is used to compute an error) because it relies on the stack of visited
nodes. We cannot modify a stack of node references while we do the "mut"
walk. Happily, an idiomatic solution is easy: we can tell the AST visitor
to backtrack to the parent node and create the error there.
Since "node_t::accept_base" is no longer a template we don't need the
"node_visitation_t" trampoline anymore.
The added copying at the FFI boundary makes things slower (memcpy dominates
the profile) but it's not unusable, which is good news:
$ hyperfine ./fish.{old,new}" -c 'source ../share/completions/git.fish'"
Benchmark 1: ./fish.old -c 'source ../share/completions/git.fish'
Time (mean ± σ): 195.5 ms ± 2.9 ms [User: 190.1 ms, System: 4.4 ms]
Range (min … max): 193.2 ms … 205.1 ms 15 runs
Benchmark 2: ./fish.new -c 'source ../share/completions/git.fish'
Time (mean ± σ): 677.5 ms ± 62.0 ms [User: 665.4 ms, System: 10.0 ms]
Range (min … max): 611.7 ms … 805.5 ms 10 runs
Summary
'./fish.old -c 'source ../share/completions/git.fish'' ran
3.47 ± 0.32 times faster than './fish.new -c 'source ../share/completions/git.fish''
Leftovers:
- Enum variants are still snakecase; I didn't get around to changing this yet.
- "ast_type_to_string()" still returns a snakecase name. This could be
changed since it's not user visible.
2023-04-02 14:42:59 +00:00
|
|
|
rust::Box<ParsedSourceRefFFI> block_node_source;
|
2020-07-03 18:16:51 +00:00
|
|
|
const ast::statement_t *internal_block_node{};
|
2012-11-18 10:23:22 +00:00
|
|
|
|
Support FOO=bar syntax for passing variables to individual commands
This adds initial support for statements with prefixed variable assignments.
Statments like this are supported:
a=1 b=$a echo $b # outputs 1
Just like in other shells, the left-hand side of each assignment must
be a valid variable identifier (no quoting/escaping). Array indexing
(PATH[1]=/bin ls $PATH) is *not* yet supported, but can be added fairly
easily.
The right hand side may be any valid string token, like a command
substitution, or a brace expansion.
Since `a=* foo` is equivalent to `begin set -lx a *; foo; end`,
the assignment, like `set`, uses nullglob behavior, e.g. below command
can safely be used to check if a directory is empty.
x=/nothing/{,.}* test (count $x) -eq 0
Generic file completion is done after the equal sign, so for example
pressing tab after something like `HOME=/` completes files in the
root directory
Subcommand completion works, so something like
`GIT_DIR=repo.git and command git ` correctly calls git completions
(but the git completion does not use the variable as of now).
The variable assignment is highlighted like an argument.
Closes #6048
2019-10-23 01:13:29 +00:00
|
|
|
struct concrete_assignment {
|
|
|
|
wcstring variable_name;
|
2023-04-18 22:19:10 +00:00
|
|
|
std::vector<wcstring> values;
|
Support FOO=bar syntax for passing variables to individual commands
This adds initial support for statements with prefixed variable assignments.
Statments like this are supported:
a=1 b=$a echo $b # outputs 1
Just like in other shells, the left-hand side of each assignment must
be a valid variable identifier (no quoting/escaping). Array indexing
(PATH[1]=/bin ls $PATH) is *not* yet supported, but can be added fairly
easily.
The right hand side may be any valid string token, like a command
substitution, or a brace expansion.
Since `a=* foo` is equivalent to `begin set -lx a *; foo; end`,
the assignment, like `set`, uses nullglob behavior, e.g. below command
can safely be used to check if a directory is empty.
x=/nothing/{,.}* test (count $x) -eq 0
Generic file completion is done after the equal sign, so for example
pressing tab after something like `HOME=/` completes files in the
root directory
Subcommand completion works, so something like
`GIT_DIR=repo.git and command git ` correctly calls git completions
(but the git completion does not use the variable as of now).
The variable assignment is highlighted like an argument.
Closes #6048
2019-10-23 01:13:29 +00:00
|
|
|
};
|
|
|
|
/// The expanded variable assignments for this process, as specified by the `a=b cmd` syntax.
|
|
|
|
std::vector<concrete_assignment> variable_assignments;
|
|
|
|
|
2016-05-03 04:41:17 +00:00
|
|
|
/// Sets argv.
|
2023-04-18 22:19:10 +00:00
|
|
|
void set_argv(std::vector<wcstring> argv) { argv_ = std::move(argv); }
|
2012-11-18 10:23:22 +00:00
|
|
|
|
2016-05-03 04:41:17 +00:00
|
|
|
/// Returns argv.
|
2023-04-18 22:19:10 +00:00
|
|
|
const std::vector<wcstring> &argv() { return argv_; }
|
2012-11-18 10:23:22 +00:00
|
|
|
|
2021-02-14 21:15:29 +00:00
|
|
|
/// Returns argv[0], or nullptr.
|
|
|
|
const wchar_t *argv0() const { return argv_.empty() ? nullptr : argv_.front().c_str(); }
|
2012-11-18 10:23:22 +00:00
|
|
|
|
2019-12-13 00:44:24 +00:00
|
|
|
/// Redirection list getter and setter.
|
2023-02-04 10:21:42 +00:00
|
|
|
const redirection_spec_list_t &redirection_specs() const { return *proc_redirection_specs_; }
|
2021-02-14 21:15:29 +00:00
|
|
|
|
2023-02-04 10:21:42 +00:00
|
|
|
void set_redirection_specs(rust::Box<redirection_spec_list_t> specs) {
|
2021-02-14 21:15:29 +00:00
|
|
|
this->proc_redirection_specs_ = std::move(specs);
|
2019-12-13 00:44:24 +00:00
|
|
|
}
|
Big fat refactoring of how redirections work. In fish 1.x and 2.0.0, the redirections for a process were flattened into a big list associated with the job, so there was no way to tell which redirections applied to each process. Each process therefore got all the redirections associated with the job. See https://github.com/fish-shell/fish-shell/issues/877 for how this could manifest.
With this change, jobs only track their block-level redirections. Process level redirections are correctly associated with the process, and at exec time we stitch them together (block, pipe, and process redirects).
This fixes the weird issues where redirects bleed across pipelines (like #877), and also allows us to play with the order in which redirections are applied, since the final list is constructed right before it's needed. This lets us put pipes after block level redirections but before process level redirections, so that a 2>&1-type redirection gets picked up after the pipe, i.e. it should fix https://github.com/fish-shell/fish-shell/issues/110
This is a significant change. The tests all pass. Cross your fingers.
2013-08-19 23:16:41 +00:00
|
|
|
|
2019-02-17 01:35:16 +00:00
|
|
|
/// Store the current topic generations. That is, right before the process is launched, record
|
|
|
|
/// the generations of all topics; then we can tell which generation values have changed after
|
|
|
|
/// launch. This helps us avoid spurious waitpid calls.
|
|
|
|
void check_generations_before_launch();
|
|
|
|
|
2020-12-13 23:39:20 +00:00
|
|
|
/// Mark that this process was part of a pipeline which was aborted.
|
|
|
|
/// The process was never successfully launched; give it a status of EXIT_FAILURE.
|
|
|
|
void mark_aborted_before_launch();
|
|
|
|
|
2020-01-30 00:39:44 +00:00
|
|
|
/// \return whether this process type is internal (block, function, or builtin).
|
|
|
|
bool is_internal() const;
|
|
|
|
|
2021-10-28 17:37:43 +00:00
|
|
|
/// \return the wait handle for the process, if it exists.
|
2023-03-14 02:23:31 +00:00
|
|
|
rust::Box<WaitHandleRefFFI> *get_wait_handle_ffi() const;
|
2021-10-28 17:37:43 +00:00
|
|
|
|
|
|
|
/// Create a wait handle for the process.
|
|
|
|
/// As a process does not know its job id, we pass it in.
|
|
|
|
/// Note this will return null if the process is not waitable (has no pid).
|
2023-03-14 02:23:31 +00:00
|
|
|
rust::Box<WaitHandleRefFFI> *make_wait_handle_ffi(internal_job_id_t jid);
|
|
|
|
|
|
|
|
/// Variants of get and make that return void*, to satisfy autocxx.
|
|
|
|
void *get_wait_handle_void() const;
|
|
|
|
void *make_wait_handle_void(internal_job_id_t jid);
|
2021-05-11 19:01:08 +00:00
|
|
|
|
2019-03-24 19:29:25 +00:00
|
|
|
/// Actual command to pass to exec in case of process_type_t::external or process_type_t::exec.
|
2012-11-19 00:30:30 +00:00
|
|
|
wcstring actual_cmd;
|
2019-02-17 01:39:14 +00:00
|
|
|
|
|
|
|
/// Generation counts for reaping.
|
|
|
|
generation_list_t gens_{};
|
|
|
|
|
2016-05-03 04:41:17 +00:00
|
|
|
/// Process ID
|
2018-02-11 03:16:35 +00:00
|
|
|
pid_t pid{0};
|
2019-02-13 23:17:07 +00:00
|
|
|
|
|
|
|
/// If we are an "internal process," that process.
|
|
|
|
std::shared_ptr<internal_proc_t> internal_proc_{};
|
|
|
|
|
2016-05-03 04:41:17 +00:00
|
|
|
/// File descriptor that pipe output should bind to.
|
2018-02-11 03:16:35 +00:00
|
|
|
int pipe_write_fd{0};
|
2020-08-07 18:38:38 +00:00
|
|
|
|
2016-05-03 04:41:17 +00:00
|
|
|
/// True if process has completed.
|
2019-03-03 19:45:05 +00:00
|
|
|
bool completed{false};
|
2020-08-07 18:38:38 +00:00
|
|
|
|
2016-05-03 04:41:17 +00:00
|
|
|
/// True if process has stopped.
|
2019-03-03 19:45:05 +00:00
|
|
|
bool stopped{false};
|
2020-08-07 18:38:38 +00:00
|
|
|
|
2022-02-19 18:05:50 +00:00
|
|
|
/// If set, this process is (or will become) the pgroup leader.
|
|
|
|
/// This is only meaningful for external processes.
|
|
|
|
bool leads_pgrp{false};
|
|
|
|
|
2022-05-08 22:27:25 +00:00
|
|
|
/// Whether we have generated a proc_exit event.
|
|
|
|
bool posted_proc_exit{false};
|
|
|
|
|
2016-05-03 04:41:17 +00:00
|
|
|
/// Reported status value.
|
2019-02-25 18:05:42 +00:00
|
|
|
proc_status_t status{};
|
2020-08-07 18:38:38 +00:00
|
|
|
|
2021-08-27 23:20:30 +00:00
|
|
|
/// Last time of cpu time check, in seconds (per timef).
|
|
|
|
timepoint_t last_time{0};
|
2020-08-07 18:38:38 +00:00
|
|
|
|
2016-05-03 04:41:17 +00:00
|
|
|
/// Number of jiffies spent in process at last cpu time check.
|
2022-05-07 22:08:12 +00:00
|
|
|
clock_ticks_t last_jiffies{0};
|
2021-02-14 21:15:29 +00:00
|
|
|
|
2023-03-14 02:23:31 +00:00
|
|
|
process_t(process_t &&) = delete;
|
|
|
|
process_t &operator=(process_t &&) = delete;
|
|
|
|
process_t(const process_t &) = delete;
|
|
|
|
process_t &operator=(const process_t &) = delete;
|
|
|
|
|
2021-02-14 21:15:29 +00:00
|
|
|
private:
|
2023-04-18 22:19:10 +00:00
|
|
|
std::vector<wcstring> argv_;
|
2023-02-04 10:21:42 +00:00
|
|
|
rust::Box<redirection_spec_list_t> proc_redirection_specs_;
|
2021-05-11 19:01:08 +00:00
|
|
|
|
|
|
|
// The wait handle. This is constructed lazily, and cached.
|
2023-03-14 02:23:31 +00:00
|
|
|
// This may be null.
|
|
|
|
std::unique_ptr<rust::Box<WaitHandleRefFFI>> wait_handle_;
|
2012-01-30 02:25:54 +00:00
|
|
|
};
|
2005-09-20 13:26:39 +00:00
|
|
|
|
2021-05-15 19:50:25 +00:00
|
|
|
using process_ptr_t = std::unique_ptr<process_t>;
|
|
|
|
using process_list_t = std::vector<process_ptr_t>;
|
2022-08-21 06:14:48 +00:00
|
|
|
class parser_t;
|
2017-01-23 17:28:34 +00:00
|
|
|
|
2023-01-14 22:56:24 +00:00
|
|
|
struct RustFFIProcList {
|
|
|
|
process_ptr_t *procs;
|
|
|
|
size_t count;
|
|
|
|
};
|
|
|
|
|
2020-02-08 21:15:33 +00:00
|
|
|
/// A struct representing a job. A job is a pipeline of one or more processes.
|
2021-07-22 17:43:25 +00:00
|
|
|
class job_t : noncopyable_t {
|
2019-06-23 19:39:29 +00:00
|
|
|
public:
|
|
|
|
/// A set of jobs properties. These are immutable: they do not change for the lifetime of the
|
|
|
|
/// job.
|
|
|
|
struct properties_t {
|
|
|
|
/// Whether the specified job is a part of a subshell, event handler or some other form of
|
|
|
|
/// special job that should not be reported.
|
|
|
|
bool skip_notification{};
|
|
|
|
|
2020-02-19 17:21:09 +00:00
|
|
|
/// Whether the job had the background ampersand when constructed, e.g. /bin/echo foo &
|
|
|
|
/// Note that a job may move between foreground and background; this just describes what the
|
|
|
|
/// initial state should be.
|
|
|
|
bool initial_background{};
|
|
|
|
|
2020-09-01 20:43:57 +00:00
|
|
|
/// Whether the job has the 'time' prefix and so we should print timing for this job.
|
|
|
|
bool wants_timing{};
|
|
|
|
|
2019-06-26 18:28:27 +00:00
|
|
|
/// Whether this job was created as part of an event handler.
|
|
|
|
bool from_event_handler{};
|
2019-06-23 19:39:29 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
private:
|
|
|
|
/// Set of immutable job properties.
|
|
|
|
const properties_t properties;
|
|
|
|
|
2016-05-03 04:41:17 +00:00
|
|
|
/// The original command which led to the creation of this job. It is used for displaying
|
|
|
|
/// messages about job status on the terminal.
|
2020-07-17 21:05:23 +00:00
|
|
|
const wcstring command_str;
|
2012-11-18 10:23:22 +00:00
|
|
|
|
2016-05-03 04:41:17 +00:00
|
|
|
public:
|
2020-07-17 21:05:23 +00:00
|
|
|
job_t(const properties_t &props, wcstring command_str);
|
2012-08-15 07:57:56 +00:00
|
|
|
~job_t();
|
2012-11-18 10:23:22 +00:00
|
|
|
|
2023-01-14 22:56:24 +00:00
|
|
|
/// Autocxx needs to see this.
|
|
|
|
job_t(const job_t &) = delete;
|
|
|
|
|
2016-05-03 04:41:17 +00:00
|
|
|
/// Returns the command as a wchar_t *. */
|
|
|
|
const wchar_t *command_wcstr() const { return command_str.c_str(); }
|
2012-11-18 10:23:22 +00:00
|
|
|
|
2016-05-03 04:41:17 +00:00
|
|
|
/// Returns the command.
|
|
|
|
const wcstring &command() const { return command_str; }
|
2012-11-18 10:23:22 +00:00
|
|
|
|
2019-02-17 01:39:14 +00:00
|
|
|
/// \return whether it is OK to reap a given process. Sometimes we want to defer reaping a
|
|
|
|
/// process if it is the group leader and the job is not yet constructed, because then we might
|
|
|
|
/// also reap the process group and then we cannot add new processes to the group.
|
2020-08-07 19:33:43 +00:00
|
|
|
bool can_reap(const process_ptr_t &p) const {
|
|
|
|
if (p->completed) {
|
|
|
|
// Can't reap twice.
|
2019-02-17 01:39:14 +00:00
|
|
|
return false;
|
2020-08-07 19:33:43 +00:00
|
|
|
} else if (p->pid && !is_constructed() && this->get_pgid() == maybe_t<pid_t>{p->pid}) {
|
2019-02-17 01:39:14 +00:00
|
|
|
// p is the the group leader in an under-construction job.
|
|
|
|
return false;
|
2019-02-13 23:17:07 +00:00
|
|
|
} else {
|
|
|
|
return true;
|
2019-02-17 01:39:14 +00:00
|
|
|
}
|
2019-02-13 23:17:07 +00:00
|
|
|
}
|
|
|
|
|
2018-10-02 16:19:56 +00:00
|
|
|
/// Returns a truncated version of the job string. Used when a message has already been emitted
|
|
|
|
/// containing the full job string and job id, but using the job id alone would be confusing
|
|
|
|
/// due to reuse of freed job ids. Prevents overloading the debug comments with the full,
|
|
|
|
/// untruncated job string when we don't care what the job is, only which of the currently
|
|
|
|
/// running jobs it is.
|
|
|
|
wcstring preview() const {
|
2019-05-05 10:09:25 +00:00
|
|
|
if (processes.empty()) return L"";
|
2018-12-02 22:53:26 +00:00
|
|
|
// Note argv0 may be empty in e.g. a block process.
|
|
|
|
const wchar_t *argv0 = processes.front()->argv0();
|
|
|
|
wcstring result = argv0 ? argv0 : L"null";
|
|
|
|
return result + L" ...";
|
2018-10-02 16:19:56 +00:00
|
|
|
}
|
|
|
|
|
2017-01-23 17:28:34 +00:00
|
|
|
/// All the processes in this job.
|
|
|
|
process_list_t processes;
|
|
|
|
|
2020-05-30 21:05:07 +00:00
|
|
|
// The group containing this job.
|
2020-02-08 22:34:10 +00:00
|
|
|
// This is never null and not changed after construction.
|
2020-05-30 21:05:07 +00:00
|
|
|
job_group_ref_t group{};
|
2020-02-08 22:34:10 +00:00
|
|
|
|
2022-02-19 18:05:50 +00:00
|
|
|
/// \return our pgid, or none if we don't have one, or are internal to fish
|
|
|
|
/// This never returns fish's own pgroup.
|
2020-07-19 23:41:58 +00:00
|
|
|
maybe_t<pid_t> get_pgid() const;
|
2019-06-23 19:39:29 +00:00
|
|
|
|
2021-05-18 19:35:37 +00:00
|
|
|
/// \return the pid of the last external process in the job.
|
|
|
|
/// This may be none if the job consists of just internal fish functions or builtins.
|
|
|
|
/// This will never be fish's own pid.
|
|
|
|
maybe_t<pid_t> get_last_pid() const;
|
|
|
|
|
2019-06-23 19:39:29 +00:00
|
|
|
/// The id of this job.
|
2020-02-08 23:43:21 +00:00
|
|
|
/// This is user-visible, is recycled, and may be -1.
|
2020-07-19 23:41:58 +00:00
|
|
|
job_id_t job_id() const;
|
Introduce the internal jobs for functions
This PR is aimed at improving how job ids are assigned. In particular,
previous to this commit, a job id would be consumed by functions (and
thus aliases). Since it's usual to use functions as command wrappers
this results in awkward job id assignments.
For example if the user is like me and just made the jump from vim -> neovim
then the user might create the following alias:
```
alias vim=nvim
```
Previous to this commit if the user ran `vim` after setting up this
alias, backgrounded (^Z) and ran `jobs` then the output might be:
```
Job Group State Command
2 60267 stopped nvim $argv
```
If the user subsequently opened another vim (nvim) session, backgrounded
and ran jobs then they might see what follows:
```
Job Group State Command
4 70542 stopped nvim $argv
2 60267 stopped nvim $argv
```
These job ids feel unnatural, especially when transitioning away from
e.g. bash where job ids are sequentially incremented (and aliases/functions
don't consume a job id).
See #6053 for more details.
As @ridiculousfish pointed out in
https://github.com/fish-shell/fish-shell/issues/6053#issuecomment-559899400,
we want to elide a job's job id if it corresponds to a single function in the
foreground. This translates to the following prerequisites:
- A job must correspond to a single process (i.e. the job continuation
must be empty)
- A job must be in the foreground (i.e. `&` wasn't appended)
- The job's single process must resolve to a function invocation
If all of these conditions are true then we should mark a job as
"internal" and somehow remove it from consideration when any
infrastructure tries to interact with jobs / job ids.
I saw two paths to implement these requirements:
- At the time of job creation calculate whether or not a job is
"internal" and use a separate list of job ids to track their ids.
Additionally introduce a new flag denoting that a job is internal so
that e.g. `jobs` doesn't list internal jobs
- I started implementing this route but quickly realized I was
computing the same information that would be computed later on (e.g.
"is this job a single process" and "is this jobs statement a
function"). Specifically I was computing data that populate_job_process
would end up computing later anyway. Additionally this added some
weird complexities to the job system (after the change there were two
job id lists AND an additional flag that had to be taken into
consideration)
- Once a function is about to be executed we release the current jobs
job id if the prerequisites are satisfied (which at this point have
been fully computed).
- I opted for this solution since it seems cleaner. In this
implementation "releasing a job id" is done by both calling
`release_job_id` and by marking the internal job_id member variable to
-1. The former operation allows subsequent child jobs to reuse that
same job id (so e.g. the situation described in Motivation doesn't
occur), and the latter ensures that no other job / job id
infrastructure will interact with these jobs because valid jobs have
positive job ids. The second operation causes job_id to become
non-const which leads to the list of code changes outside of `exec.c`
(i.e. a codemod from `job_t::job_id` -> `job_t::job_id()` and moving the
old member variable to a non-const private `job_t::job_id_`)
Note: Its very possible I missed something and setting the job id to -1
will break some other infrastructure, please let me know if so!
I tried to run `make/ninja lint`, but a bunch of non-relevant issues
appeared (e.g. `fatal error: 'config.h' file not found`). I did
successfully clang-format (`git clang-format -f`) and run tests, though.
This PR closes #6053.
2019-12-29 15:46:07 +00:00
|
|
|
|
2020-02-08 23:43:21 +00:00
|
|
|
/// A non-user-visible, never-recycled job ID.
|
|
|
|
const internal_job_id_t internal_job_id;
|
|
|
|
|
2023-01-14 22:56:24 +00:00
|
|
|
/// Getter to enable ffi.
|
|
|
|
internal_job_id_t get_internal_job_id() const { return internal_job_id; }
|
|
|
|
|
2019-10-15 21:37:10 +00:00
|
|
|
/// Flags associated with the job.
|
|
|
|
struct flags_t {
|
2020-02-08 23:12:58 +00:00
|
|
|
/// Whether the specified job is completely constructed: every process in the job has been
|
|
|
|
/// forked, etc.
|
|
|
|
bool constructed{false};
|
|
|
|
|
2021-11-03 22:13:26 +00:00
|
|
|
/// Whether the user has been notified that this job is stopped (if it is).
|
|
|
|
bool notified_of_stop{false};
|
2019-10-15 21:37:10 +00:00
|
|
|
|
|
|
|
/// Whether the exit status should be negated. This flag can only be set by the not builtin.
|
2021-12-28 15:38:53 +00:00
|
|
|
/// Two "not" prefixes on a single job cancel each other out.
|
2019-10-15 21:37:10 +00:00
|
|
|
bool negate{false};
|
|
|
|
|
|
|
|
/// This job is disowned, and should be removed from the active jobs list.
|
|
|
|
bool disown_requested{false};
|
2019-12-21 10:45:07 +00:00
|
|
|
|
2020-07-12 00:05:42 +00:00
|
|
|
// Indicates that we are the "group root." Any other jobs using this tree are nested.
|
|
|
|
bool is_group_root{false};
|
2020-02-08 23:12:58 +00:00
|
|
|
|
2019-10-15 21:37:10 +00:00
|
|
|
} job_flags{};
|
|
|
|
|
|
|
|
/// Access the job flags.
|
|
|
|
const flags_t &flags() const { return job_flags; }
|
2013-08-18 23:55:01 +00:00
|
|
|
|
2019-10-15 21:37:10 +00:00
|
|
|
/// Access mutable job flags.
|
|
|
|
flags_t &mut_flags() { return job_flags; }
|
2017-01-26 23:06:58 +00:00
|
|
|
|
2020-09-01 20:43:57 +00:00
|
|
|
// \return whether we should print timing information.
|
|
|
|
bool wants_timing() const { return properties.wants_timing; }
|
|
|
|
|
2019-06-23 19:39:29 +00:00
|
|
|
/// \return if we want job control.
|
2022-02-19 18:05:50 +00:00
|
|
|
bool wants_job_control() const;
|
2019-06-23 19:39:29 +00:00
|
|
|
|
2020-02-19 17:21:09 +00:00
|
|
|
/// \return whether this job is initially going to run in the background, because & was
|
|
|
|
/// specified.
|
|
|
|
bool is_initially_background() const { return properties.initial_background; }
|
|
|
|
|
2019-12-11 02:32:56 +00:00
|
|
|
/// Mark this job as constructed. The job must not have previously been marked as constructed.
|
|
|
|
void mark_constructed();
|
|
|
|
|
2020-01-30 00:39:44 +00:00
|
|
|
/// \return whether we have internal or external procs, respectively.
|
|
|
|
/// Internal procs are builtins, blocks, and functions.
|
|
|
|
/// External procs include exec and external.
|
|
|
|
bool has_external_proc() const;
|
|
|
|
|
2022-02-19 18:05:50 +00:00
|
|
|
/// \return whether this job, when run, will want a job ID.
|
|
|
|
/// Jobs that are only a single internal block do not get a job ID.
|
|
|
|
bool wants_job_id() const;
|
|
|
|
|
2018-10-02 17:30:23 +00:00
|
|
|
// Helper functions to check presence of flags on instances of jobs
|
|
|
|
/// The job has been fully constructed, i.e. all its member processes have been launched
|
2020-02-08 23:12:58 +00:00
|
|
|
bool is_constructed() const { return flags().constructed; }
|
2018-10-02 17:30:23 +00:00
|
|
|
/// The job is complete, i.e. all its member processes have been reaped
|
|
|
|
bool is_completed() const;
|
|
|
|
/// The job is in a stopped state
|
|
|
|
bool is_stopped() const;
|
2019-04-10 04:29:58 +00:00
|
|
|
/// The job is OK to be externally visible, e.g. to the user via `jobs`
|
2019-04-29 05:33:29 +00:00
|
|
|
bool is_visible() const {
|
2019-10-15 21:37:10 +00:00
|
|
|
return !is_completed() && is_constructed() && !flags().disown_requested;
|
2019-11-20 06:17:30 +00:00
|
|
|
}
|
2019-06-23 19:39:29 +00:00
|
|
|
bool skip_notification() const { return properties.skip_notification; }
|
2019-06-26 18:28:27 +00:00
|
|
|
bool from_event_handler() const { return properties.from_event_handler; }
|
2018-10-02 17:30:23 +00:00
|
|
|
|
2020-07-12 00:01:52 +00:00
|
|
|
/// \return whether this job's group is in the foreground.
|
2020-07-19 23:41:58 +00:00
|
|
|
bool is_foreground() const;
|
2020-07-12 00:01:52 +00:00
|
|
|
|
2021-11-03 22:03:37 +00:00
|
|
|
/// \return whether we should post job_exit events.
|
|
|
|
bool posts_job_exit_events() const;
|
2018-11-04 09:11:12 +00:00
|
|
|
|
2022-02-13 21:12:18 +00:00
|
|
|
/// Run ourselves. Returning once we complete or stop.
|
|
|
|
void continue_job(parser_t &parser);
|
|
|
|
|
|
|
|
/// Prepare to resume a stopped job by sending SIGCONT and clearing the stopped flag.
|
|
|
|
/// \return true on success, false if we failed to send the signal.
|
|
|
|
bool resume();
|
2018-10-02 17:30:23 +00:00
|
|
|
|
|
|
|
/// Send the specified signal to all processes in this job.
|
2018-10-02 20:10:42 +00:00
|
|
|
/// \return true on success, false on failure.
|
|
|
|
bool signal(int signal);
|
2018-10-02 17:30:23 +00:00
|
|
|
|
2019-02-25 09:21:32 +00:00
|
|
|
/// \returns the statuses for this job.
|
2020-07-18 17:25:43 +00:00
|
|
|
maybe_t<statuses_t> get_statuses() const;
|
2023-01-14 22:56:24 +00:00
|
|
|
|
|
|
|
/// \returns the list of processes.
|
|
|
|
const process_list_t &get_processes() const;
|
|
|
|
|
|
|
|
/// autocxx junk.
|
|
|
|
RustFFIProcList ffi_processes() const;
|
2023-02-28 22:42:12 +00:00
|
|
|
|
|
|
|
/// autocxx junk.
|
|
|
|
const job_group_t &ffi_group() const;
|
|
|
|
|
|
|
|
/// autocxx junk.
|
|
|
|
/// The const is a lie and is only necessary since at the moment cxx's SharedPtr doesn't support
|
|
|
|
/// getting a mutable reference.
|
|
|
|
bool ffi_resume() const;
|
2012-01-30 00:36:21 +00:00
|
|
|
};
|
2021-11-03 22:03:37 +00:00
|
|
|
using job_ref_t = std::shared_ptr<job_t>;
|
2005-09-20 13:26:39 +00:00
|
|
|
|
2023-01-14 22:56:24 +00:00
|
|
|
// Helper junk for autocxx.
|
|
|
|
struct RustFFIJobList {
|
|
|
|
job_ref_t *jobs;
|
|
|
|
size_t count;
|
|
|
|
};
|
|
|
|
|
2020-12-06 21:40:45 +00:00
|
|
|
/// Whether this shell is attached to a tty.
|
|
|
|
bool is_interactive_session();
|
|
|
|
void set_interactive_session(bool flag);
|
2005-12-15 13:59:02 +00:00
|
|
|
|
2016-05-03 04:41:17 +00:00
|
|
|
/// Whether we are a login shell.
|
2019-05-12 22:48:00 +00:00
|
|
|
bool get_login();
|
|
|
|
void mark_login();
|
|
|
|
|
|
|
|
/// If this flag is set, fish will never fork or run execve. It is used to put fish into a syntax
|
|
|
|
/// verifier mode where fish tries to validate the syntax of a file but doesn't actually do
|
|
|
|
/// anything.
|
|
|
|
bool no_exec();
|
|
|
|
void mark_no_exec();
|
2005-12-15 13:59:02 +00:00
|
|
|
|
2018-12-31 05:53:26 +00:00
|
|
|
// List of jobs.
|
2023-01-14 22:56:24 +00:00
|
|
|
using job_list_t = std::vector<job_ref_t>;
|
2012-02-28 02:43:24 +00:00
|
|
|
|
2016-05-03 04:41:17 +00:00
|
|
|
/// The current job control mode.
|
|
|
|
///
|
2019-03-24 19:12:08 +00:00
|
|
|
/// Must be one of job_control_t::all, job_control_t::interactive and job_control_t::none.
|
2019-04-30 06:08:01 +00:00
|
|
|
job_control_t get_job_control_mode();
|
|
|
|
void set_job_control_mode(job_control_t mode);
|
2006-01-30 17:54:26 +00:00
|
|
|
|
2019-04-29 16:05:00 +00:00
|
|
|
/// Notify the user about stopped or terminated jobs, and delete completed jobs from the job list.
|
2019-04-30 03:58:58 +00:00
|
|
|
/// If \p interactive is set, allow removing interactive jobs; otherwise skip them.
|
2019-04-29 16:05:00 +00:00
|
|
|
/// \return whether text was printed to stdout.
|
2019-04-30 03:58:58 +00:00
|
|
|
bool job_reap(parser_t &parser, bool interactive);
|
2005-12-15 13:59:02 +00:00
|
|
|
|
2020-02-20 01:22:54 +00:00
|
|
|
/// \return the list of background jobs which we should warn the user about, if the user attempts to
|
|
|
|
/// exit. An empty result (common) means no such jobs.
|
|
|
|
job_list_t jobs_requiring_warning_on_exit(const parser_t &parser);
|
|
|
|
|
|
|
|
/// Print the exit warning for the given jobs, which should have been obtained via
|
|
|
|
/// jobs_requiring_warning_on_exit().
|
|
|
|
void print_exit_warning_for_jobs(const job_list_t &jobs);
|
|
|
|
|
2021-08-27 20:03:01 +00:00
|
|
|
/// Use the procfs filesystem to look up how many jiffies of cpu time was used by a given pid. This
|
2016-05-03 04:41:17 +00:00
|
|
|
/// function is only available on systems with the procfs file entry 'stat', i.e. Linux.
|
2022-05-07 22:08:12 +00:00
|
|
|
clock_ticks_t proc_get_jiffies(pid_t inpid);
|
2005-09-20 13:26:39 +00:00
|
|
|
|
2016-05-03 04:41:17 +00:00
|
|
|
/// Update process time usage for all processes by calling the proc_get_jiffies function for every
|
|
|
|
/// process of every job.
|
2019-05-05 05:12:31 +00:00
|
|
|
void proc_update_jiffies(parser_t &parser);
|
2005-09-20 13:26:39 +00:00
|
|
|
|
2016-05-03 04:41:17 +00:00
|
|
|
/// Initializations.
|
2005-10-14 11:40:33 +00:00
|
|
|
void proc_init();
|
|
|
|
|
2019-03-03 00:45:15 +00:00
|
|
|
/// Wait for any process finishing, or receipt of a signal.
|
2019-04-30 03:58:58 +00:00
|
|
|
void proc_wait_any(parser_t &parser);
|
2017-10-22 07:10:23 +00:00
|
|
|
|
2020-02-20 03:35:04 +00:00
|
|
|
/// Send SIGHUP to the list \p jobs, excepting those which are in fish's pgroup.
|
|
|
|
void hup_jobs(const job_list_t &jobs);
|
2018-10-20 18:58:51 +00:00
|
|
|
|
2020-07-14 14:20:46 +00:00
|
|
|
/// Add a job to the list of PIDs/PGIDs we wait on even though they are not associated with any
|
|
|
|
/// jobs. Used to avoid zombie processes after disown.
|
2021-04-04 04:05:32 +00:00
|
|
|
void add_disowned_job(const job_t *j);
|
2018-10-02 03:55:18 +00:00
|
|
|
|
2019-05-12 21:59:30 +00:00
|
|
|
bool have_proc_stat();
|
2019-04-29 13:29:21 +00:00
|
|
|
|
2018-10-02 03:55:18 +00:00
|
|
|
#endif
|