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 module ae.net.shutdown; 21 22 void addShutdownHandler(void delegate() fn) 23 { 24 handlers ~= fn; 25 if (handlers.length == 1) // first 26 register(); 27 } 28 29 /// Calls all registered handlers. 30 void shutdown() 31 { 32 foreach (fn; handlers) 33 fn(); 34 } 35 36 private: 37 38 static import ae.sys.shutdown; 39 import std.socket : socketPair; 40 import ae.net.asockets; 41 import ae.sys.data; 42 43 // Per-thread 44 void delegate()[] handlers; 45 46 final class ShutdownConnection : TcpConnection 47 { 48 Socket pinger; 49 50 this() 51 { 52 auto pair = socketPair(); 53 pair[0].blocking = false; 54 super(pair[0]); 55 pinger = pair[1]; 56 this.handleReadData = &onReadData; 57 addShutdownHandler(&onShutdown); // for manual shutdown calls 58 this.daemon = true; 59 } 60 61 void ping() 62 { 63 ubyte[] data = [42]; 64 pinger.send(data); 65 } 66 67 void onShutdown() 68 { 69 pinger.close(); 70 } 71 72 void onReadData(Data data) 73 { 74 shutdown(); 75 } 76 } 77 78 void register() 79 { 80 auto socket = new ShutdownConnection(); 81 ae.sys.shutdown.addShutdownHandler(&socket.ping); 82 }