1 module d.semantic.scheduler; 2 3 import d.ir.symbol; 4 5 import d.semantic.semantic; 6 import d.semantic.symbol; 7 8 import std.algorithm; 9 import std.range; 10 import std.traits; 11 12 import core.thread; 13 14 final class Scheduler { 15 SemanticPass pass; 16 17 Process[Symbol] processes; 18 19 private Process[] pool; 20 21 this(SemanticPass pass) { 22 this.pass = pass; 23 } 24 25 void terminate() { 26 auto f = new Fiber({ 27 while (processes.length) { 28 foreach (s; processes.keys) { 29 require(s); 30 } 31 } 32 }); 33 34 while (f.state != Fiber.State.TERM) { 35 f.call(); 36 } 37 } 38 39 void require(Symbol s, Step step = LastStep) { 40 if (s.step >= step) { 41 return; 42 } 43 44 // Overloadset sadness... 45 if (auto os = cast(OverloadSet) s) { 46 require(os, step); 47 return; 48 } 49 50 auto state = pass.state; 51 scope(exit) pass.state = state; 52 53 while(s.step < step) { 54 auto p = s in processes; 55 assert(p, "No Fiber found for " ~ s.name.toString(pass.context)); 56 57 auto f = *p; 58 if (f.state == Fiber.State.EXEC) { 59 // TODO: Check for possible forward reference problem. 60 } 61 62 if (f.state == Fiber.State.HOLD) { 63 f.call(); 64 } 65 66 if (f.state == Fiber.State.TERM) { 67 processes.remove(s); 68 69 pool ~= f; 70 } 71 72 if (s.step >= step) { 73 return; 74 } 75 76 /+ 77 import std.stdio; 78 writefln("%s (%s) %s", s.name.toString(pass.context), typeid(s).toString(), step); 79 //+ 80 try { 81 throw new Exception("Require call stack"); 82 } catch(Exception e) { 83 writeln(e); 84 } 85 // +/ 86 writeln("Yield !"); 87 88 Thread.sleep(dur!"seconds"(1)); 89 // +/ 90 Fiber.yield(); 91 } 92 } 93 94 void require(R)(R syms, Step step = LastStep) if(isSymbolRange!R) { 95 foreach (s; syms) { 96 require(s, step); 97 } 98 } 99 100 void require(OverloadSet os, Step step = LastStep) { 101 if (os.step >= step) { 102 return; 103 } 104 105 foreach (s; os.set) { 106 require(s, step); 107 os.hasContext = os.hasContext || s.hasContext; 108 os.hasThis = os.hasThis || s.hasThis; 109 } 110 111 os.step = step; 112 } 113 114 private Process getProcess() { 115 Process p; 116 117 // XXX: it seems that if(pool) test for the pointer, not the content. 118 // Seems to me like a weird conflation of identity and value. 119 if (pool.length) { 120 p = pool[$ - 1]; 121 122 pool = pool[0 .. $ - 1]; 123 pool.assumeSafeAppend(); 124 } else { 125 p = new Process(pass); 126 } 127 128 return p; 129 } 130 131 void schedule(D, S)(D d, S s) if(isSchedulable!(D, S)) in { 132 assert(s.step == SemanticPass.Step.Parsed, "Symbol processing already started."); 133 } do { 134 auto p = getProcess(); 135 p.init(d, s); 136 137 processes[s] = p; 138 } 139 140 void schedule(Template t, TemplateInstance i) in { 141 assert(i.step == SemanticPass.Step.Parsed, "Symbol processing already started."); 142 } do { 143 auto p = getProcess(); 144 p.init(t, i); 145 146 processes[i] = p; 147 } 148 149 // FIXME: We should consider a generic way to get things in there. 150 // It is clearly not going to scale that way. 151 import d.ast.expression; 152 void schedule(AstExpression dv, Variable v) in { 153 assert(v.step == SemanticPass.Step.Parsed, "Symbol processing already started."); 154 } do { 155 auto p = getProcess(); 156 p.init(dv, v); 157 158 processes[v] = p; 159 } 160 } 161 162 private: 163 final class Process : Fiber { 164 enum StackSize = 32 * 4096; 165 166 SemanticPass pass; 167 168 this(SemanticPass pass) { 169 this.pass = pass; 170 171 super(function() { 172 assert(0, "You must initialize process before using it."); 173 }, StackSize); 174 } 175 176 void init(D, S)(D d, S s) { 177 auto state = pass.state; 178 reset({ 179 pass.state = state; 180 SymbolAnalyzer(pass).analyze(d, s); 181 }); 182 } 183 } 184 185 alias Step = SemanticPass.Step; 186 enum LastStep = EnumMembers!Step[$ - 1]; 187 188 bool checkEnumElements() { 189 uint i; 190 foreach (s; EnumMembers!Step) { 191 if (s != i++) { 192 return false; 193 } 194 } 195 196 return i > 0; 197 } 198 199 static assert(is(Step : uint) && checkEnumElements(), "Step enum is ill defined."); 200 201 enum isSymbolRange(R) = isInputRange!R && is(ElementType!R : Symbol); 202