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 ShutdownSocket : ClientSocket 47 { 48 Socket pinger; 49 50 this() 51 { 52 auto pair = socketPair(); 53 super(pair[0]); 54 pinger = pair[1]; 55 this.handleReadData = &onReadData; 56 addShutdownHandler(&onShutdown); // for manual shutdown calls 57 this.daemon = true; 58 } 59 60 void ping() 61 { 62 ubyte[] data = [42]; 63 pinger.send(data); 64 } 65 66 void onShutdown() 67 { 68 pinger.close(); 69 } 70 71 void onReadData(ClientSocket socket, Data data) 72 { 73 shutdown(); 74 } 75 } 76 77 void register() 78 { 79 auto socket = new ShutdownSocket(); 80 ae.sys.shutdown.addShutdownHandler(&socket.ping); 81 }