Skip to content
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

How to deal with signals when using git2-rs? #908

Open
srhb opened this issue Jan 6, 2023 · 4 comments
Open

How to deal with signals when using git2-rs? #908

srhb opened this issue Jan 6, 2023 · 4 comments

Comments

@srhb
Copy link

srhb commented Jan 6, 2023

Warning: If you run the test program, it will pollute your $TMP dir. Beware!

I wrote a test program to explain my question.

https://github.com/srhb/git2-rs-debug-eintr/blob/main/src/main.rs
It can be run with a ssh git repo as its first argument and assumes a private key at ~/.ssh/id_rsa:

> cargo run -- sarah@localhost:testrepo

The program does two things continuously:

  1. continuously clones the repo to a fresh temporary directory
  2. runs true in a tight loop via async-process

This causes a problem with libssh2 (via git2-rs)

Copy/paste of explanatory comment from my test program:

With it (async-process), you'll get lots of errors a la:

```
error: Failed to retrieve list of SSH authentication methods: Error waiting on socket; class=Ssh (23); code=Auth (-16)
error: SSH could not read data: Error waiting on socket; class=Ssh (23)
error: Failed to open SSH channel: Error waiting on socket; class=Ssh (23)
```

(They key error here is: "Error waiting on socket")

I believe what's happening is this:

async-process (Command::new()) works internally by dealing with SIGCHLD etc.
for process reaping. In other words, _this_ process starts receiving a bunch
of SIGCHLD signals.

This causes the following `poll()` (or `select()`, depending on
implementation)

https://github.com/libssh2/libssh2/blob/master/src/session.c#L645

... to return with errno EINTR on each signal received:

https://github.com/libssh2/libssh2/blob/master/src/session.c#L678

... which is the error that ultimately surfaces in git2-rs.

The question then is: How does one even use git2-rs from within a process
that receives signals periodically? If we simply mask it out, whomever
depends on the signal gets broken. If not, we'll have to deal with the error
all the way up here, even though we should really have been able to simply
restart a simple poll on eg. a recv() on socket. Any help or thoughts
appreciated!
@kim
Copy link
Contributor

kim commented Jan 12, 2023

Do you have to use async, or is this just for illustration?

@srhb
Copy link
Author

srhb commented Jan 26, 2023

It's mostly an example. The "real" program is an API served over HTTP, which responds to various commands, updates repos from upstream based on those commands, and spawns (ephemeral) child processes to operate on those repos. SIGCHLD is more or less unavoidable, but the rest could possibly be restructured, though I'm not quite sure how.

@kim
Copy link
Contributor

kim commented Jan 26, 2023

I might be wrong, but I don't think there really is a way to work around this, except by avoiding this SIGCHLD business altogether (run the normal std::process::Command). Or, perhaps by registering a custom transport which would give you more control over IO / syscalls.

@haydenflinner
Copy link

You could also try using Tokio's command which as far as I have run into, doesn't work by polluting your main process with signals. Or spawn a subprocess to isolate this mechanism away from the rest of your code. You will find a lot of things don't play well with signals, not just this library. One approach is to set SA_RESTART, or wrap all of your syscalls in a retry for EINTR. https://www.gnu.org/software/libc/manual/html_node/Interrupted-Primitives.html

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants