如何通过Launch Daemon判断macOS是否正在重启?
判断macOS重启状态(Launch Daemon场景)
对于运行在macOS上的C++编写的Launch Daemon,有几种可靠的方式判断系统是否正在重启/进入收尾阶段:
1. 监听系统级通知
macOS通过CoreFoundation框架提供系统状态变更通知,你可以在Daemon中注册监听com.apple.system.restart或com.apple.system.shutdown通知,这是最直接的触发式检测方式。
示例C++代码:
#include <CoreFoundation/CoreFoundation.h> void restartNotificationCallback(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { // 回调触发时,系统已启动重启流程 CFShow(CFSTR("System is restarting...")); // 在此执行你的收尾逻辑 } int main() { CFNotificationCenterRef center = CFNotificationCenterGetDistributedCenter(); CFNotificationCenterAddObserver( center, NULL, restartNotificationCallback, CFSTR("com.apple.system.restart"), NULL, CFNotificationSuspensionBehaviorDeliverImmediately ); // 维持Daemon运行的事件循环 CFRunLoopRun(); return 0; }
编译提示:需链接CoreFoundation框架,示例命令:g++ -o restart_monitor restart_monitor.cpp -framework CoreFoundation
2. 检查系统关机标志文件
系统进入重启/关机收尾阶段时,会自动创建/var/run/shuttingdown文件。你可以通过两种方式检测该文件:
方式A:轮询检查(简单易实现)
#include <fstream> #include <unistd.h> bool isSystemShuttingDown() { std::ifstream file("/var/run/shuttingdown"); return file.good(); } int main() { while(true) { if(isSystemShuttingDown()) { // 系统已进入重启/关机流程 break; } sleep(1); } return 0; }
方式B:kqueue监听(高效无轮询)
#include <sys/event.h> #include <sys/stat.h> #include <unistd.h> #include <iostream> int main() { int kq = kqueue(); if(kq == -1) { perror("kqueue failed"); return 1; } struct kevent event; EV_SET(&event, AT_FDCWD, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_ONESHOT, NOTE_WRITE | NOTE_ATTRIB, 0, "/var/run/shuttingdown"); int nev = kevent(kq, &event, 1, NULL, 0, NULL); if(nev == -1) { perror("kevent failed"); close(kq); return 1; } // 事件触发说明文件已创建,系统进入收尾阶段 std::cout << "System is entering shutdown/restart phase" << std::endl; close(kq); return 0; }
3. 捕获launchd发送的SIGTERM信号
系统准备重启/关机时,launchd会向所有Daemon发送SIGTERM信号,等待30秒后若进程未退出,会发送SIGKILL强制终止。你可以捕获该信号,再结合前两种方式确认是否为系统重启(避免误判launchd单独重启Daemon的情况)。
示例代码:
#include <signal.h> #include <unistd.h> #include <iostream> volatile sig_atomic_t shutdown_flag = 0; void sigtermHandler(int signum) { shutdown_flag = 1; } int main() { signal(SIGTERM, sigtermHandler); while(!shutdown_flag) { // 正常业务逻辑执行 sleep(1); } // 收到信号后,可进一步验证系统状态 std::cout << "Received SIGTERM, preparing for shutdown/restart" << std::endl; return 0; }
额外注意事项
- Launch Daemon以root权限运行,无需担心访问
/var/run/shuttingdown的权限问题。 - 若需执行长耗时收尾逻辑,可修改Daemon的plist配置文件,通过
ExitTimeOut键延长launchd的等待时间(最长不超过300秒)。 - 系统通知监听需要Daemon维持CFRunLoop运行,若已有自定义事件循环,可直接集成监听逻辑。
内容的提问来源于stack exchange,提问作者c00000fd
相关产品推荐
相关产品推荐

