Commit Graph

173 Commits

Author SHA1 Message Date
Mahmoud Al-Qudsi
4aea4c09b3 Optimize identification of deferred process 2019-03-28 22:12:50 -05:00
ridiculousfish
5eade35257 Stop buffering deferred function processes
If a function process is deferred, allow it to be unbuffered.
This permits certain simple cases where functions are piped to external
commands to execute without buffering.

This is a somewhat-hacky stopgap measure that can't really be extended
to more general concurrent processes. However it is overall an improvement
in user experience that might help flush out some bugs too.
2019-03-24 21:23:26 -07:00
ridiculousfish
3bbee06248 Introduce the notion of a deferred process
In a job, a deferred process is the last fish internal process which pipes
to an external command. Execute the deferred process last; this will allow
for streaming its output.
2019-03-24 14:27:23 -07:00
ridiculousfish
165c82e68a Promote process_type_t to an enum class 2019-03-24 12:29:25 -07:00
Aaron Gyes
477b2e8d7c std::vector<wcstring> is wcstring_list_t 2019-03-14 11:17:26 -07:00
Aaron Gyes
aaacdb89b6 Switches over to cstring from string.h. 2019-03-12 15:09:36 -07:00
ridiculousfish
1a4bb50cd5 Combine status and pipestatus into statuses_t
In most places where we set one, we want to set both. Make this less
error-prone by combining them into a single type statuses_t.
2019-02-26 20:07:37 -08:00
ridiculousfish
bb36274e6b Introduce proc_status_t
In fish we play fast and loose with status codes as set directly (e.g. on
failed redirections), vs status codes returned from waitpid(), versus the
value $status. Introduce a new value type proc_status_t to encapsulate
this logic.
2019-02-25 10:14:45 -08:00
ridiculousfish
2c3214cabd Make $pipestatus thread safe and other misc cleanup 2019-02-24 23:29:33 -08:00
zabereer
2c8abdf5cb add $pipestatus support 2019-02-24 21:46:52 -08:00
ridiculousfish
0b3eca1743 Cleanup handle_builtin_output
Now that we use an internal process to perform builtin output, simplify the
logic around how it is performed. In particular we no longer have to be
careful about async-safe functions since we do not fork.

Also fix a bunch of comments that no longer apply.
2019-02-17 14:17:44 -08:00
ridiculousfish
4a2fd443b2 Use internal processes to write builtin output
This uses the new internal process mechanism to write output for builtins.
After this the only reason fish ever forks is to execute external processes.
2019-02-17 13:08:00 -08:00
ridiculousfish
ada8ea954e Use "internal" processes to write buffered output
This introduces "internal processes" which are backed by a pthread instead
of a normal process. Internal processes are reaped using the topic
machinery, plugging in neatly alongside the sigchld topic; this means that
process_mark_finished_children() can wait for internal and external
processes simultaneously.

Initially internal processes replace the forked process that fish uses to
write out the output of blocks and functions.
2019-02-17 13:05:20 -08:00
ridiculousfish
ebe2dc2766 Processes to record topic generations before execution
The sigchld generation expresses the idea that, if we receive a sigchld
signal, the generation will be different than when we last recorded it. A
process cannot exit before it has launched, so check the generation count
before process launch. This is an optimization that reduces failing
waitpid calls.
2019-02-17 13:01:59 -08:00
Mrmaxmeier
6e9250425a src/exec: fix assertion on failed exec redirection
Minimal reproducer: `fish -c "exec cat<x"`
2019-02-12 20:52:03 -08:00
ridiculousfish
1701e2c558 Revert "add $pipestatus support"
This reverts commit ec290209db.
2019-02-10 13:46:58 -08:00
zabereer
ec290209db add $pipestatus support 2019-02-10 13:30:40 -08:00
David Adam
662708e72d src/exec: drop unused parameter in can_use_posix_spawn_for_job
Process object is not checked since 084ff64f4f.
2019-02-10 15:57:06 +08:00
ridiculousfish
d3fa58d621 Cleanup common.h
Remove a bunch of headers, simplify lots of code, migrate it into .cpp files.

