Skip to content

gvfs-helper-client: clean up server process #756

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
wants to merge 2 commits into
base: vfs-2.49.0
Choose a base branch
from

Conversation

derrickstolee
Copy link

@derrickstolee derrickstolee commented May 23, 2025

On Linux, the following command would cause the terminal to be stuck waiting:

  git fetch origin foobar

The issue would be that the fetch would fail with the error

  fatal: couldn't find remote ref foobar

but the underlying git-gvfs-helper process wouldn't die. The subprocess_exit_handler() method would close its stdin and stdout, but that wouldn't be enough to cause the process to end.

The current approach creates our own atexit() handler by sending a SIGINT signal to the child process. This has worked in my end-to-end test.

Perhaps another approach would be to change the way git-gvfs-helper server gets messages over stdin to better terminate when the pipe closes. However, I debugged to the point that I could see the git-gvfs-helper process waiting on a basic read() from the standard library, so it's not mishandling an EOF signal or anything.

@derrickstolee derrickstolee self-assigned this May 23, 2025
@derrickstolee derrickstolee marked this pull request as ready for review May 23, 2025 19:00
@derrickstolee
Copy link
Author

Promoting to a full PR after trying to explore the option of being better bout stdin closing. In fact, the git-gvfs-helper process is waiting on stdin in the read() method and isn't getting a response. So there's nothing to be done in that direction.

@derrickstolee derrickstolee requested review from dscho and mjcheetham May 23, 2025 19:01
On Linux, the following command would cause the terminal to be stuck
waiting:

  git fetch origin foobar

The issue would be that the fetch would fail with the error

  fatal: couldn't find remote ref foobar

but the underlying git-gvfs-helper process wouldn't die. The
`subprocess_exit_handler()` method would close its stdin and stdout, but
that wouldn't be enough to cause the process to end, even though the
`packet_read_line_gently()` call that is run in `do_sub_cmd__server()`
in a loop should return -1 and the process should the terminate
peacefully.

While it is unclear why this does not happen, there may be other
conditions where the `gvfs-helper` process would not terminate. Let's
ensure that the gvfs-helper-client process cleans up the gvfs-helper
server processes that it spawned upon exit.

Reported-by: Stuart Wilcox Humilde <[email protected]>
Signed-off-by: Derrick Stolee <[email protected]>
Signed-off-by: Johannes Schindelin <[email protected]>
@@ -48,6 +58,8 @@ static int gh_client__start_fn(struct subprocess_entry *subprocess)

struct gh_server__process *entry = (struct gh_server__process *)subprocess;

server_process_pid = subprocess->process.pid;
atexit(cleanup_server_process_on_exit);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While it may be interesting to find out why the process does not finish when stdin closes (looks like the packet_read_line_gently() call that should return -1 does not? Or maybe the problem is that child processes continue to exist as zombie processes on Linux until a waitpid() of their parent process releases them?), an atexit() handler definitely takes care of cleaning up the server process.

However, there may be more than one gvfs-helper process to clean up. @derrickstolee could you test whether b8d292f (pushed to microsoft/git as gvfs-helper-linux-term) addresses the problem you observed, too?

I had to change where the atexit() was registered in order to make sure
things ran at the right place.
@derrickstolee derrickstolee force-pushed the gvfs-helper-linux-term branch from 5d57c6d to 68f5d49 Compare May 27, 2025 13:17
@@ -48,6 +50,8 @@ static int gh_client__start_fn(struct subprocess_entry *subprocess)

struct gh_server__process *entry = (struct gh_server__process *)subprocess;

atexit(stop_gh_server_subprocesses);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should move this all the way into the cmd_main() function, to be 100% sure that it is registered, and registered one time only?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That could work, or I could add a static int registered = 0; into this method. This is definitely on the critical path for starting a process.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I do not understand is: the previous location was in the code path that initializes the hashmap, and the new location is in the gh_client__start_fn() function which is passed as a callback a couple lines further down from the previous location. So how is it possible that it was not called early enough in the previous location but it is early enough in the new location?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was also confused by this, since I specifically traced that the hashing location was being called but somehow wasn't sticking. I'll look into it some more later this week.

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

Successfully merging this pull request may close these issues.

2 participants