libfuse / libfuse

The reference implementation of the Linux FUSE (Filesystem in Userspace) interface
Other
5.31k stars 1.14k forks source link

Exiting on signal receipt may take indefinitely long #997

Open Nikratio opened 3 months ago

Nikratio commented 3 months ago

Currently, the default signal handler just sets an exit flag. However, worker threads only terminate when they next check check this flag, which at least sometimes is only when the next request from the kernel is received (which may take indefinitely long). We should find a way to make this work in bounded time.

I remember this working in the past without the need to wait for the next kernel request, but at least on my systems this is no longer working.

The way I would expect it to work is that when the signal is received, the pending read syscall returns with EINT, and the thread checks the flag before re-trying the system call. But clearly that is (no longer?) the case.

I'm not sure what a better solution would be. Perhaps have a separate thread that is woken by the signal handler, and have that thread somehow make the other threads terminate (maybe by using pthread_cancel or accessing the mountpoint?).

bsbernd commented 3 months ago

Hi Nikolaus, I don't think we should access the mount point - with bind mounts and umount of the original mount point might not even be valid anymore. And for me pthread_cancel sounds also a bit weird, why not pthread_kill(thread, SIGHUP) (untested, but I think SIGHUP should work)?

Nikratio commented 3 months ago

I haven't thought too much about possible solutions. If pthread_kill works, that's probably best. I'm a bit wary because I still don't understand why this stopped working / why there isn't at least one thread that returns with EINTR, so I'm not 100% confident that pthread_kill will work either. We'll also have to install per-thread signal handlers to avoid an infinite loop, right?

From pthread_kill(3):

  Signal dispositions are process-wide: if a signal handler is installed, the handler will be
  invoked in the thread thread, but if the disposition of the signal is  "stop",  "continue",
  or "terminate", this action will affect the whole process.
bsbernd commented 3 months ago

Personally I don't have that issue - I typically kill passthrough-hp with ctrl-c (SIGINT) and it works fine. The issue I have is that fuse_session_exit() is just setting the flag, but is not waking up threads - from my point of view that needs to get primarily fixed.

bsbernd commented 3 months ago

And avoiding recursive action - yeah, reset to default the the signal handlers before waking up the other threads.

Nikratio commented 3 months ago

Personally I don't have that issue - I typically kill passthrough-hp with ctrl-c (SIGINT) and it works fine.

Interesting. This is exactly what I'm testing with, and which hangs for me.

The issue I have is that fuse_session_exit() is just setting the flag, but is not waking up threads - from my point of view that needs to get primarily fixed.

...but now I'm confused. I thought when you say it "works fine", it means it exits immediately without the need for something else to wake up the threads?

bsbernd commented 3 months ago

What I mean with fuse_session_exit() is that I sometimes have some bugs somewhere in branch and then want to exit without a signal, but that fuse_session_exit function just sets the flag without sending signals.