Skip to content

Consider execv for uv run on Unix #3095

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
zanieb opened this issue Apr 17, 2024 · 15 comments
Open

Consider execv for uv run on Unix #3095

zanieb opened this issue Apr 17, 2024 · 15 comments
Labels
enhancement New feature or improvement to existing functionality

Comments

@zanieb
Copy link
Member

zanieb commented Apr 17, 2024

See #3074 (comment)

@zanieb zanieb self-assigned this Apr 17, 2024
@zanieb zanieb added the enhancement New feature or improvement to existing functionality label Apr 17, 2024
@bluss
Copy link
Contributor

bluss commented Apr 21, 2024

Edit: The below concern has found other solutions since then, and is not really relevant.

For the https://github.com/bluss/pyproject-local-kernel usecase (sorry if this is boring), spawn vs exec would make a difference on Linux in terms of how a jupyter notebook is kernel is launched.

jupyter lab launches my python script -> launches uv run -> launches ipykernel.

My script already handles forwarding posix signals to the child (first arrow). If you use exec, the second arrow disappears and posix signals are forwarded to the ipykernel which is useful, in fact the ipykernel doesn't want to start correctly if it doesn't have that signal path. I think exec is generally what you'd want to do. I didn't run into this with rye run, because it uses exec on Linux.

I could configure my kernel with interrupt_mode=message (instead of default signal) to make this issue disappear, but maybe that shouldn't be needed. (Edit, no interrupt_mode=message is only fully supported on Linux, not on Windows, so this is not a great option).

@bluss
Copy link
Contributor

bluss commented Jul 21, 2024

Is this still possible, how does the ephemeral venv cleanup work? Is it using a scope based cleanup. I'll file another issue that's related to ipykernel, and maybe we'll find a good solution.

@zanieb
Copy link
Member Author

zanieb commented Jul 21, 2024

It is not clear how we'd clean up the ephemeral environment, that's a good question.

@charliermarsh
Copy link
Member

It runs on Drop.

@bluss
Copy link
Contributor

bluss commented Jul 24, 2024

The pyproject-local-kernel usecase seems to work perfectly on Linux now after the #5257 fix I think 🤩. Probably should carry over to windows too. Thanks for the help with this 🙂

uv run --with ipykernel is perfect for the notebook use case, it's very smooth.

@charliermarsh
Copy link
Member

Awesome. I did test on my Windows machine and it worked as expected for me, so hopefully good there too...

@zanieb
Copy link
Member Author

zanieb commented Oct 4, 2024

When you execv is nothing dropped until the process exits? I'm quite naive as to how that is handled. cc @BurntSushi

@BurntSushi
Copy link
Member

Basically, you can think of execv (and related functions) as like a std::process::exit. It can be inserted anywhere in your program, and it will unceremoniously stop executing the current program. Destructors are not guaranteed to run.

So to make this work here, we'd probably want to bubble some instruction to "run this exec command" to main in a way that everything else goes out of scope and gets dropped. Otherwise, you'll not just have things like an ephemeral environment hanging around, but all the various allocations and file descriptors won't get dropped either (they will eventually by the OS once the replacing process terminates, AIUI).

Also, we are very likely already using exec. I think what is meant here is that we do not want to fork before an exec. Or stated at a higher level, we want to replace the current process with the thing we want to run.

@zanieb
Copy link
Member Author

zanieb commented Oct 7, 2024

Hm.. thanks for the details.

I think that supports my concern that we have resources e.g., the ephemeral environment, that can't be removed until the spawned process finishes which makes it hard to entirely cede control?

@BurntSushi
Copy link
Member

Oh I see, yes, hmmm. That is a conundrum. I am reminded of a trick where you can unlink a file but keep an open file descriptor to it, which at least on Unix, will keep the file around until the descriptor is closed. But, 1) I'm not sure how to make that scale to an entire directory tree and 2) I'm not sure if that concept works on Windows. Failing some trick like that, I'd guess the only way to do this is to introduce some kind of garbage collection? Not sure.

@charliermarsh
Copy link
Member

Yeah I think the general form of the problem here is that execv won't run Drop, but it we Drop things before deferring to execv, we'll remove things we need like temporary directories.

@zanieb
Copy link
Member Author

zanieb commented Oct 8, 2024

This feels like a pretty significant blocker for switching to execv – I think we might need to prioritize passing signals to the child in a robust manner?

@charliermarsh
Copy link
Member

Yeah, agreed.

@zanieb zanieb removed their assignment Feb 18, 2025
@zanieb
Copy link
Member Author

zanieb commented Feb 18, 2025

Signal handling was improved #11009

I think the Drop question remains a blocker. I'll leave this open for future consideration though.

@zanieb
Copy link
Member Author

zanieb commented Apr 21, 2025

More signal handling changes in #13017

zanieb added a commit that referenced this issue Apr 21, 2025
As I suspected quite some time ago
(#6738 (comment)),
it's problematic that we don't handle _every_ signal here. This PR adds
handling for all of the Unix signals except `SIGCHLD`, `SIGIO`, and
`SIGPOLL` which seem incorrect to forward. Also notable, we _cannot_
handle `SIGKILL` so if someone sends that to the PID instead of the
PGID, they will leave dangling subprocesses.

Instead, we could use `exec` and avoid this handling. However, we'd lose
the ability to add nice error message on failure (e.g., as someone is
trying to add in #12201) and, more
critically, we'd need to figure out how to clean up resources properly
(i.e., temporary directories) which currently happens on `Drop`. In the
long-term, we'll probably want an option to use `exec` — but we'll need
to figure out when to clean up resources or accept that they will
dangle. This was last discussed in
#3095 — discussion on that
approach should continue there.

A note on the implementation: I spent time time trying to write the
handler using a tokio stream, so we could dynamically iterate over a
list of signals instead of copy/pasting the implementation — I couldn't
get it to work though and it didn't seem critical.

Closes #12830
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or improvement to existing functionality
Projects
None yet
Development

No branches or pull requests

4 participants