1 /// Mecca main entrypoint 2 module mecca.runtime.main; 3 4 // Licensed under the Boost license. Full copyright information in the AUTHORS file 5 6 import std.stdio; 7 import std..string; 8 import mecca.reactor: theReactor; 9 import mecca.runtime.services; 10 11 12 struct ServiceManager { 13 bool isRunning; 14 string[] args; 15 private string[] _serviceStack; 16 private string[] _orderOfInitialization; 17 string[] servicesToInit; 18 19 void main(string[] args) { 20 assert (!isRunning); 21 isRunning = true; 22 scope(exit) isRunning = false; 23 this.args = args; 24 25 scope(exit) runAtExitCallbacks(); 26 27 theReactor.setup(); 28 scope(success) theReactor.teardown(); 29 30 setupServices(); 31 scope(success) teardownServices(); 32 33 // this is the mainloop 34 theReactor.start(); 35 } 36 37 version(unittest) void utMain(string[] args, string[] servicesToInit = null) { 38 this.servicesToInit = servicesToInit; 39 main(args); 40 } 41 42 private void _recursiveSetup(string name) { 43 auto svc = &_registeredServices[name]; 44 45 final switch (svc.state) with (ServiceInterface.State) { 46 case DOWN: 47 _serviceStack ~= name; 48 scope(exit) _serviceStack.length--; 49 50 svc.state = SETUP; 51 foreach(depName; svc.deps) { 52 _recursiveSetup(depName); 53 } 54 if (svc.setup()) { 55 _orderOfInitialization ~= name; 56 svc.state = UP; 57 } 58 else { 59 svc.state = DISABLED; 60 } 61 break; 62 63 case SETUP: 64 assert (false, "Cycle detected: %s".format(_serviceStack)); 65 66 case UP: 67 break; 68 69 case DISABLED: 70 if (_serviceStack.length == 0) { 71 // invoked from root, just skip 72 } 73 else { 74 assert (false, "Service %s requires disabled service %s (%s)".format(_serviceStack[$-1], name)); 75 } 76 break; 77 78 case TEARDOWN: 79 assert (false, "Teardown during setup: %s".format(_serviceStack)); 80 } 81 } 82 83 private void setupServices() { 84 _orderOfInitialization.length = 0; 85 _serviceStack.length = 0; 86 foreach(_, ref svc; _registeredServices) { 87 svc.state = ServiceInterface.State.DOWN; 88 } 89 scope(exit) servicesToInit = null; 90 if (servicesToInit is null) { 91 servicesToInit = _registeredServices.keys; 92 } 93 foreach(name; servicesToInit) { 94 assert (_serviceStack.length == 0); 95 _recursiveSetup(name); 96 assert (_serviceStack.length == 0); 97 } 98 } 99 100 private void teardownServices() { 101 foreach_reverse(name; _orderOfInitialization) { 102 auto svc = &_registeredServices[name]; 103 assert (svc.state == ServiceInterface.State.UP); 104 svc.teardown(); 105 svc.state = ServiceInterface.State.DOWN; 106 } 107 _orderOfInitialization.length = 0; 108 } 109 110 public void stop() { 111 // graceful termination 112 //theReactor.stop(); -- this asserts on a context switch while in a critical section 113 import mecca.lib.time: Timeout; 114 115 static void stopWrapper() { 116 theReactor.stop(); 117 } 118 119 theReactor.registerTimer(Timeout.elapsed, &stopWrapper); 120 } 121 } 122 123 __gshared ServiceManager serviceManager; 124 125 /** 126 * main entrance function for the mecca reactor 127 */ 128 int meccaMain(string[] argv) { 129 serviceManager.main(argv); 130 return 0; 131 }