On Thu, 24 Mar 2011, Jerry Krinock said:
On 2011 Mar 24, at 02:16, Quinn The Eskimo! wrote: On 24 Mar 2011, at 01:51, Antoine Missout wrote:
What is the proper answer to the original question, ie getting the shutdown event in a global context daemon ?
I don't have a good answer.
Well, I think my original question is to getting the shutdown event in a *user* context daemon. The only notification I've been able to receive is SIGTERM. And further testing shows that whatever sends the SIGTERMs to processes during shutdown will *block* sending further SIGTERMs when an app doesn't terminate. I say this because, in my most recent test, this happened: min:sec 00:00 Confirmed by clicking the "Shut Down" button 00:03 Got the first "dirty document" warning from an app. I did not respond. 00:30-00:40 Clicked "Don't Save" in this dialog, and in two others which appeared from two other apps 00:51 My process received SIGTERM ("Finally!!") 01:11 My process was killed So, this is quite worse than I had thought. Let me restate my question, in case this helps: I want my non-GUI command-line program which is launched by user-level launchd to know as early as possible when shutdown is occuring, preferably (for example, if initiated by the console user) immediately when the user clicks the "Shut Down" button in the confirmation dialog, and, at least, before SIGTERMs start getting sent to processes. NSWorkspaceWillPowerOffNotification doesn't work, and IORegisterForSystemPower() doesn't work. Alternatively, I'd like an API to which I could ask before beginning a long task, "Is shutdown in progress?"
The reason you don't get SIGTERM notifications earlier is that the OS assumes that your agent is intended to support applications, which means that applications may be talking to your daemon, and thus terminating it before the last app quits would just cause it to get started right back up again.
The reason that IORegisterForSystemPower() won't work is that it is triggered by the kernel teardown, which can't occur until after user space is torn down (including daemons and agents).
It looks to me like what we have here is something of a layering violation. As a general rule, only foreground (GUI) tasks should delay shutdown or logout significantly. Doing it in a background task makes for a bad user experience, leaving the user sitting there wondering "Why is my computer not restarting? Is it broken? Do I need to hold down the power button?" This tends to result in your daemon getting killed by manual user intervention even if the OS didn't do it for him/her. :-)
I can think of only two ways to solve this problem:
* Spawn a full-blown launch-services-run helper app that receives NSWorkspaceWillPowerOffNotification notifications and, upon receiving one, displays a dialog box and then refuses to quit until your daemon finishes the long-running operation. Apparently, this application must not use LSUIElement or LSBackgroundOnly because these keys prevent you from getting the notification you need.
* Modify your agent so that it can handle premature termination of long operations, either through a rollback system or through saving state and quitting, then picking up where you left off on the next reboot.
Either way, you should never attempt to delay logout or shutdown for arbitrary periods of time from any code that can't display UI. It's too confusing and unnerving for the user.
David
|