1 module reloaded.reloaded; 2 3 import reloaded.setjmp; 4 5 public: 6 7 mixin template ReloadedCrashReturn() 8 { 9 import core.stdc.signal; 10 import reloaded.setjmp : setjmp, jmp_buf; 11 12 static jmp_buf __crash_return_buffer; 13 14 extern(C) @nogc nothrow 15 static void __crash_return_handler(int code) 16 { 17 import core.stdc.stdio; 18 import core.stdc.signal; 19 import reloaded.setjmp : longjmp; 20 21 enum ERROR_MSG = 22 [ 23 SIGABRT : "Signal Abort", 24 SIGFPE : "Signal Floating-Point Exception", 25 SIGILL : "Signal Illegal Instruction", 26 SIGINT : "Signal Interrupt", 27 SIGSEGV : "Signal Segmentation Violation", 28 SIGTERM : "Signal Terminate", 29 ]; 30 31 printf("ReloadeD Client crashed with signal :"); 32 33 switch(code) 34 { 35 case SIGABRT: printf("Abort"); break; 36 case SIGFPE: printf("Floating-Point Exception"); break; 37 case SIGILL: printf("Illegal Instruction"); break; 38 case SIGINT: printf("Interrupt"); break; 39 case SIGSEGV: printf("Segmentation Violation"); break; 40 case SIGTERM: printf("Terminate"); break; 41 default: 42 printf("Unknown (%d) ", code); 43 break; 44 } 45 46 printf("\n",); 47 longjmp(__crash_return_buffer, 1); 48 } 49 version(Windows) 50 { 51 auto __crash_return_code = setjmp(__crash_return_buffer, null); 52 } 53 else 54 { 55 auto __crash_return_code = setjmp(__crash_return_buffer); 56 } 57 auto __crash_return_noop = {signal(SIGSEGV, &__crash_return_handler ); return false; }(); 58 } 59 60 struct Reloaded 61 { 62 import derelict.util.sharedlib : SharedLib; 63 import fswatch : FileWatch, FileChangeEventType; 64 import std.typecons : Flag, Yes, No; 65 66 static void noop(){} 67 68 alias extern_init = void function(void*); 69 alias extern_uninit = void function(void*); 70 alias extern_load = void function(void*); 71 alias extern_unload = void function(void*); 72 alias extern_update = void function(); 73 74 SharedLib lib; 75 extern_update update_fun; 76 void* userdata; 77 FileWatch fw; 78 79 string lib_path; 80 string[2] lib_swaps; 81 bool lib_swaps_v = 0; 82 83 84 85 this(T)(string lib_path, auto ref T userdata) 86 { 87 load( lib_path, userdata ); 88 } 89 90 void load(T)(string lib_path, auto ref T userdata) 91 { 92 import std.path : stripExtension, extension; 93 94 this.lib_path = lib_path; 95 this.userdata = cast(void*)&userdata; 96 fw = FileWatch(lib_path); 97 98 auto base = lib_path.stripExtension; 99 auto ext = lib_path.extension; 100 101 lib_swaps[0] = base ~ "0" ~ ext; 102 lib_swaps[1] = base ~ "1" ~ ext; 103 104 loadLib!(Yes.FirstTime); 105 } 106 107 void update() 108 { 109 foreach (event; fw.getEvents()) 110 { 111 if (event.type == FileChangeEventType.create || event.type == FileChangeEventType.modify ) 112 { 113 loadLib!(No.FirstTime); 114 break; 115 } 116 } 117 update_fun(); 118 } 119 120 ~this() 121 { 122 auto unload = getLibFun!"unload"; 123 if(unload) 124 unload(userdata); 125 126 auto uninit = getLibFun!"uninit"; 127 if(uninit) 128 uninit(userdata); 129 } 130 131 private: 132 133 auto getLibFun(string fun, Args... )(auto ref Args args) 134 { 135 mixin("return cast(extern_" ~ fun ~ " )lib.loadSymbol(fun, false);"); 136 } 137 138 void waitFileUnlock() 139 { 140 import core.stdc.stdio : FILE, fopen, fclose; 141 142 FILE* fp; 143 while( (fp = fopen(lib_path.ptr, "r" )) == null ){} 144 fclose(fp); 145 } 146 147 148 void loadLib(Flag!"FirstTime" first_time = No.FirstTime)() 149 { 150 import std.file : copy, exists, remove; 151 import std.stdio : printf = writefln; 152 153 if( !lib_path.exists ) 154 { 155 printf("Lib not found :'%s'", lib_path ); 156 return; 157 } 158 159 waitFileUnlock; 160 161 auto lib_tmp = lib_swaps[cast(size_t)lib_swaps_v]; 162 copy(lib_path, lib_tmp); 163 164 if( lib.isLoaded ) 165 { 166 lib.unload; 167 //DTOR unload; 168 } 169 170 lib.load( [lib_tmp] ); 171 172 //TEST ALL FUNCTIONS 173 174 static foreach(fun ; ["init", "uninit", "load", "unload", "update"]) 175 { 176 if( getLibFun!fun() == null ) 177 { 178 printf("Lib failed to load extern function: %s -> '%s'", fun, mixin( "extern_"~fun~".stringof" )); 179 } 180 } 181 182 lib_swaps_v = !lib_swaps_v; 183 184 update_fun = getLibFun!"update"; 185 if( !update_fun ) 186 update_fun = &noop; 187 188 static if(first_time) 189 { 190 auto init = getLibFun!"init"; 191 if(init) 192 init(userdata); 193 194 auto load = getLibFun!"load"; 195 if(load) 196 load(userdata); 197 } 198 else 199 { 200 auto unload = getLibFun!"unload"; 201 if(unload) 202 unload( userdata ); 203 204 auto load = getLibFun!"load"; 205 if(load) 206 load( userdata ); 207 208 } 209 } 210 }