Debug build time improves by ~3 seconds on my Mac.
2019-02-03 18:22:38 -08:00
ridiculousfish
6f682c8405 Fill io_buffer via background thread
This is a large change to how io_buffers are filled. The essential problem
comes about with code like (example):

    echo ( /bin/pwd )

The output of /bin/pwd must go to fish, not the tty. To arrange for this,
fish does the following:

1. Invoke pipe() to create a pipe.
2. Add an io_bufferfill_t redirection that owns the write end of the pipe.
3. After fork (or equiv), call dup2() to replace pwd's stdout with this  pipe.

Now when /bin/pwd writes, it will send output to the read end of the pipe.
But who reads it?

Prior to this fix, fish would do the following in a loop:

1. select() on the pipe with a 10 msec timeout
2. waitpid(WNOHANG) on the pwd proc

This polling is ugly and confusing and is what is replaced here.

With this new change, fish now reads from the pipe via a background thread:

1. Spawn a background pthread, which select()s on the pipe's read end with
a long (100 msec) timeout.
2. In the foreground, waitpid() (allowing hanging) on the pwd proc.

The big win here is a major simplification of job_t::continue_job() since
it no longer has to worry about filling buffers. This will make things
easier for concurrent execution.

It may not be obvious why the background thread still needs a poll (100 msec).
The answer is for cases where the write end of the fd escapes, in particular
background processes invoked inside command substitutions. psub is perhaps
the only important case of this (other shells typically just hang here).
2019-02-03 01:58:49 -08:00
ridiculousfish
178b72b2fd io_buffer_t becomes io_bufferfill_t
This makes some significant architectual improvements to io_pipe_t and
io_buffer_t.

Prior to this fix, io_buffer_t subclassed io_pipe_t. io_buffer_t is now
replaced with a class io_bufferfill_t, which does not subclass pipe.

io_pipe_t no longer remembers both fds. Instead it has an autoclose_fd_t,
so that the file descriptor ownership is clear.
2019-02-03 01:58:49 -08:00
ridiculousfish
084ff64f4f Allow posix_spawn more often
Now that we no longer open files after fork, we can correctly report errors
for failed file opens. So allow posix_spawn even if there's redirections.
2019-02-03 01:58:49 -08:00
ridiculousfish
2742267b9e Use dup2_list_t in posix_spawn
This simplifies the posix_spawn path and unifies it with the fork execution
path.
2019-02-03 01:58:49 -08:00
ridiculousfish
d62576ce22 Adopt dup2_list_t in fork execution path
This switches IO redirections after fork() to use the dup2_list_t,
instead of io_chain_t. This results in simpler code with much simpler
error handling.
2019-02-03 01:58:49 -08:00
ridiculousfish
6ba0d4c88a Revert io_bufferfill_t stack
This reverts commit 88dc484858 onwards.
2019-02-02 17:53:40 -08:00
ridiculousfish
9a4153f5e2 Fill io_buffer via background thread
This is a large change to how io_buffers are filled. The essential problem
comes about with code like (example):

    echo ( /bin/pwd )

The output of /bin/pwd must go to fish, not the tty. To arrange for this,
fish does the following:

1. Invoke pipe() to create a pipe.
2. Add an io_bufferfill_t redirection that owns the write end of the pipe.
3. After fork (or equiv), call dup2() to replace pwd's stdout with this  pipe.

Now when /bin/pwd writes, it will send output to the read end of the pipe.
But who reads it?

Prior to this fix, fish would do the following in a loop:

1. select() on the pipe with a 10 msec timeout
2. waitpid(WNOHANG) on the pwd proc

This polling is ugly and confusing and is what is replaced here.

With this new change, fish now reads from the pipe via a background thread:

