ghostty icon indicating copy to clipboard operation
ghostty copied to clipboard

fix: always wait on open command to avoid defunct processes

Open pbui opened this issue 9 months ago • 6 comments

Without waiting on the xdg-open process on linux/freebsd, we end up with a defunct (zombie) process after each time we open a URL.

For example, after click on two URLs in a ghostty, here is the output of ps ux | grep xdg-open:

pbui      8364  0.0  0.0      0     0 tty7     Z+   05:03   0:00 [xdg-open] <defunct>
pbui      8453  0.0  0.0      0     0 tty7     Z+   05:03   0:00 [xdg-open] <defunct>

Perhaps we should revisit 695bc30, which removed the wait in the first place. On my machine running Alpine Linux 3.22, xdg-open does not stay alive and finishes immediately, thus making it safe to call wait (and not block). This is also the case on my other machine running Ubuntu 24.04: xdg-open launches the URL in a browser and terminates immediately.

Either way, this process must be waited upon eventually. Otherwise, we will accumulate a collection of defunct processes until the terminal itself terminates.

pbui avatar Jun 23 '25 09:06 pbui

cc @gpanders who did this originally, the question I have is why does your xdg-open block? Mine also appears to not block, but I could be holding it wrong. Worst case we could spin up a thread that sits on wait.

mitchellh avatar Jun 23 '25 11:06 mitchellh

I think a more complete solution would be #5988 which runs xdg-open in a background thread as some versions of xdg-open block waiting for completion instead of quickly exiting.

jcollie avatar Jun 23 '25 13:06 jcollie

cc @gpanders who did this originally, the question I have is why does your xdg-open block? Mine also appears to not block, but I could be holding it wrong. Worst case we could spin up a thread that sits on wait.

I just tried this again and xdg-open no longer blocks for me either.

It's possible this was a quirk/bug with an older version of xdg-open? At the time I wrote that PR I was using Ubuntu 22.04, but am now using Ubuntu 24.04.

For what it's worth, a quick search shows a lot of people asking about xdg-open's blocking behavior:

https://stackoverflow.com/questions/77333067/why-does-xdg-open-block-on-command-line

https://bbs.archlinux.org/viewtopic.php?id=259672

It's probably safest to assume that xdg-open can block and reap the child process asynchronously.

gpanders avatar Jun 23 '25 15:06 gpanders

It's probably safest to assume that xdg-open can block and reap the child process asynchronously.

Agreed. To keep things simple I'd just move the wait call to a thread, the spawn is already async no matter what and it simplifies memory lifetimes to an integer value (pid).

mitchellh avatar Jun 23 '25 15:06 mitchellh

Ok, I took a stab at moving the wait to a detached thread. After some quick testing, it seems to wait properly and there are no defunct processes after clicking on a URL.

That said, this is my first time programming in Zig, so I'm not sure if I managed the lifetimes properly (struggled a bit with getting the types to the _openWait thread function correct).

pbui avatar Jun 23 '25 16:06 pbui

I discovered that there was a race condition in a previous version where I was passing exe as a pointer to the thread function. Since this was on the stack, it was possible that it would get deallocated before the thread could run.

To fix this, I changed the code to pass exe by value and then fixed a compiler error by doing a @constCast on the struct when calling wait.

pbui avatar Jun 23 '25 21:06 pbui

Thanks, this is looking good to me. I made some touchups, mostly style. I think functionally the most important is we must use log.warn and not log.err. log.err is for fatal messages.

mitchellh avatar Jun 24 '25 11:06 mitchellh