1 /** 2 * Application shutdown control (with SIGTERM handling). 3 * Different from atexit in that it controls initiation 4 * of graceful shutdown, as opposed to cleanup actions 5 * that are done as part of the shutdown process. 6 * 7 * Note: thread safety of this module is questionable. 8 * Use ae.net.shutdown for networked applications. 9 * TODO: transition to thread-safe centralized event loop. 10 * 11 * License: 12 * This Source Code Form is subject to the terms of 13 * the Mozilla Public License, v. 2.0. If a copy of 14 * the MPL was not distributed with this file, You 15 * can obtain one at http://mozilla.org/MPL/2.0/. 16 * 17 * Authors: 18 * Vladimir Panteleev <vladimir@thecybershadow.net> 19 */ 20 21 module ae.sys.shutdown; 22 23 /// Warning: the delegate may be called in an arbitrary thread. 24 void addShutdownHandler(void delegate() fn) 25 { 26 if (handlers.length == 0) 27 register(); 28 handlers ~= fn; 29 } 30 31 /// Calls all registered handlers. 32 void shutdown() 33 { 34 foreach (fn; handlers) 35 fn(); 36 } 37 38 private: 39 40 import core.thread; 41 42 void syncShutdown() nothrow @system 43 { 44 try 45 { 46 thread_suspendAll(); 47 scope(exit) thread_resumeAll(); 48 shutdown(); 49 } 50 catch (Throwable e) 51 { 52 import core.stdc.stdio; 53 string s = e.msg; 54 fprintf(stderr, "Unhandled error while shutting down:\r\n%.*s", s.length, s.ptr); 55 } 56 } 57 58 // http://d.puremagic.com/issues/show_bug.cgi?id=7016 59 version(Posix) 60 import ae.sys.signals; 61 else 62 version(Windows) 63 import core.sys.windows.windows; 64 65 void register() 66 { 67 version(Posix) 68 { 69 addSignalHandler(SIGTERM, { syncShutdown(); }); 70 addSignalHandler(SIGINT , { syncShutdown(); }); 71 } 72 else 73 version(Windows) 74 { 75 static shared bool closing = false; 76 77 static void win32write(string msg) nothrow 78 { 79 DWORD written; 80 WriteConsoleA(GetStdHandle(STD_ERROR_HANDLE), msg.ptr, cast(uint)msg.length, &written, null); 81 } 82 83 extern(Windows) 84 static BOOL handlerRoutine(DWORD dwCtrlType) nothrow 85 { 86 if (!closing) 87 { 88 closing = true; 89 win32write("Shutdown event received, shutting down.\r\n"); 90 91 try 92 { 93 thread_attachThis(); 94 syncShutdown(); 95 thread_detachThis(); 96 97 return TRUE; 98 } 99 catch (Throwable e) 100 { 101 win32write("Unhandled error while shutting down:\r\n"); 102 win32write(e.msg); 103 } 104 } 105 return FALSE; 106 } 107 108 // https://issues.dlang.org/show_bug.cgi?id=12710 109 SetConsoleCtrlHandler(cast(PHANDLER_ROUTINE)&handlerRoutine, TRUE); 110 } 111 } 112 113 shared void delegate()[] handlers;