1. Spawn a background pthread, which select()s on the pipe's read end with
a long (100 msec) timeout.
2. In the foreground, waitpid() (allowing hanging) on the pwd proc.

The big win here is a major simplification of job_t::continue_job() since
it no longer has to worry about filling buffers. This will make things
easier for concurrent execution.

It may not be obvious why the background thread still needs a poll (100 msec).
The answer is for cases where the write end of the fd escapes, in particular
background processes invoked inside command substitutions. psub is perhaps
the only important case of this (other shells typically just hang here).
2019-02-02 14:21:46 -08:00
ridiculousfish
78bbcef356 io_buffer_t becomes io_bufferfill_t
This makes some significant architectual improvements to io_pipe_t and
io_buffer_t.

Prior to this fix, io_buffer_t subclassed io_pipe_t. io_buffer_t is now
replaced with a class io_bufferfill_t, which does not subclass pipe.

io_pipe_t no longer remembers both fds. Instead it has an autoclose_fd_t,
so that the file descriptor ownership is clear.
2019-02-02 14:21:46 -08:00
ridiculousfish
7c256e7e51 Allow posix_spawn more often
Now that we no longer open files after fork, we can correctly report errors
for failed file opens. So allow posix_spawn even if there's redirections.
2019-02-02 14:21:46 -08:00
ridiculousfish
4c0b6a6add Use dup2_list_t in posix_spawn
This simplifies the posix_spawn path and unifies it with the fork execution
path.
2019-02-02 14:21:46 -08:00
ridiculousfish
d895075d9b Adopt dup2_list_t in fork execution path
This switches IO redirections after fork() to use the dup2_list_t,
instead of io_chain_t. This results in simpler code with much simpler
error handling.
2019-02-02 14:21:46 -08:00
ridiculousfish
b00f039489 Clean up the io_chain_t interface 2019-01-31 18:49:52 -08:00
ridiculousfish
371f67f1b5 Remove pipe_read_fd
In practice it was always STDIN_FILENO.
2019-01-31 17:58:59 -08:00
ridiculousfish
a2aab24db7 Switch io_mode to an enum class 2019-01-31 12:12:46 -08:00
ridiculousfish
6f52e6bb1c Instantize contents of exec.cpp and others 2019-01-10 20:07:47 -08:00
ridiculousfish
c1dd284b3e Instantize env_set
Switch env_set to an instance method on environmnet_t.
2019-01-10 20:05:45 -08:00
ridiculousfish
ede66ccaac Instance env_set_argv and env_set_pwd 2019-01-10 20:29:10 -08:00
ridiculousfish
e6872b83b0 Eliminate global env_export_arr()
This assumes the set of exported variables is a global property; but we
want it to be a local property.
2019-01-10 20:29:10 -08:00
Mahmoud Al-Qudsi
3d557518d5 Replace 0/1 with true/false in calls to job_reap 2018-11-18 17:40:18 -06:00
Mahmoud Al-Qudsi
d0085cae3c Fix zombie job on failed redirection in exec_job
Closes #5346.
2018-11-18 17:40:18 -06:00
ridiculousfish
73537fc7c3 Remove NESTED and WAIT_BY_PROCESS
Now jobs are aware of their parent jobs, and can interrogate those jobs,
to determine if every job in the chain is fully constructed.
Remove flags and the static stacks that manipulated them.
2018-11-04 01:52:17 -08:00
ridiculousfish
3770d9fb7a Teach each job about its parent
The parent of a job is the parent pipeline that executed the function or
block corresponding to this job. This will help simplify
process_mark_finished_children().
2018-11-04 01:40:07 -08:00
ridiculousfish
93aa95d8c4 Remove proc_last_bg_pid
It wasn't used.
2018-11-03 19:28:16 -07:00
Mahmoud Al-Qudsi
4d3b56c151 Associate external commands in functions with extant pgrps
When a function is encountered by exec_job, a new context is created for
its execution from the ground up, with a new job and all, ultimately
resulting in a recursive call to exec_job from the same (main) thread.

