Start another program then quit
From a program A written in rust, I want to start a program B, have A end, and have B normally run just like if it was manually launched from the same shell just after termination of A.
My current program:
use std::process::Command;
pub fn execute(exe: &str, args: &[&str]) {
Command::new(exe)
.args(args)
.spawn()
.expect("failed to start external executable");
}
fn main() {
execute("/usr/bin/nvim", &["/home/dys/todo.txt"]);
}
This fails. nvim is launched as a child and is non-working as soon as the calling program stops.
How can I write execute
so the caller program immediately stops and lets nvim (or another program) properly run (even without any windowing system) ?
process rust
|
show 13 more comments
From a program A written in rust, I want to start a program B, have A end, and have B normally run just like if it was manually launched from the same shell just after termination of A.
My current program:
use std::process::Command;
pub fn execute(exe: &str, args: &[&str]) {
Command::new(exe)
.args(args)
.spawn()
.expect("failed to start external executable");
}
fn main() {
execute("/usr/bin/nvim", &["/home/dys/todo.txt"]);
}
This fails. nvim is launched as a child and is non-working as soon as the calling program stops.
How can I write execute
so the caller program immediately stops and lets nvim (or another program) properly run (even without any windowing system) ?
process rust
Does Windows really kill all child processes as soon as the parent process dies? It's been two decades since I did software development on Windows, but I don't remember this behaviour.
– Sven Marnach
Nov 26 '18 at 9:35
@SvenMarnach I don't know for Windows as I don't have any box available right now. My requirement is to have it work on windows, linux and macos. I'll remove the OS tags (for a time maybe) to make it clear this isn't a Windows specific question.
– Denys Séguret
Nov 26 '18 at 9:37
I missed there was also a Linux tag. Neither Linux nor Windows kill the child process when the parent process exits.
– Sven Marnach
Nov 26 '18 at 9:46
1
@SvenMarnach becauseprocess::spawn()
is setting up some pipes between parent and child. Have awhile true; echo foo; sleep 1; done
as the child, and you should see the failure.
– Florian Margaine
Nov 26 '18 at 11:05
1
Which explains both why anos.setsid()
in the beginning the process works, and why it's not reproducible withstrace
(stdin is not a pty)
– Florian Margaine
Nov 26 '18 at 14:10
|
show 13 more comments
From a program A written in rust, I want to start a program B, have A end, and have B normally run just like if it was manually launched from the same shell just after termination of A.
My current program:
use std::process::Command;
pub fn execute(exe: &str, args: &[&str]) {
Command::new(exe)
.args(args)
.spawn()
.expect("failed to start external executable");
}
fn main() {
execute("/usr/bin/nvim", &["/home/dys/todo.txt"]);
}
This fails. nvim is launched as a child and is non-working as soon as the calling program stops.
How can I write execute
so the caller program immediately stops and lets nvim (or another program) properly run (even without any windowing system) ?
process rust
From a program A written in rust, I want to start a program B, have A end, and have B normally run just like if it was manually launched from the same shell just after termination of A.
My current program:
use std::process::Command;
pub fn execute(exe: &str, args: &[&str]) {
Command::new(exe)
.args(args)
.spawn()
.expect("failed to start external executable");
}
fn main() {
execute("/usr/bin/nvim", &["/home/dys/todo.txt"]);
}
This fails. nvim is launched as a child and is non-working as soon as the calling program stops.
How can I write execute
so the caller program immediately stops and lets nvim (or another program) properly run (even without any windowing system) ?
process rust
process rust
edited Nov 26 '18 at 16:45
Denys Séguret
asked Nov 26 '18 at 9:13
Denys SéguretDenys Séguret
281k56589605
281k56589605
Does Windows really kill all child processes as soon as the parent process dies? It's been two decades since I did software development on Windows, but I don't remember this behaviour.
– Sven Marnach
Nov 26 '18 at 9:35
@SvenMarnach I don't know for Windows as I don't have any box available right now. My requirement is to have it work on windows, linux and macos. I'll remove the OS tags (for a time maybe) to make it clear this isn't a Windows specific question.
– Denys Séguret
Nov 26 '18 at 9:37
I missed there was also a Linux tag. Neither Linux nor Windows kill the child process when the parent process exits.
– Sven Marnach
Nov 26 '18 at 9:46
1
@SvenMarnach becauseprocess::spawn()
is setting up some pipes between parent and child. Have awhile true; echo foo; sleep 1; done
as the child, and you should see the failure.
– Florian Margaine
Nov 26 '18 at 11:05
1
Which explains both why anos.setsid()
in the beginning the process works, and why it's not reproducible withstrace
(stdin is not a pty)
– Florian Margaine
Nov 26 '18 at 14:10
|
show 13 more comments
Does Windows really kill all child processes as soon as the parent process dies? It's been two decades since I did software development on Windows, but I don't remember this behaviour.
– Sven Marnach
Nov 26 '18 at 9:35
@SvenMarnach I don't know for Windows as I don't have any box available right now. My requirement is to have it work on windows, linux and macos. I'll remove the OS tags (for a time maybe) to make it clear this isn't a Windows specific question.
– Denys Séguret
Nov 26 '18 at 9:37
I missed there was also a Linux tag. Neither Linux nor Windows kill the child process when the parent process exits.
– Sven Marnach
Nov 26 '18 at 9:46
1
@SvenMarnach becauseprocess::spawn()
is setting up some pipes between parent and child. Have awhile true; echo foo; sleep 1; done
as the child, and you should see the failure.
– Florian Margaine
Nov 26 '18 at 11:05
1
Which explains both why anos.setsid()
in the beginning the process works, and why it's not reproducible withstrace
(stdin is not a pty)
– Florian Margaine
Nov 26 '18 at 14:10
Does Windows really kill all child processes as soon as the parent process dies? It's been two decades since I did software development on Windows, but I don't remember this behaviour.
– Sven Marnach
Nov 26 '18 at 9:35
Does Windows really kill all child processes as soon as the parent process dies? It's been two decades since I did software development on Windows, but I don't remember this behaviour.
– Sven Marnach
Nov 26 '18 at 9:35
@SvenMarnach I don't know for Windows as I don't have any box available right now. My requirement is to have it work on windows, linux and macos. I'll remove the OS tags (for a time maybe) to make it clear this isn't a Windows specific question.
– Denys Séguret
Nov 26 '18 at 9:37
@SvenMarnach I don't know for Windows as I don't have any box available right now. My requirement is to have it work on windows, linux and macos. I'll remove the OS tags (for a time maybe) to make it clear this isn't a Windows specific question.
– Denys Séguret
Nov 26 '18 at 9:37
I missed there was also a Linux tag. Neither Linux nor Windows kill the child process when the parent process exits.
– Sven Marnach
Nov 26 '18 at 9:46
I missed there was also a Linux tag. Neither Linux nor Windows kill the child process when the parent process exits.
– Sven Marnach
Nov 26 '18 at 9:46
1
1
@SvenMarnach because
process::spawn()
is setting up some pipes between parent and child. Have a while true; echo foo; sleep 1; done
as the child, and you should see the failure.– Florian Margaine
Nov 26 '18 at 11:05
@SvenMarnach because
process::spawn()
is setting up some pipes between parent and child. Have a while true; echo foo; sleep 1; done
as the child, and you should see the failure.– Florian Margaine
Nov 26 '18 at 11:05
1
1
Which explains both why an
os.setsid()
in the beginning the process works, and why it's not reproducible with strace
(stdin is not a pty)– Florian Margaine
Nov 26 '18 at 14:10
Which explains both why an
os.setsid()
in the beginning the process works, and why it's not reproducible with strace
(stdin is not a pty)– Florian Margaine
Nov 26 '18 at 14:10
|
show 13 more comments
2 Answers
2
active
oldest
votes
After further discussion, we identified the actual problem: The program you are launching is supposed to stay in the foreground, so it can read from the terminal (which background processes can't do on Unix).
There are two ways to achieve this. The first, and easiest, is to wait for the child process before the parent process exits:
use std::process::{Command, ExitStatus};
use std::io::Result;
pub fn execute(exe: &str, args: &[&str]) -> Result<ExitStatus> {
Command::new(exe).args(args).spawn()?.wait()
}
This ensures the processes (parent and child) stay in the foreground, since the shell is waiting for the parent process, so the child process can read from the terminal.
If for some reason you can't afford the parent process to linger on while the child process is running, you need platform-dependent code. On Unix, you can use some syscall from the exec()
familiy to replace the image of the parent process with the image of the child process:
use std::process::Command;
use std::os::unix::process::CommandExt;
use std::io::Error;
pub fn execute(exe: &str, args: &[&str]) -> Error {
Command::new(exe).args(args).exec()
}
The function only returns if there is an error. Otherwise, the process image is replaced by the new image. From the viewpoint of the shell, it's still the same process, so the shell will wait for the command you launched to finish.
The advantages of the second approach seem slim. It does not work on Windows, since Windows does not support exec()
and friends. You will have one less process around while running the command, but the resource usage of that process should be small in practice – it does not use any CPU, and the memory pages can be swapped out if necessary.
Original Answer
From a program A written in rust, I want to start a program B, have A end, and have B normally run just like if it was manually launched from the same shell just after termination of A.
This is more or less what your code is already doing. There are a few differences to a process launched directly from the shell on Unix systems, though:
- The new process will not be included in the shell's job list, so you can't use the shell's job control commands like
bg
andfg
. - The new process will run in the background, and the shell will immediately show a prompt after the Rust programs exits.
This fails because nvim is launched as a child and is killed as soon as the calling program stops.
This is not true, neither for Unix nor for Windows.
How can I write execute so the caller program immediately stops and lets nvim (or another program) properly run (even without any windowing system)?
This should be exactly what your Rust code is doing (and what it does when run on my Linux machine). The code in your answer, on the other hand, does something else: It uses execv()
to replace the Rust process with nvim. In effect, the process does not immediately stop, and the shell remaind blocked until nvim exits.
"and what it does when run on my Linux machine" Did you try with a real terminal program like vim and not just a sleep ? Your explanations are interesting but I don't see how you solve the problem.
– Denys Séguret
Nov 26 '18 at 11:20
@DenysSéguret I don't have "nvim" installed, so I didn't try that, by I triedbash -c 'while true; do echo a; sleep 2; done'
, and it still keeps running in the background.
– Sven Marnach
Nov 26 '18 at 11:48
@DenysSéguret I also suggested a simple solution that behaves similar to your answer in the comments to your answer – specifically, simply wait for the subprocess instead of immediately exiting. I did not include this in this answer, since it is in direct conflict with the requirements in the question (which asks that the caller program exits immediately).
– Sven Marnach
Nov 26 '18 at 12:03
thanks for the answer. An accept or not will only come after some more studies.
– Denys Séguret
Nov 26 '18 at 13:18
@DenysSéguret I adapted the answer to account for the findings in the comments.
– Sven Marnach
Nov 28 '18 at 15:28
|
show 1 more comment
Here's a working solution on linux, using a wrapping ot the execv
function:
use nix::unistd;
use std::ffi::CString;
pub fn executev(args: &[&str]) {
let mut args: Vec<CString> = args.iter()
.map(|t| CString::new(*t).expect("not a proper CString"))
.collect();
unistd::execv(
&args[0],
&args,
).expect("failed");
}
fn main() {
executev(&["/usr/bin/nvim", "/home/dys/todo.txt"]);
}
Note: This does start another program and quit but be wary that replacing the current process implies you properly closed open resources. If you can accept having your program kept alive, you probably want to wait
as suggested by Sven Marnach.
If this is confirmed to be the right solution, and after confirmation it was already working on Windows, then I'll clean this fast written solution up.
– Denys Séguret
Nov 26 '18 at 10:07
This does something different: theexecv()
function does not return on success, and the current process is replaced by the new process. Note thatCommand::spawn()
also usesexecv()
under the hood, but only afterfork()
ing a child process. I recommend looking into this answer to understand possible root causes of the behaviour you saw.
– Sven Marnach
Nov 26 '18 at 10:19
@SvenMarnach My understanding is that avoidingfork
was the goal
– Denys Séguret
Nov 26 '18 at 10:19
Then simply waiting for the subprocess would also work, and avoid platform-specific code.
– Sven Marnach
Nov 26 '18 at 10:22
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53477846%2fstart-another-program-then-quit%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
After further discussion, we identified the actual problem: The program you are launching is supposed to stay in the foreground, so it can read from the terminal (which background processes can't do on Unix).
There are two ways to achieve this. The first, and easiest, is to wait for the child process before the parent process exits:
use std::process::{Command, ExitStatus};
use std::io::Result;
pub fn execute(exe: &str, args: &[&str]) -> Result<ExitStatus> {
Command::new(exe).args(args).spawn()?.wait()
}
This ensures the processes (parent and child) stay in the foreground, since the shell is waiting for the parent process, so the child process can read from the terminal.
If for some reason you can't afford the parent process to linger on while the child process is running, you need platform-dependent code. On Unix, you can use some syscall from the exec()
familiy to replace the image of the parent process with the image of the child process:
use std::process::Command;
use std::os::unix::process::CommandExt;
use std::io::Error;
pub fn execute(exe: &str, args: &[&str]) -> Error {
Command::new(exe).args(args).exec()
}
The function only returns if there is an error. Otherwise, the process image is replaced by the new image. From the viewpoint of the shell, it's still the same process, so the shell will wait for the command you launched to finish.
The advantages of the second approach seem slim. It does not work on Windows, since Windows does not support exec()
and friends. You will have one less process around while running the command, but the resource usage of that process should be small in practice – it does not use any CPU, and the memory pages can be swapped out if necessary.
Original Answer
From a program A written in rust, I want to start a program B, have A end, and have B normally run just like if it was manually launched from the same shell just after termination of A.
This is more or less what your code is already doing. There are a few differences to a process launched directly from the shell on Unix systems, though:
- The new process will not be included in the shell's job list, so you can't use the shell's job control commands like
bg
andfg
. - The new process will run in the background, and the shell will immediately show a prompt after the Rust programs exits.
This fails because nvim is launched as a child and is killed as soon as the calling program stops.
This is not true, neither for Unix nor for Windows.
How can I write execute so the caller program immediately stops and lets nvim (or another program) properly run (even without any windowing system)?
This should be exactly what your Rust code is doing (and what it does when run on my Linux machine). The code in your answer, on the other hand, does something else: It uses execv()
to replace the Rust process with nvim. In effect, the process does not immediately stop, and the shell remaind blocked until nvim exits.
"and what it does when run on my Linux machine" Did you try with a real terminal program like vim and not just a sleep ? Your explanations are interesting but I don't see how you solve the problem.
– Denys Séguret
Nov 26 '18 at 11:20
@DenysSéguret I don't have "nvim" installed, so I didn't try that, by I triedbash -c 'while true; do echo a; sleep 2; done'
, and it still keeps running in the background.
– Sven Marnach
Nov 26 '18 at 11:48
@DenysSéguret I also suggested a simple solution that behaves similar to your answer in the comments to your answer – specifically, simply wait for the subprocess instead of immediately exiting. I did not include this in this answer, since it is in direct conflict with the requirements in the question (which asks that the caller program exits immediately).
– Sven Marnach
Nov 26 '18 at 12:03
thanks for the answer. An accept or not will only come after some more studies.
– Denys Séguret
Nov 26 '18 at 13:18
@DenysSéguret I adapted the answer to account for the findings in the comments.
– Sven Marnach
Nov 28 '18 at 15:28
|
show 1 more comment
After further discussion, we identified the actual problem: The program you are launching is supposed to stay in the foreground, so it can read from the terminal (which background processes can't do on Unix).
There are two ways to achieve this. The first, and easiest, is to wait for the child process before the parent process exits:
use std::process::{Command, ExitStatus};
use std::io::Result;
pub fn execute(exe: &str, args: &[&str]) -> Result<ExitStatus> {
Command::new(exe).args(args).spawn()?.wait()
}
This ensures the processes (parent and child) stay in the foreground, since the shell is waiting for the parent process, so the child process can read from the terminal.
If for some reason you can't afford the parent process to linger on while the child process is running, you need platform-dependent code. On Unix, you can use some syscall from the exec()
familiy to replace the image of the parent process with the image of the child process:
use std::process::Command;
use std::os::unix::process::CommandExt;
use std::io::Error;
pub fn execute(exe: &str, args: &[&str]) -> Error {
Command::new(exe).args(args).exec()
}
The function only returns if there is an error. Otherwise, the process image is replaced by the new image. From the viewpoint of the shell, it's still the same process, so the shell will wait for the command you launched to finish.
The advantages of the second approach seem slim. It does not work on Windows, since Windows does not support exec()
and friends. You will have one less process around while running the command, but the resource usage of that process should be small in practice – it does not use any CPU, and the memory pages can be swapped out if necessary.
Original Answer
From a program A written in rust, I want to start a program B, have A end, and have B normally run just like if it was manually launched from the same shell just after termination of A.
This is more or less what your code is already doing. There are a few differences to a process launched directly from the shell on Unix systems, though:
- The new process will not be included in the shell's job list, so you can't use the shell's job control commands like
bg
andfg
. - The new process will run in the background, and the shell will immediately show a prompt after the Rust programs exits.
This fails because nvim is launched as a child and is killed as soon as the calling program stops.
This is not true, neither for Unix nor for Windows.
How can I write execute so the caller program immediately stops and lets nvim (or another program) properly run (even without any windowing system)?
This should be exactly what your Rust code is doing (and what it does when run on my Linux machine). The code in your answer, on the other hand, does something else: It uses execv()
to replace the Rust process with nvim. In effect, the process does not immediately stop, and the shell remaind blocked until nvim exits.
"and what it does when run on my Linux machine" Did you try with a real terminal program like vim and not just a sleep ? Your explanations are interesting but I don't see how you solve the problem.
– Denys Séguret
Nov 26 '18 at 11:20
@DenysSéguret I don't have "nvim" installed, so I didn't try that, by I triedbash -c 'while true; do echo a; sleep 2; done'
, and it still keeps running in the background.
– Sven Marnach
Nov 26 '18 at 11:48
@DenysSéguret I also suggested a simple solution that behaves similar to your answer in the comments to your answer – specifically, simply wait for the subprocess instead of immediately exiting. I did not include this in this answer, since it is in direct conflict with the requirements in the question (which asks that the caller program exits immediately).
– Sven Marnach
Nov 26 '18 at 12:03
thanks for the answer. An accept or not will only come after some more studies.
– Denys Séguret
Nov 26 '18 at 13:18
@DenysSéguret I adapted the answer to account for the findings in the comments.
– Sven Marnach
Nov 28 '18 at 15:28
|
show 1 more comment
After further discussion, we identified the actual problem: The program you are launching is supposed to stay in the foreground, so it can read from the terminal (which background processes can't do on Unix).
There are two ways to achieve this. The first, and easiest, is to wait for the child process before the parent process exits:
use std::process::{Command, ExitStatus};
use std::io::Result;
pub fn execute(exe: &str, args: &[&str]) -> Result<ExitStatus> {
Command::new(exe).args(args).spawn()?.wait()
}
This ensures the processes (parent and child) stay in the foreground, since the shell is waiting for the parent process, so the child process can read from the terminal.
If for some reason you can't afford the parent process to linger on while the child process is running, you need platform-dependent code. On Unix, you can use some syscall from the exec()
familiy to replace the image of the parent process with the image of the child process:
use std::process::Command;
use std::os::unix::process::CommandExt;
use std::io::Error;
pub fn execute(exe: &str, args: &[&str]) -> Error {
Command::new(exe).args(args).exec()
}
The function only returns if there is an error. Otherwise, the process image is replaced by the new image. From the viewpoint of the shell, it's still the same process, so the shell will wait for the command you launched to finish.
The advantages of the second approach seem slim. It does not work on Windows, since Windows does not support exec()
and friends. You will have one less process around while running the command, but the resource usage of that process should be small in practice – it does not use any CPU, and the memory pages can be swapped out if necessary.
Original Answer
From a program A written in rust, I want to start a program B, have A end, and have B normally run just like if it was manually launched from the same shell just after termination of A.
This is more or less what your code is already doing. There are a few differences to a process launched directly from the shell on Unix systems, though:
- The new process will not be included in the shell's job list, so you can't use the shell's job control commands like
bg
andfg
. - The new process will run in the background, and the shell will immediately show a prompt after the Rust programs exits.
This fails because nvim is launched as a child and is killed as soon as the calling program stops.
This is not true, neither for Unix nor for Windows.
How can I write execute so the caller program immediately stops and lets nvim (or another program) properly run (even without any windowing system)?
This should be exactly what your Rust code is doing (and what it does when run on my Linux machine). The code in your answer, on the other hand, does something else: It uses execv()
to replace the Rust process with nvim. In effect, the process does not immediately stop, and the shell remaind blocked until nvim exits.
After further discussion, we identified the actual problem: The program you are launching is supposed to stay in the foreground, so it can read from the terminal (which background processes can't do on Unix).
There are two ways to achieve this. The first, and easiest, is to wait for the child process before the parent process exits:
use std::process::{Command, ExitStatus};
use std::io::Result;
pub fn execute(exe: &str, args: &[&str]) -> Result<ExitStatus> {
Command::new(exe).args(args).spawn()?.wait()
}
This ensures the processes (parent and child) stay in the foreground, since the shell is waiting for the parent process, so the child process can read from the terminal.
If for some reason you can't afford the parent process to linger on while the child process is running, you need platform-dependent code. On Unix, you can use some syscall from the exec()
familiy to replace the image of the parent process with the image of the child process:
use std::process::Command;
use std::os::unix::process::CommandExt;
use std::io::Error;
pub fn execute(exe: &str, args: &[&str]) -> Error {
Command::new(exe).args(args).exec()
}
The function only returns if there is an error. Otherwise, the process image is replaced by the new image. From the viewpoint of the shell, it's still the same process, so the shell will wait for the command you launched to finish.
The advantages of the second approach seem slim. It does not work on Windows, since Windows does not support exec()
and friends. You will have one less process around while running the command, but the resource usage of that process should be small in practice – it does not use any CPU, and the memory pages can be swapped out if necessary.
Original Answer
From a program A written in rust, I want to start a program B, have A end, and have B normally run just like if it was manually launched from the same shell just after termination of A.
This is more or less what your code is already doing. There are a few differences to a process launched directly from the shell on Unix systems, though:
- The new process will not be included in the shell's job list, so you can't use the shell's job control commands like
bg
andfg
. - The new process will run in the background, and the shell will immediately show a prompt after the Rust programs exits.
This fails because nvim is launched as a child and is killed as soon as the calling program stops.
This is not true, neither for Unix nor for Windows.
How can I write execute so the caller program immediately stops and lets nvim (or another program) properly run (even without any windowing system)?
This should be exactly what your Rust code is doing (and what it does when run on my Linux machine). The code in your answer, on the other hand, does something else: It uses execv()
to replace the Rust process with nvim. In effect, the process does not immediately stop, and the shell remaind blocked until nvim exits.
edited Nov 28 '18 at 15:28
answered Nov 26 '18 at 11:04
Sven MarnachSven Marnach
358k79757700
358k79757700
"and what it does when run on my Linux machine" Did you try with a real terminal program like vim and not just a sleep ? Your explanations are interesting but I don't see how you solve the problem.
– Denys Séguret
Nov 26 '18 at 11:20
@DenysSéguret I don't have "nvim" installed, so I didn't try that, by I triedbash -c 'while true; do echo a; sleep 2; done'
, and it still keeps running in the background.
– Sven Marnach
Nov 26 '18 at 11:48
@DenysSéguret I also suggested a simple solution that behaves similar to your answer in the comments to your answer – specifically, simply wait for the subprocess instead of immediately exiting. I did not include this in this answer, since it is in direct conflict with the requirements in the question (which asks that the caller program exits immediately).
– Sven Marnach
Nov 26 '18 at 12:03
thanks for the answer. An accept or not will only come after some more studies.
– Denys Séguret
Nov 26 '18 at 13:18
@DenysSéguret I adapted the answer to account for the findings in the comments.
– Sven Marnach
Nov 28 '18 at 15:28
|
show 1 more comment
"and what it does when run on my Linux machine" Did you try with a real terminal program like vim and not just a sleep ? Your explanations are interesting but I don't see how you solve the problem.
– Denys Séguret
Nov 26 '18 at 11:20
@DenysSéguret I don't have "nvim" installed, so I didn't try that, by I triedbash -c 'while true; do echo a; sleep 2; done'
, and it still keeps running in the background.
– Sven Marnach
Nov 26 '18 at 11:48
@DenysSéguret I also suggested a simple solution that behaves similar to your answer in the comments to your answer – specifically, simply wait for the subprocess instead of immediately exiting. I did not include this in this answer, since it is in direct conflict with the requirements in the question (which asks that the caller program exits immediately).
– Sven Marnach
Nov 26 '18 at 12:03
thanks for the answer. An accept or not will only come after some more studies.
– Denys Séguret
Nov 26 '18 at 13:18
@DenysSéguret I adapted the answer to account for the findings in the comments.
– Sven Marnach
Nov 28 '18 at 15:28
"and what it does when run on my Linux machine" Did you try with a real terminal program like vim and not just a sleep ? Your explanations are interesting but I don't see how you solve the problem.
– Denys Séguret
Nov 26 '18 at 11:20
"and what it does when run on my Linux machine" Did you try with a real terminal program like vim and not just a sleep ? Your explanations are interesting but I don't see how you solve the problem.
– Denys Séguret
Nov 26 '18 at 11:20
@DenysSéguret I don't have "nvim" installed, so I didn't try that, by I tried
bash -c 'while true; do echo a; sleep 2; done'
, and it still keeps running in the background.– Sven Marnach
Nov 26 '18 at 11:48
@DenysSéguret I don't have "nvim" installed, so I didn't try that, by I tried
bash -c 'while true; do echo a; sleep 2; done'
, and it still keeps running in the background.– Sven Marnach
Nov 26 '18 at 11:48
@DenysSéguret I also suggested a simple solution that behaves similar to your answer in the comments to your answer – specifically, simply wait for the subprocess instead of immediately exiting. I did not include this in this answer, since it is in direct conflict with the requirements in the question (which asks that the caller program exits immediately).
– Sven Marnach
Nov 26 '18 at 12:03
@DenysSéguret I also suggested a simple solution that behaves similar to your answer in the comments to your answer – specifically, simply wait for the subprocess instead of immediately exiting. I did not include this in this answer, since it is in direct conflict with the requirements in the question (which asks that the caller program exits immediately).
– Sven Marnach
Nov 26 '18 at 12:03
thanks for the answer. An accept or not will only come after some more studies.
– Denys Séguret
Nov 26 '18 at 13:18
thanks for the answer. An accept or not will only come after some more studies.
– Denys Séguret
Nov 26 '18 at 13:18
@DenysSéguret I adapted the answer to account for the findings in the comments.
– Sven Marnach
Nov 28 '18 at 15:28
@DenysSéguret I adapted the answer to account for the findings in the comments.
– Sven Marnach
Nov 28 '18 at 15:28
|
show 1 more comment
Here's a working solution on linux, using a wrapping ot the execv
function:
use nix::unistd;
use std::ffi::CString;
pub fn executev(args: &[&str]) {
let mut args: Vec<CString> = args.iter()
.map(|t| CString::new(*t).expect("not a proper CString"))
.collect();
unistd::execv(
&args[0],
&args,
).expect("failed");
}
fn main() {
executev(&["/usr/bin/nvim", "/home/dys/todo.txt"]);
}
Note: This does start another program and quit but be wary that replacing the current process implies you properly closed open resources. If you can accept having your program kept alive, you probably want to wait
as suggested by Sven Marnach.
If this is confirmed to be the right solution, and after confirmation it was already working on Windows, then I'll clean this fast written solution up.
– Denys Séguret
Nov 26 '18 at 10:07
This does something different: theexecv()
function does not return on success, and the current process is replaced by the new process. Note thatCommand::spawn()
also usesexecv()
under the hood, but only afterfork()
ing a child process. I recommend looking into this answer to understand possible root causes of the behaviour you saw.
– Sven Marnach
Nov 26 '18 at 10:19
@SvenMarnach My understanding is that avoidingfork
was the goal
– Denys Séguret
Nov 26 '18 at 10:19
Then simply waiting for the subprocess would also work, and avoid platform-specific code.
– Sven Marnach
Nov 26 '18 at 10:22
add a comment |
Here's a working solution on linux, using a wrapping ot the execv
function:
use nix::unistd;
use std::ffi::CString;
pub fn executev(args: &[&str]) {
let mut args: Vec<CString> = args.iter()
.map(|t| CString::new(*t).expect("not a proper CString"))
.collect();
unistd::execv(
&args[0],
&args,
).expect("failed");
}
fn main() {
executev(&["/usr/bin/nvim", "/home/dys/todo.txt"]);
}
Note: This does start another program and quit but be wary that replacing the current process implies you properly closed open resources. If you can accept having your program kept alive, you probably want to wait
as suggested by Sven Marnach.
If this is confirmed to be the right solution, and after confirmation it was already working on Windows, then I'll clean this fast written solution up.
– Denys Séguret
Nov 26 '18 at 10:07
This does something different: theexecv()
function does not return on success, and the current process is replaced by the new process. Note thatCommand::spawn()
also usesexecv()
under the hood, but only afterfork()
ing a child process. I recommend looking into this answer to understand possible root causes of the behaviour you saw.
– Sven Marnach
Nov 26 '18 at 10:19
@SvenMarnach My understanding is that avoidingfork
was the goal
– Denys Séguret
Nov 26 '18 at 10:19
Then simply waiting for the subprocess would also work, and avoid platform-specific code.
– Sven Marnach
Nov 26 '18 at 10:22
add a comment |
Here's a working solution on linux, using a wrapping ot the execv
function:
use nix::unistd;
use std::ffi::CString;
pub fn executev(args: &[&str]) {
let mut args: Vec<CString> = args.iter()
.map(|t| CString::new(*t).expect("not a proper CString"))
.collect();
unistd::execv(
&args[0],
&args,
).expect("failed");
}
fn main() {
executev(&["/usr/bin/nvim", "/home/dys/todo.txt"]);
}
Note: This does start another program and quit but be wary that replacing the current process implies you properly closed open resources. If you can accept having your program kept alive, you probably want to wait
as suggested by Sven Marnach.
Here's a working solution on linux, using a wrapping ot the execv
function:
use nix::unistd;
use std::ffi::CString;
pub fn executev(args: &[&str]) {
let mut args: Vec<CString> = args.iter()
.map(|t| CString::new(*t).expect("not a proper CString"))
.collect();
unistd::execv(
&args[0],
&args,
).expect("failed");
}
fn main() {
executev(&["/usr/bin/nvim", "/home/dys/todo.txt"]);
}
Note: This does start another program and quit but be wary that replacing the current process implies you properly closed open resources. If you can accept having your program kept alive, you probably want to wait
as suggested by Sven Marnach.
edited Jan 23 at 12:53
answered Nov 26 '18 at 10:06
Denys SéguretDenys Séguret
281k56589605
281k56589605
If this is confirmed to be the right solution, and after confirmation it was already working on Windows, then I'll clean this fast written solution up.
– Denys Séguret
Nov 26 '18 at 10:07
This does something different: theexecv()
function does not return on success, and the current process is replaced by the new process. Note thatCommand::spawn()
also usesexecv()
under the hood, but only afterfork()
ing a child process. I recommend looking into this answer to understand possible root causes of the behaviour you saw.
– Sven Marnach
Nov 26 '18 at 10:19
@SvenMarnach My understanding is that avoidingfork
was the goal
– Denys Séguret
Nov 26 '18 at 10:19
Then simply waiting for the subprocess would also work, and avoid platform-specific code.
– Sven Marnach
Nov 26 '18 at 10:22
add a comment |
If this is confirmed to be the right solution, and after confirmation it was already working on Windows, then I'll clean this fast written solution up.
– Denys Séguret
Nov 26 '18 at 10:07
This does something different: theexecv()
function does not return on success, and the current process is replaced by the new process. Note thatCommand::spawn()
also usesexecv()
under the hood, but only afterfork()
ing a child process. I recommend looking into this answer to understand possible root causes of the behaviour you saw.
– Sven Marnach
Nov 26 '18 at 10:19
@SvenMarnach My understanding is that avoidingfork
was the goal
– Denys Séguret
Nov 26 '18 at 10:19
Then simply waiting for the subprocess would also work, and avoid platform-specific code.
– Sven Marnach
Nov 26 '18 at 10:22
If this is confirmed to be the right solution, and after confirmation it was already working on Windows, then I'll clean this fast written solution up.
– Denys Séguret
Nov 26 '18 at 10:07
If this is confirmed to be the right solution, and after confirmation it was already working on Windows, then I'll clean this fast written solution up.
– Denys Séguret
Nov 26 '18 at 10:07
This does something different: the
execv()
function does not return on success, and the current process is replaced by the new process. Note that Command::spawn()
also uses execv()
under the hood, but only after fork()
ing a child process. I recommend looking into this answer to understand possible root causes of the behaviour you saw.– Sven Marnach
Nov 26 '18 at 10:19
This does something different: the
execv()
function does not return on success, and the current process is replaced by the new process. Note that Command::spawn()
also uses execv()
under the hood, but only after fork()
ing a child process. I recommend looking into this answer to understand possible root causes of the behaviour you saw.– Sven Marnach
Nov 26 '18 at 10:19
@SvenMarnach My understanding is that avoiding
fork
was the goal– Denys Séguret
Nov 26 '18 at 10:19
@SvenMarnach My understanding is that avoiding
fork
was the goal– Denys Séguret
Nov 26 '18 at 10:19
Then simply waiting for the subprocess would also work, and avoid platform-specific code.
– Sven Marnach
Nov 26 '18 at 10:22
Then simply waiting for the subprocess would also work, and avoid platform-specific code.
– Sven Marnach
Nov 26 '18 at 10:22
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53477846%2fstart-another-program-then-quit%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Does Windows really kill all child processes as soon as the parent process dies? It's been two decades since I did software development on Windows, but I don't remember this behaviour.
– Sven Marnach
Nov 26 '18 at 9:35
@SvenMarnach I don't know for Windows as I don't have any box available right now. My requirement is to have it work on windows, linux and macos. I'll remove the OS tags (for a time maybe) to make it clear this isn't a Windows specific question.
– Denys Séguret
Nov 26 '18 at 9:37
I missed there was also a Linux tag. Neither Linux nor Windows kill the child process when the parent process exits.
– Sven Marnach
Nov 26 '18 at 9:46
1
@SvenMarnach because
process::spawn()
is setting up some pipes between parent and child. Have awhile true; echo foo; sleep 1; done
as the child, and you should see the failure.– Florian Margaine
Nov 26 '18 at 11:05
1
Which explains both why an
os.setsid()
in the beginning the process works, and why it's not reproducible withstrace
(stdin is not a pty)– Florian Margaine
Nov 26 '18 at 14:10