1 module ws.thread.loader; 2 3 import 4 core.thread, 5 std.traits, 6 ws.wm, 7 ws.thread.awaiter, 8 ws.log, 9 ws.list, 10 ws.event, 11 ws.io; 12 13 __gshared: 14 15 16 class Loadable { 17 18 enum: size_t { 19 Idle, 20 Loading, 21 Loaded, 22 Error 23 } 24 25 this(){ 26 loadState = Loadable.Idle; 27 onLoaded = new LoadedQueue; 28 } 29 30 void finish(){ 31 synchronized(this){ 32 state = Loaded; 33 } 34 } 35 36 @property size_t loadState(){ 37 synchronized(this) { 38 return state; 39 } 40 } 41 42 @property size_t loadState(size_t s){ 43 synchronized(this){ 44 state = s; 45 if(s == Loaded) 46 onLoaded(); 47 return state; 48 } 49 } 50 51 @property bool loaded(){ 52 synchronized(this) { 53 return state == Loaded; 54 } 55 } 56 57 Loader loader; 58 LoadedQueue onLoaded; 59 60 private: 61 size_t state; 62 63 class LoadedQueue: ws.event.Event!() { 64 void opOpAssign(string op)(void delegate() d) if(op=="~") { 65 if(loaded) 66 d(); 67 else 68 super.opOpAssign!op(d); 69 } 70 } 71 72 } 73 74 alias void delegate() Function; 75 76 77 interface Loader { 78 79 void run(Function); 80 81 int length(); 82 83 } 84 85 86 class LoaderQueue: Loader { 87 88 private List!Function queue; 89 90 this(){ 91 queue = new List!Function; 92 } 93 94 override int length(){ 95 synchronized(this){ 96 return cast(int)queue.length; 97 } 98 } 99 100 override void run(Function fn){ 101 synchronized(this){ 102 queue ~= fn; 103 } 104 } 105 106 void tick(){ 107 if(length){ 108 Function fn; 109 synchronized(this){ 110 fn = queue.popFront(); 111 } 112 fn(); 113 } 114 } 115 116 } 117 118 119 class LoaderThread: LoaderQueue { 120 121 private Thread worker; 122 123 void shutdown(){ 124 synchronized(this) 125 queue = null; 126 } 127 128 this(void delegate() precall){ 129 queue = new List!Function; 130 worker = new Thread({ 131 worker.priority = Thread.PRIORITY_MIN; 132 worker.isDaemon = true; 133 while(worker.isRunning && queue){ 134 try { 135 while(worker && worker.isRunning && queue && !queue.length) 136 worker.sleep(msecs(10)); 137 if(!queue) 138 return; 139 Function cb; 140 synchronized(this) 141 cb = queue.popFront(); 142 precall(); 143 cb(); 144 }catch(Throwable t) 145 Log.error("THREAD ERROR: " ~ t.toString()); 146 } 147 }); 148 worker.start(); 149 } 150 151 }