Since each time exec_job encounters a new job with external commands
that needs terminal control it creates a new pgrp and gives it control
of the terminal (tcsetpgrp & co), this effectively takes control away
from the previously spawned external commands which may be (and likely
are) expecting to still have terminal access.

This commit attempts to detect when such a situation arises by handling
recursive calls to exec_job (which can only happen if the pipeline
included a function) by borrowing the pgrp from the (necessarily still
active) parent job and spawning new external commands into it.

When a parent job spawns new jobs due to the evaluation of a new
function (which shouldn't be the case in the first place), we end up
with two distinct jobs sharing one pgrp (to fix #3952). This can lead to
early termination of a pgrp if finished parent job children are reaped
before future processes in either the parent or future child jobs can
join it.

While the parent job is under construction, require that waitpid(2)
calls for the child job be done by process id and not job pgrp.

Closes #3952.
2018-10-27 18:01:38 -05:00
Mahmoud Al-Qudsi
419d7a5138 Don't decompose shared_ptr to raw pointer for exec_job 2018-10-27 18:01:38 -05:00
Mahmoud Al-Qudsi
3afcca3114 Drop keepalive process even for WSL
Windows 10 17763 Redstone 5 (October 2018 Update) officially brings
zombie support (first introduced in 17713) to the general public.

See https://docs.microsoft.com/en-us/windows/wsl/release-notes#build-17763-1809
2018-10-27 18:01:38 -05:00
Mahmoud Al-Qudsi
f9118d964e Clean up job flags, status helpers, and instance helper methods
* Convert JOB_* enums to scoped enums
* Convert standalone job_is_* functions to member functions
* Convert standalone job_{promote, signal, continue} to member functions
* Convert standolen job_get{,_from_pid} to `job_t` static functions
* Reduce usage of JOB_* enums outside of proc.cpp by using new
  `job_t::is_foo()` const helper methods instead.

This patch is only a refactor and should not change any functionality or
behavior (both observed and unobserved).
2018-10-27 18:01:38 -05:00
Mahmoud Al-Qudsi
e753581df7 Bring some consistency and rationale to debug log levels
* Debug level 3: describe all commands being executed (this is, after all,
a shell and one can argue that this is the most important debug
information avaliable)
* Debug level 4: details of execution, mainly fork vs no-fork and io
handling

Also introduced j->preview() to print a short descriptor of the job
based on the head of the first process so we don't overwhelm with
needless repitition, but also so that we don't have to rely on
distinguishing between repeated, non-unique/non-monotonic job ids that
are often recycled within a single "execution cycle" (pressing enter
once).
2018-10-27 18:01:38 -05:00
Mahmoud Al-Qudsi
d467bb58d9 Replace pid/pgid -2 with INVALID_PID 2018-10-27 18:01:38 -05:00
Mahmoud Al-Qudsi
af0c8d51e0 Overhaul job and terminal control
* Instead of reaping all child processes when we receive a SIGCHLD, try
reaping only processes belonging to process groups from fully-
constructed jobs, which should eliminate the need for the keepalive
process entirely (WSL's lack of zombies not withstanding) as now
completed processes are not reaped until the job has been fully
constructed (i.e.  all processes launched), which means their process
group should still be around for new processes to join.

* When `tcgetpgrp()` calls return 0, attempt to `tcsetpgrp()` before
invoking failure handling code.

* When forking a builtin and not running interactively, do not bail if
unable to set/restore terminal attributes.

Fixes #4178. Fixes #3805. Fixes #5210.
2018-10-27 18:01:38 -05:00
ridiculousfish
a17a815c87 Revert "Add vector of cleanup/termination events to be executed before quit"
This reverts commit 8c14f0f30f.

This list is not reliable - there are many ways for fish to quit that does not
invoke these functions. It's also not necessary since the history is correctly
saved on exec.
2018-09-28 20:21:23 -04:00