Well, there are some pretty severe restrictions on the type of code you can put into signal handlers. Only atomic operations are allowed. And, in my experience, almost all applications react appropriately to signals.
>Well, there are some pretty severe restrictions on the type of code you can put into signal handlers.
Err... Maybe I'm missing something but I don't believe that's the case. There's a lot of things that you shouldn't do inside of a signal handler that will exhibit undefined behavior, but it's not like the kernel puts any restrictions on what the application can do inside of a signal handler. If an application wants to make SIGHUP just call whatever existing application exit logic they already have, they can. It's a terrible idea because if the application was signalled in the middle of some library call then it's anyone's guess as to whether or not it's just going to crash but that doesn't mean that you can't do it.
I think you're underestimating the difficulty of gracefully shutting down an application in a signal handler. If it's waiting for the application to finish some operation it's stuck in it'll just do the exact same thing as using nohup and there's no way to know that outside of the application.
If an application is handling SIGHUP then it presumably intends to continue running. If it used systemd-run instead, it could still get into a bad state at any point thereafter and you have the same problem. Even using a watchdog couldn't fix every buggy application, because there are ways for an application to crash or misbehave yet continue to send the watchdog notification. We still haven't solved the halting problem.
Meanwhile if the process isn't handling SIGHUP then there is little chance of undefined behavior in the default handler, which merely terminates the process immediately.
>If an application is handling SIGHUP then it presumably intends to continue running.
That's not correct, for stuff running in the user's scope more often than not a SIGHUP handler is just to gracefully exit the application. I.E. close any open files, finish any writes in process, etc.
But also, you don't know what the SIGHUP handler does to begin with. That's the crux of the problem. Outside of the process the SIGHUP handler is just a black box.
>If it used systemd-run instead, it could still get into a bad state at any point thereafter and you have the same problem.
No, if it was started with systemd-run there's no SIGHUP sent to it in the first place. Reaping applications that won't close in the user scope isn't about preventing them from breaking in the first place, it's just sweeping up the broken pieces so that it doesn't break the next user scope because it's still holding some exclusive lock on something.
It's like putting the user session into its own container. It doesn't fix anything, it just keeps the breakage contained to the user's scope so that when you log out, it really does shut down that "container".
> That's not correct, for stuff running in the user's scope more often than not a SIGHUP handler is just to gracefully exit the application. I.E. close any open files, finish any writes in process, etc.
That's essentially the same thing, and the application would have to do something similar to protect itself.
Suppose the user would lose data if the application doesn't exit gracefully, but this may take a variable amount of time depending on how much unsaved data there is, current load on the machine, etc. So it handles SIGHUP, continues running to save its state, but hasn't finished before systemd kills it.
To prevent this it would have to use systemd-run to preserve itself long enough to finish saving its state, and we're back to square one again. Or it doesn't do that and the user loses data.
When they work, sure. And when they don’t the user is wondering why his laptop is playing sounds when she’s logged out. Systemd’s solution is the right one from technical POV. No need to hope applications cooperate when you can just ask the kernel to make sure they do.