1 /** 2 Copyright: 2018 Mark Fisher 3 4 License: 5 Permission is hereby granted, free of charge, to any person obtaining a copy of 6 this software and associated documentation files (the "Software"), to deal in 7 the Software without restriction, including without limitation the rights to 8 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 of the Software, and to permit persons to whom the Software is furnished to do 10 so, subject to the following conditions: 11 12 The above copyright notice and this permission notice shall be included in all 13 copies or substantial portions of the Software. 14 15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 SOFTWARE. 22 **/ 23 module dxx.sys.loader; 24 25 private import std.exception; 26 private import std.experimental.logger; 27 28 private import reloaded : Reloaded, ReloadedCrashReturn; 29 30 private import dxx.constants; 31 private import dxx.util.notify; 32 private import dxx.util.log; 33 34 struct ModuleData 35 { 36 const(RTConstants)* hostRuntime; 37 const(RTConstants)* moduleRuntime; 38 void* modData; 39 } 40 41 class Loader { 42 @property 43 const(string) path; 44 45 shared(ModuleData) moduleData; 46 Reloaded script; 47 48 this(const(string) path,void* data) { 49 debug(Loader) { 50 MsgLog.info("Loader " ~ path); 51 } 52 //this.moduleData.libVersion = packageVersion; 53 this.moduleData.hostRuntime = &RTConstants.runtimeConstants; 54 this.moduleData.modData = cast(shared(void*))data; 55 this.path = path; 56 script = Reloaded(); 57 } 58 void load() { 59 debug(Loader) { 60 sharedLog.info("load " ~ path); 61 } 62 script.load(path, moduleData); 63 mixin ReloadedCrashReturn; 64 } 65 void update() { 66 debug(Loader) { 67 sharedLog.info("update " ~ path); 68 } 69 script.update; 70 } 71 void update(void* data) { 72 debug(Loader) { 73 sharedLog.info("update"); 74 } 75 this.moduleData.modData = cast(shared(void*))data; 76 update; 77 } 78 static auto loadModule(const(string) path,void* data) { 79 debug(Loader) { 80 sharedLog.info("loadModule " ~ path); 81 } 82 auto l = new Loader(path,data); 83 l.load; 84 debug(Loader) { 85 sharedLog.info("loaded " ~ path); 86 } 87 l.validate; 88 return l; 89 } 90 void validate() { 91 debug(Loader) { 92 sharedLog.info("validate " ~ path); 93 sharedLog.info(moduleData.hostRuntime.libVersions); 94 } 95 enforce(moduleData.moduleRuntime); 96 enforce(moduleData.moduleRuntime.checkVersion(RTConstants.constants.semVer)); 97 } 98 } 99 100 final class Module : SyncNotificationSource { 101 struct ModuleEvent { 102 enum Type { 103 Init, 104 Deinit, 105 Load, 106 Unload, 107 Update 108 } 109 Type eventType; 110 shared(Module) mod; 111 }; 112 ModuleData* moduleData; 113 114 private static __gshared shared(Module) INSTANCE; 115 static bool instantiated = false; 116 117 static auto getInstance() { 118 if(!instantiated) { 119 synchronized(Module.classinfo) { 120 if(!INSTANCE) { 121 INSTANCE = new shared(Module); 122 debug(Module) { 123 sharedLog.info("new instance."); 124 } 125 } 126 } 127 instantiated = true; 128 } 129 return INSTANCE; 130 } 131 132 template data(alias T) { 133 //alias data = moduleData.data!T; 134 auto ref shared data() { 135 return cast(T*)moduleData.modData; 136 } 137 } 138 139 private shared this() {} 140 141 private nothrow shared void sendModuleEvent(alias T)() { 142 auto m = ModuleEvent(T,this); 143 this.send!ModuleEvent(&m); 144 } 145 shared void init() { 146 //checkModuleVersion; 147 debug(Module) { sharedLog.info("init"); } 148 sendModuleEvent!(ModuleEvent.Type.Init); 149 } 150 shared void deinit() { 151 debug(Module) { sharedLog.info("deinit"); } 152 sendModuleEvent!(ModuleEvent.Type.Deinit); 153 } 154 shared void load() { 155 debug(Module) { sharedLog.info("load"); } 156 sendModuleEvent!(ModuleEvent.Type.Load); 157 } 158 shared void unload() { 159 debug(Module) { sharedLog.info("unload"); } 160 sendModuleEvent!(ModuleEvent.Type.Unload); 161 } 162 shared void update() { 163 debug(Module) { sharedLog.info("update"); } 164 sendModuleEvent!(ModuleEvent.Type.Update); 165 } 166 } 167 168 169 class ModuleNotificationListener : NotificationListener { 170 override shared void handleNotification(void* t) { 171 Module.ModuleEvent* event = cast(Module.ModuleEvent*)t; 172 debug(Module) { 173 import std.conv; 174 sharedLog.info("Notification:",event.eventType); 175 } 176 final switch(event.eventType) { 177 case Module.ModuleEvent.Type.Init: 178 onInit(event); 179 break; 180 case Module.ModuleEvent.Type.Deinit: 181 onDeinit(event); 182 unregister; 183 break; 184 case Module.ModuleEvent.Type.Load: 185 onLoad(event); 186 break; 187 case Module.ModuleEvent.Type.Unload: 188 onUnload(event); 189 break; 190 case Module.ModuleEvent.Type.Update: 191 onUpdate(event); 192 break; 193 } 194 } 195 shared void onInit(Module.ModuleEvent* event){} 196 shared void onDeinit(Module.ModuleEvent* event){} 197 shared void onLoad(Module.ModuleEvent* event){} 198 shared void onUnload(Module.ModuleEvent* event){} 199 shared void onUpdate(Module.ModuleEvent* event){} 200 void register() { 201 version(DXX_Module) { 202 Module.getInstance.addNotificationListener(cast(shared(NotificationListener))this); 203 } 204 } 205 shared void unregister() { 206 version(DXX_Module) { 207 Module.getInstance.removeNotificationListener(cast(shared(NotificationListener))this); 208 } 209 } 210 } 211 version(DXX_Module) { 212 extern(C): 213 void load( void* userdata ); 214 void unload(void* userdata); 215 void init(void* data); 216 void uninit(void* userdata); 217 void update(); 218 }