1 /** 2 * Integration with and wrapper around ae.sys.shutdown 3 * for networked (ae.net.asockets-based) applications. 4 * 5 * Unlike ae.sys.shutdown, the handlers are called from 6 * within the same thread they were registered from - 7 * provided that socketManager.loop() is running in that 8 * thread. 9 * 10 * License: 11 * This Source Code Form is subject to the terms of 12 * the Mozilla Public License, v. 2.0. If a copy of 13 * the MPL was not distributed with this file, You 14 * can obtain one at http://mozilla.org/MPL/2.0/. 15 * 16 * Authors: 17 * Vladimir Panteleev <vladimir@thecybershadow.net> 18 */ 19 20 // TODO: Unify addShutdownHandler under a common API. 21 // The host program should decide which shutdown 22 // driver to use. 23 24 // TODO: Add shuttingDown property 25 26 module ae.net.shutdown; 27 28 void addShutdownHandler(void delegate() fn) 29 { 30 handlers ~= fn; 31 if (handlers.length == 1) // first 32 register(); 33 } 34 35 /// Calls all registered handlers. 36 void shutdown() 37 { 38 foreach (fn; handlers) 39 fn(); 40 } 41 42 private: 43 44 static import ae.sys.shutdown; 45 import std.socket : socketPair; 46 import ae.net.asockets; 47 import ae.sys.data; 48 49 // Per-thread 50 void delegate()[] handlers; 51 52 final class ShutdownConnection : TcpConnection 53 { 54 Socket pinger; 55 56 this() 57 { 58 auto pair = socketPair(); 59 pair[0].blocking = false; 60 super(pair[0]); 61 pinger = pair[1]; 62 this.handleReadData = &onReadData; 63 addShutdownHandler(&onShutdown); // for manual shutdown calls 64 this.daemon = true; 65 } 66 67 void ping() //@nogc 68 { 69 static immutable ubyte[1] data = [42]; 70 pinger.send(data[]); 71 } 72 73 void onShutdown() 74 { 75 pinger.close(); 76 } 77 78 void onReadData(Data data) 79 { 80 shutdown(); 81 } 82 } 83 84 void register() 85 { 86 auto socket = new ShutdownConnection(); 87 ae.sys.shutdown.addShutdownHandler(&socket.ping); 88 }