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