Changeset 367
- Timestamp:
- 06/25/08 10:45:35 (5 months ago)
- Files:
-
- trunk/tools/dsss.conf (modified) (1 diff)
- trunk/tools/tools/behave_as.d (modified) (1 diff)
- trunk/tools/tools/downloader.d (modified) (1 diff)
- trunk/tools/tools/mersenne.d (modified) (2 diffs)
- trunk/tools/tools/stackthreads.d (modified) (1 diff)
- trunk/tools/tools/stackthreads_impl.d (modified) (8 diffs)
- trunk/tools/tools/threads.d (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/tools/dsss.conf
r344 r367 7 7 target=tools_test 8 8 # buildflags=-full -unittest -g -O -debug 9 buildflags=-full -unittest - O9 buildflags=-full -unittest -debug -g trunk/tools/tools/behave_as.d
r315 r367 112 112 foo++; foo -= 4; 113 113 mustEqual("BehaveAsEqualityTest", foo, 2); 114 mustFail("RangedTest", foo += 100);114 debug { mustFail("RangedTest", foo += 100); } 115 115 auto x = new Test2; x.f = 5; 116 116 x.f_pf++; x.f_pf -= 4; trunk/tools/tools/downloader.d
r366 r367 300 300 if (len==0) { reuseConnection=false; logln("Connection closed at ", received.length); break; } 301 301 received ~= buffer[0..len]; 302 string _res; if (checkProgress(chunked, _res)) return _res; 302 303 if (chunked) if (receiveChunked) continue; else break; 303 string _res; if (checkProgress(chunked, _res)) return _res;304 304 if (length && (received.length !< length)) { if (!quiet) logln("Received all data"); break; } 305 305 } trunk/tools/tools/mersenne.d
r361 r367 10 10 logln("Downloading random data from Hotbits"); 11 11 res ~= cast(ubyte[]) download(Format("http://www.fourmilab.ch/cgi-bin/Hotbits?nbytes=", count-res.length, "&fmt=bin")); 12 logln("Now got ", res.length); 12 13 } 13 14 return res; … … 24 25 } 25 26 } 26 void seed_hotbits() { mt[] = cast(size_t[]) get_hotbits(N*4); } 27 void init_by_array(size_t init_key[], size_t key_length) { 28 int i=1, j=0, k=(N>key_length ? N : key_length); 27 void seed_hotbits() { 28 //mt[0 .. 16] = cast(size_t[]) get_hotbits(64); 29 init_by_array(cast(size_t[]) get_hotbits(64)); 30 } 31 void init_by_array(size_t[] key) { 32 int i=1, j=0, k=(N>key.length ? N : key.length); 29 33 seed(19650218UL); 30 34 while (k--) { 31 mt[i] = cast(uint) ((mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL)) + init_key[j] + j); /* non linear */35 mt[i] = cast(uint) ((mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525UL)) + key[j] + j); /* non linear */ 32 36 mt[i] &= 0xffffffffUL; /* for WORDSIZE > 32 machines */ 33 37 i++; j++; 34 38 if (i>=N) { mt[0] = mt[N-1]; i=1; } 35 if (j>=key _length) j=0;39 if (j>=key.length) j=0; 36 40 } 37 41 k=N-1; while (k--) { trunk/tools/tools/stackthreads.d
r319 r367 1 /// This file, insofar as copyright is applicable,2 /// shall fall under the BSD license. --the author3 1 module tools.stackthreads; 4 public import tools.base; 5 // stupid DSSS 6 // mixin(expandImport("tools.[base; log; functional; stackthreads_impl]; std.string")); 7 import std.string, tools.base, tools.log, tools.functional, tools.stackthreads_impl; 2 import tools.stackthreads_impl, tools.log, tools.threads; 8 3 9 const int defaultsize=1024*1024; // as stack space is mmapped, it starts out smaller and grows on usage. 10 11 class Pipe(I, O) { 12 static if (is(I==void)) alias Tuple!() InputPar; else alias Tuple!(I[]) InputPar; 13 static if (is(O==void)) alias void OutputPar; else static if (is(I==void)) alias O OutputPar; else alias O[] OutputPar; 14 alias I InputType; alias O OutputType; 15 abstract { 16 bool ready(); 17 OutputPar opCall(InputPar input); 4 class Coroutine { 5 static TLS!(Exception) failures; 6 static this() { New(failures, { return cast(Exception) null; }); } 7 private context ctx; 8 proc dg; 9 void safe_exec() { 10 toMain(); 11 try dg(); 12 catch (Exception ex) { 13 failures.set(ex); 14 toMain(); 15 asm { int 3; } 16 } 17 toMain(); 18 failures.set(new Exception("Coroutine has ended. Cannot invoke again.")); 19 toMain(); 18 20 } 19 const string descof="("~InputType.stringof~"->"~OutputType.stringof~")"; 20 Pipe!(InputType, W.OutputType) opCat(W)(W other) { 21 alias typeof(this) V; 22 return new class(this, other) Pipe!(InputType, W.OutputType) { 23 V stage1; W stage2; 24 this(V _one, W _two) { stage1=_one; stage2=_two; } 25 bool ready() { return stage1.ready() && stage2.ready(); } 26 OutputPar opCall(InputPar par) { return stage2(stage1(par)); } 27 }; 21 this(proc dg, size_t stacksize=1024*1024) { 22 this.dg = dg; 23 ctx.genstack(stacksize); 24 ctx.run(&safe_exec, getActiveContext()); 28 25 } 29 static if (is(OutputPar==void) && is(InputPar==Tuple!())) void execute() { while (ready) opCall(); } 26 void failcheck(string info) { 27 if (auto ex = failures()) throw new Exception(info~ex.toString()); 28 } 29 void opCall() { 30 failcheck("Trying to invoke coroutine failed with "); 31 ctx.activate(getActiveContext()); 32 failcheck("Coroutine failed with "); 33 } 34 static void toMain() { yield_main(getActiveContext()); } 30 35 } 31 36 32 static if (enableStackthreads) { 33 34 class StackThread(T, U) : Pipe!(T, U) { 35 const bool gotInput=!is(InputType==void); 36 const bool gotOutput=!is(OutputType==void); 37 final bool runsMe() { return ctx.runsMe(); } 38 /*ubyte[] backup() { return ctx.backup(); } 39 void restore(ubyte[] v) { ctx.restore(v); }*/ 40 Exception threadex; 41 private { 42 void delegate() _yield; 43 context!() ctx; 44 final void gencall(void delegate() y) { 45 _yield = y; 46 y(); 47 try func(); 48 catch (Exception e) { 49 threadex=e; 50 ctx.myState=ctxState.aborted; 51 y(); 52 } 53 ctx.myState=ctxState.completed; 54 y(); 55 asm { int 3; } 56 } 57 static if(gotInput) InputType *input; 58 static if(gotOutput) OutputType *output; 59 } 60 final void resume() { ctx.resume(); if (threadex) throw threadex; } 61 final void resume_samethread() { ctx.resume_samethread(); if (threadex) throw threadex; } 62 protected { 63 abstract void func(); 64 bool reading=false; 65 static if(gotInput) InputType read() { 66 reading=true; 67 scope(exit) { reading=false; input=null; } 68 while (!input) _yield(); 69 return *input; 70 } 71 static if(gotOutput) { 72 void yield(OutputType u) { 73 if (output) throw new Exception("Axiomatic exception: output buffer still filled"); 74 output=&u; 75 while (output) _yield(); 76 } 77 } else void yield() { _yield(); } 78 } 79 void reset() { 80 static if(gotInput) input=null; 81 static if(gotOutput) output=null; 82 ctx.run(&gencall); 83 } 84 this(int size=defaultsize) { ctx.genstack(size); reset; } 85 ~this() { 86 ctx.cleanup; 87 } 88 final { 89 static if (gotOutput) { 90 static if (!gotInput) { 91 OutputType opCall() { 92 while (!output) { if (!ready) throw new Exception("Cannot call ST: not ready"); resume; } 93 scope(exit) output=null; 94 return *output; 95 } 96 } else { 97 void flush(ref OutputType[] target) { 98 while (input) { 99 if (output) { target ~= *output; output=null; } 100 resume; 101 } 102 while (output) { 103 target ~= *output; 104 output=null; 105 if (ready) resume; 106 } 107 } 108 OutputType[] opCall(InputType inp) { 109 OutputType[] res; 110 flush(res); 111 input = &inp; 112 flush(res); 113 return res; 114 } 115 OutputType[] opCall(InputType[] inp) { 116 OutputType[] res; 117 foreach (ref i; inp) { 118 flush(res); 119 input = &i; 120 } 121 flush(res); 122 return res; 123 } 124 } 125 } else { 126 static if (gotInput) { 127 void opCall(InputType inp) { while (input) resume; input=&inp; while (input) resume; } 128 void opCall(InputType[] inp) { while (input) resume; foreach (ref i; inp) { input=&i; while (input) resume; } } 129 } else { 130 void opCall() { resume; } 131 } 132 } 133 final bool ready() { return ctx.myState==ctxState.sleeping; } 134 static if (gotOutput) bool hasOutput() { while (!output) { if (!ready) return false; resume; } return true; } 135 final bool run() { 136 if (ready && !reading) resume; 137 return ready; 138 } 139 final bool run_samethread() { 140 if (ready && !reading) resume_samethread; 141 return ready; 142 } 143 } 37 import tools.tests; 38 unittest { 39 logln("StackThread test"); 40 auto test = new Coroutine({ 41 logln("This is virtual stack context!"); 42 Coroutine.toMain(); 43 logln("Hi again. Finishing now."); 44 }); 45 logln("> This is main."); test(); 46 logln("> Reinvoking."); test(); 47 logln("> done"); 48 mustFail("ReinvokeTest", test()); 49 asm { int 3; } 144 50 } 145 146 import std.stdio;147 final class DelegateStackThread(T, U, bool reverse=false) : StackThread!(T, U) {148 static if (is(U==void)) {149 static if (is(T==void)) void delegate(proc yield) dg;150 else {151 static if (reverse) void delegate(T delegate() read, proc yield) dg;152 else void delegate(proc yield, T delegate() read) dg;153 }154 } else static if (is(T==void)) void delegate(void delegate(U) yield) dg;155 else156 static if (reverse) void delegate(T delegate() read, void delegate(U) yield) dg;157 else void delegate(void delegate(U) yield, T delegate() read) dg;158 this(typeof(dg) _dg, int size=defaultsize) { dg=_dg; super(size); }159 void func() {160 static if (is(T==void)) dg(&yield);161 else static if (reverse) dg(&read, &yield);162 else dg(&yield, &read);163 }164 }165 struct stackthread {166 static StackThread!(T, U) opAssign(T, U)(void delegate(void delegate(U) yield, T delegate() read) dg) {167 return new DelegateStackThread!(T, U)(dg);168 }169 static StackThread!(T, U) opAssign(T, U)(void delegate(T delegate() read, void delegate(U) yield) dg) {170 return new DelegateStackThread!(T, U, true)(dg);171 }172 static StackThread!(void, IF!(U.length, U), IF!(!U.length, Tuple!(void))) opAssign(U...)(void delegate(void delegate(U) yield) dg) {173 return new DelegateStackThread!(void, IF!(U.length, U), IF!(!U.length, void))(dg);174 }175 static StackThread!(T, void) opAssign(T)(void delegate(proc yield, T delegate() read) dg) {176 return new DelegateStackThread!(T, void)(dg);177 }178 static StackThread!(T, void) opAssign(T)(void delegate(T delegate() read, proc yield) dg) {179 return new DelegateStackThread!(T, void, true)(dg);180 }181 static StackThread!(T, void) opAssign(T)(void delegate(T delegate() read) dg) {182 static if (is(T==void)) {183 return new DelegateStackThread!(void, void)(dg);184 } else {185 return new DelegateStackThread!(T, void)((typeof(dg) _dg, proc yield, T delegate() read) {186 _dg(read);187 } /fix/ dg);188 }189 }190 }191 192 import tools.tests, std.gc;193 unittest {194 logln("stackthreads test");195 auto sieve = stackthread = (void delegate(int) yield) {196 auto length = 20, removed = new bool[length];197 for (int i = 2; i < length; i = i + 1) {198 if (removed[i] == false) { yield (i); for (int z = i * 2; z < length; z += i) removed[z]=true; }199 }200 };201 int[] res;202 while (sieve.hasOutput) res ~= sieve();203 mustEqual("SieveTest", res, [2, 3, 5, 7, 11, 13, 17, 19]);204 delete sieve;205 }206 207 /*208 void main() {209 auto sched=new StackThreadSched;210 sched~=(proc yield, void delegate(float) wait) { for (int i=0; i<3; ++i) { writefln("I: ", i, ": waiting 1s"); wait(1f); } };211 sched~=(proc yield, void delegate(float) wait) { for (int i=0; i<9; ++i) { writefln("II: ", i, ": waiting .3s"); wait(0.3f); } };212 while (sched.contexts.length) sched();213 }214 */215 } else { pragma(msg, "StackThreads are not supported on your architecture. Sorry ._."); }trunk/tools/tools/stackthreads_impl.d
r361 r367 1 1 module tools.stackthreads_impl; 2 import std.thread, tools.base, std.stdio;2 import tools.base; 3 3 4 4 static if (size_t.sizeof==8) const string regsize="r"; 5 5 else const string regsize="e"; 6 6 7 const bool patchedPhobos = is(typeof((new Thread).stack));8 9 7 version (BigEndian) const bool enableStackthreads = false; 10 8 else const bool enableStackthreads = true; 11 9 static if (enableStackthreads) { 12 static if (!patchedPhobos) {13 pragma(msg, "Your Phobos does not incorporate the MultiStacks patch. The GC will be disabled while StackThreads are active.");14 pragma(msg, "This may, in certain not-so-corner-cases, cause memory leaks. Blame the lack of Phobos maintenance.");15 }16 17 //TLS!(void*) original_stack_start;18 //static this() { New(original_stack_start, { return &(new Stuple!(void*))._0; }); }19 10 // this is a template so it's not compiled into static library code 20 11 // thus allowing the debug segments to depend on the application's debug mode, not the library's 21 12 struct djmpinfo() { 22 void* jmpaddr; 23 debug bool loaded=false; 24 void reset() { debug loaded=false; } 25 final void swap(ref djmpinfo other) { 26 debug { 27 if (loaded) { 28 writefln(this, " - Cannot save to a loaded jmp point"); 29 asm { int 3; } 30 } 31 loaded=true; 32 if (!other.loaded) { 33 writefln(&other, " - Cannot load from an unloaded jmp point"); 34 asm { int 3; } 35 } 36 other.loaded=false; 13 void* esp, start; // start is for the GC 14 static void switch_gc(ref djmpinfo from, djmpinfo to) { 15 auto thr = Thread.getThis(); 16 disable; // don't enable it again until you've switched over 17 from.start = thr.stackBottom; 18 thr.stackBottom = to.start; 19 auto esp = getESP(); 20 if (esp < from.start) addRange(esp, from.start); // this range is now static and not being updated on collection 21 else addRange(from.start, esp); 22 // remove to's range from the scanlist because it's going Active 23 with (to) if (esp) { 24 if (esp < start) removeRange(esp); 25 else if (start < esp) removeRange(start); 37 26 } 38 auto ja=&jmpaddr, ja2=&other.jmpaddr; 27 // I hope I didn't forget anything. 28 } 29 static void swap(ref djmpinfo from, ref djmpinfo to) { 30 switch_gc(from, to); 31 auto ep=&from.esp; 39 32 // now save to local, resume from other. 40 33 static if (gccasm) { … … 44 37 0: 45 38 46 push #ax\n push #bx\n push #si\n push #di\n push #bp39 pushal 47 40 48 41 mov #sp, (#cx) 49 mov (#dx), #sp42 mov #dx, #sp 50 43 51 pop #bp\n pop #di\n pop #si\n pop #bx\n pop #ax44 popal 52 45 53 46 ret 54 1:\" : : \"c\" ja, \"d\" ja2: \"ax\", \"bx\";47 1:\" : : \"c\" ep, \"d\" to.esp : \"ax\", \"bx\"; 55 48 }", "#", "%%"~regsize)); 56 49 } else { 57 50 asm { 58 mov ECX, ja; mov EDX, ja2;51 mov ECX, ep; mov EDX, to.esp; 59 52 call fuckery; jmp end; fuckery: 60 53 … … 62 55 63 56 mov [ECX], ESP; 64 mov ESP, [EDX];57 mov ESP, EDX; 65 58 66 59 popad; … … 70 63 } 71 64 } 65 enable; 72 66 } 73 void set(void* vstack, void delegate() dg) { 74 debug { 75 if (loaded) { 76 writefln(this, " - trying to set jmp point twice"); 77 asm { int 3; } 78 } 79 loaded=true; 80 } 81 void *ja=&jmpaddr; 82 bool _loaded = void; 67 void set(void* vstack, ref djmpinfo invoker, void delegate() dg) { 68 switch_gc(invoker, *this); 69 void *ep=&invoker.esp; 70 start = esp = vstack; 71 bool loaded = void; 83 72 auto dg_ptr = &dg; 84 73 typeof(dg_ptr) new_ptr; … … 90 79 jmp 1f 91 80 92 0: push %%ax\n push %%bx\n push %%si\n push %%di\n push %%bp81 0: pushal 93 82 mov %%sp, (%%bx) 94 83 mov %%cx, %%sp 95 84 96 85 push $1 97 1: pop %%cx\" : \"=c\" _loaded, \"=d\" new_ptr : \"b\" ja, \"c\" vstack, \"d\" dg_ptr;86 1: pop %%cx\" : \"=c\" loaded, \"=d\" new_ptr : \"b\" ep, \"c\" esp, \"d\" dg_ptr; 98 87 }", "%%", "%%"~regsize 99 88 )); 100 89 } else asm { 101 mov EBX, ja; mov ECX, vstack; mov EDX, dg_ptr;90 mov EBX, ep; mov ECX, esp; mov EDX, dg_ptr; 102 91 call set_fuckery; 103 mov _loaded, 0; jmp set_end;92 mov loaded, 0; jmp set_end; 104 93 set_fuckery: 105 94 … … 109 98 110 99 mov new_ptr, EDX; 111 mov _loaded, 1;100 mov loaded, 1; 112 101 set_end:; 113 102 } 114 if (!_loaded) return; 103 enable; 104 if (!loaded) return; 115 105 (*new_ptr)(); 106 asm { int 3; } 116 107 } 117 108 } 118 109 119 import std.gc, std.mmfile ;110 import std.gc, std.mmfile, std.thread, tools.threads; 120 111 121 112 /// NOT "mov res, EBP". Trust me on this one. … … 124 115 enum ctxState { dormant, running, sleeping, aborted, completed } 125 116 126 // see rationale for djmpinfo being templates 127 struct context() { 128 djmpinfo!() main, virtual; /// register and jump values for caller and stackthread 129 ctxState myState = ctxState.dormant; /// my current state (running, sleeping, dead) 117 TLS!(context) mainline; 118 TLS!(context*) active; 119 static this() { 120 New(mainline, { return new context; }); 121 New(active, { auto res = new Stuple!(context*); return &res._0; }); 122 } 123 void yield_main(context* invoker) { mainline.ptr().activate(invoker); } 124 context* getActiveContext() { 125 auto res = active.ptr(); 126 if (!res || !*res) return mainline.ptr(); 127 else return *res; 128 } 129 130 struct context { 131 djmpinfo!() info; // jump info for stackthread. 132 ctxState state = ctxState.dormant; /// my current state (running, sleeping, dead) 130 133 void[] vstack; /// the virtual stack 131 134 MmFile vstack_file=null; /// the underlying MmFile for the stack. 132 135 void genstack(size_t size) { 133 136 assert(!vstack_file); 134 version(Win32) { 135 pragma(msg, "Using new for the vstack. Blame Walter and win32's broken MmFile."); 136 pragma(msg, "If anonymous MmFile has been fixed by now, please notify the author and disregard this warning."); 137 vstack = new void[size]; 138 } else vstack=(vstack_file=new MmFile(null, MmFile.Mode.ReadWriteNew, size, null))[]; 139 static if (patchedPhobos) me = addStack(vstack.ptr, vstack.ptr + vstack.length); 140 addRange(vstack.ptr, vstack.ptr + vstack.length); 137 vstack=(vstack_file=new MmFile(null, MmFile.Mode.ReadWriteNew, size, null))[]; 138 // hasPointers(vstack.ptr); 141 139 } 142 static if (patchedPhobos) Stack* me, caller; 143 void cleanup() { 144 static if (patchedPhobos) delStack(me); 145 if (vstack_file) delete vstack_file; 146 vstack_file=null; 147 } 140 void cleanup() { vstack_file=null; } 148 141 // size_t size() { return vstack.length/uint.sizeof; } 149 142 bool runsMe() { … … 155 148 return (esp>=vstack.ptr) && (esp < vstack.ptr+vstack.length); 156 149 } 157 void yield() { 158 if (myState == ctxState.running) myState = ctxState.sleeping; 159 static if (patchedPhobos) { 160 me.lastESP = getESP(); 161 lastExecutingThread.stack = caller; // reset to calling stack 162 } else enable; 163 virtual.swap(main); 150 void run(void delegate() dg, context* invoker) { 151 scope(failure) logln(" >>run fails"); 152 state = ctxState.running; 153 if (!invoker) invoker = mainline.ptr(); 154 invoker.state = ctxState.sleeping; 155 *active.ptr() = this; 156 /// leave a bit of space on the other side 157 info.set(vstack.ptr + vstack.length - 256, invoker.info, dg); 164 158 } 165 void delegate(proc yield) dg; 166 void execute() { dg(&yield); } 167 static if (patchedPhobos) Thread lastExecutingThread; 168 void run(void delegate(void delegate() yield) dg) { 169 scope(failure) writefln(" >>run fails"); 170 main.reset; virtual.reset; 171 auto vbp = vstack.ptr + vstack.length - 256; /// leave a bit of space on the other side 172 myState = ctxState.running; 173 this.dg=dg; 174 static if (patchedPhobos) { 175 auto esp = getESP(); 176 lastExecutingThread = Thread.getThis; 177 caller = lastExecutingThread.stack; 178 assert(caller.contains(esp)); 179 caller.lastESP = esp; 180 lastExecutingThread.stack = me; 181 } else disable; 182 main.set(vbp, &execute); 183 } 184 void resume_samethread() { 185 if (myState != ctxState.sleeping) throw new Exception(Format("Trying to resume from invalid state ", myState, "!")); 186 myState = ctxState.running; 187 static if (patchedPhobos) { 188 auto esp = getESP(); 189 caller = lastExecutingThread.stack; 190 assert(caller.contains(esp)); 191 caller.lastESP = esp; 192 lastExecutingThread.stack = me; // switch the thread's active stack 193 } else disable; 194 main.swap(virtual); 195 } 196 void resume() { 197 static if (patchedPhobos) { 198 assert(!!lastExecutingThread); 199 if (!lastExecutingThread.isSelf()) lastExecutingThread = Thread.getThis(); 200 } 201 resume_samethread(); 159 void activate(context* invoker) { 160 *active.ptr() = this; 161 if (state != ctxState.sleeping) throw new Exception(Format("Cannot activate context: invalid state ", state, "!")); 162 state = ctxState.running; 163 if (!invoker) invoker = mainline.ptr(); 164 invoker.state = ctxState.sleeping; 165 typeof(info).swap(invoker.info, info); 202 166 } 203 167 } trunk/tools/tools/threads.d
r365 r367 90 90 if (!res) { 91 91 res = maker(); 92 synchronized values ~= res;92 synchronized(this) values ~= res; 93 93 check("TlsSetValue", TlsSetValue(key, cast(void*) res)); 94 94 } … … 207 207 if (!res) { 208 208 res = maker(); 209 synchronized values ~= res;209 synchronized(this) values ~= res; 210 210 check("pthread_setspecific", pthread_setspecific(key, cast(void*) res)); 211 211 }
