Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 328 lines (275 sloc) 7.512 kb
998e929 @AndrejMitrovic Add license, some updates.
authored
1 /+
2 + Copyright Andrej Mitrovic 2011.
a04db48 @AndrejMitrovic add more license info.
authored
3 + Copyright Tomasz Stachowiak 2009 - 2011
998e929 @AndrejMitrovic Add license, some updates.
authored
4 + Distributed under the Boost Software License, Version 1.0.
5 + (See accompanying file LICENSE_1_0.txt or copy at
6 + http://www.boost.org/LICENSE_1_0.txt)
7 +/
ac0b94b @AndrejMitrovic process ported, partially.
authored
8 module xfbuild.Process;
9
ea05025 @AndrejMitrovic Replace custom functions with Phobos stuff. Add more license headers.
authored
10 import xfbuild.GlobalParams;
105c4a3 @AndrejMitrovic Small details.
authored
11 import xfbuild.Exception;
ac0b94b @AndrejMitrovic process ported, partially.
authored
12
ea05025 @AndrejMitrovic Replace custom functions with Phobos stuff. Add more license headers.
authored
13 version (Windows)
14 {
6f1adb8 @AndrejMitrovic Preliminary profiling support.
authored
15 import xfbuild.Pipes;
16
ea05025 @AndrejMitrovic Replace custom functions with Phobos stuff. Add more license headers.
authored
17 import win32.windef;
18 import win32.winuser;
19 import win32.winbase;
20 import win32.winnls;
67240e0 @AndrejMitrovic new stuff
authored
21
ea05025 @AndrejMitrovic Replace custom functions with Phobos stuff. Add more license headers.
authored
22 // note: has to be here as in win32.winbase it's protected via version(_WIN32_WINNT_ONLY),
23 // maybe it's there for a good reason ..
24 extern (Windows) extern BOOL SetProcessAffinityMask(HANDLE, size_t);
25 extern (Windows) extern BOOL GetProcessAffinityMask(HANDLE, size_t*, size_t*);
26 }
27
28 version (MultiThreaded)
29 {
30 import core.atomic;
ac0b94b @AndrejMitrovic process ported, partially.
authored
31 }
32
ea05025 @AndrejMitrovic Replace custom functions with Phobos stuff. Add more license headers.
authored
33 import std.algorithm;
34 import std.concurrency;
35 import std.exception;
6f1adb8 @AndrejMitrovic Preliminary profiling support.
authored
36 import std.datetime;
ea05025 @AndrejMitrovic Replace custom functions with Phobos stuff. Add more license headers.
authored
37 import std.process;
38 import std.stdio;
39 import std.string;
40 import std.array;
41 import std.utf;
42 import std.conv : to;
43
f141c77 @AndrejMitrovic linux support
authored
44 alias reduce!("a ~ ' ' ~ b") flatten;
45
46 import std.array;
47 import std.random;
48 import std.format;
49 import std.file;
50
6f1adb8 @AndrejMitrovic Preliminary profiling support.
authored
51 struct ProfWatch
52 {
53 void restart()
54 {
55 sw.stop();
56 sw.reset();
57 sw.start();
58 }
59
150c844 @AndrejMitrovic Fix 2.057 compatibility.
authored
60 auto time()
61 {
62 return sw.peek.msecs;
63 }
64
6f1adb8 @AndrejMitrovic Preliminary profiling support.
authored
65 StopWatch sw;
66 alias sw this;
67 }
68
f141c77 @AndrejMitrovic linux support
authored
69 // modified from std.process.shell
70 // (nothrow, saves output)
71 // note: doesn't pass environment
72 string shellExecute(string cmd)
ac0b94b @AndrejMitrovic process ported, partially.
authored
73 {
f141c77 @AndrejMitrovic linux support
authored
74 // Generate a random filename
75 auto a = appender!string();
76 foreach (ref e; 0 .. 8)
926538d @AndrejMitrovic First full compile.
authored
77 {
f141c77 @AndrejMitrovic linux support
authored
78 formattedWrite(a, "%x", rndGen.front);
79 rndGen.popFront;
926538d @AndrejMitrovic First full compile.
authored
80 }
f141c77 @AndrejMitrovic linux support
authored
81 auto filename = a.data;
82 scope(exit) if (exists(filename)) remove(filename);
83 auto result = system(cmd ~ "> " ~ filename);
84 return readText(filename);
85 }
86
87 struct Process
88 {
89 string[] args;
926538d @AndrejMitrovic First full compile.
authored
90
91 this(bool copyEnv, string[] args)
92 {
f141c77 @AndrejMitrovic linux support
authored
93 // todo: can't find anything in phobos to pass environment
94 // and return stdout/stderr output, OR just execute process
95 // and redirect stdout/stderr. execvpe isn't useful since
96 // I can't redirect via ' > ' in its call.
97 this.args = args;
926538d @AndrejMitrovic First full compile.
authored
98 }
99
f141c77 @AndrejMitrovic linux support
authored
100 string execute()
ac0b94b @AndrejMitrovic process ported, partially.
authored
101 {
f141c77 @AndrejMitrovic linux support
authored
102 auto cmd = flatten(args);
103 return shellExecute(cmd);
ac0b94b @AndrejMitrovic process ported, partially.
authored
104 }
105
106 // todo
107 string toString()
108 {
109 return "";
110 }
111
112 // todo
113 struct Result
114 {
115 int status;
116 }
117
118 // todo
119 Result wait()
120 {
121 return Result(0);
122 }
123
124 // todo
125 ~this()
126 {
127 }
128 }
129
130 void checkProcessFail(Process process)
131 {
132 auto result = process.wait();
133
134 if (result.status != 0)
135 {
105c4a3 @AndrejMitrovic Small details.
authored
136 string name = process.toString();
ac0b94b @AndrejMitrovic process ported, partially.
authored
137
138 if (name.length > 255)
139 name = name[0 .. 255] ~ " [...]";
140
105c4a3 @AndrejMitrovic Small details.
authored
141 string errorMsg = format("\"%s\" returned %s",
142 name,
143 result.status);
144
145 throw new ProcessExecutionException(errorMsg, __FILE__, __LINE__);
ac0b94b @AndrejMitrovic process ported, partially.
authored
146 }
147 }
148
f141c77 @AndrejMitrovic linux support
authored
149 string execute(Process process)
ac0b94b @AndrejMitrovic process ported, partially.
authored
150 {
f141c77 @AndrejMitrovic linux support
authored
151 return process.execute();
ac0b94b @AndrejMitrovic process ported, partially.
authored
152
f141c77 @AndrejMitrovic linux support
authored
153 // todo
154 //~ if (globalParams.printCommands)
155 //~ {
156 //~ writeln(process);
157 //~ }
ac0b94b @AndrejMitrovic process ported, partially.
authored
158 }
159
e80ecfb @AndrejMitrovic Implement process piping. This is still highly experimental, and there a...
authored
160 // @TODO@ Implement pipes here
ac0b94b @AndrejMitrovic process ported, partially.
authored
161 void executeAndCheckFail(string[] cmd, size_t affinity)
162 {
6f1adb8 @AndrejMitrovic Preliminary profiling support.
authored
163 version (Profile)
ac0b94b @AndrejMitrovic process ported, partially.
authored
164 {
6f1adb8 @AndrejMitrovic Preliminary profiling support.
authored
165 auto thisSw = StopWatch(AutoStart.yes);
166 scope (exit)
167 {
168 thisSw.stop();
169 writefln("--Profiler-- Execute compiler and check fail done in %s msecs.", thisSw.peek.msecs);
170 }
e80ecfb @AndrejMitrovic Implement process piping. This is still highly experimental, and there a...
authored
171 }
6f1adb8 @AndrejMitrovic Preliminary profiling support.
authored
172
89dd83d @AndrejMitrovic Woops, forgot about our friend Linux. Still have to test...
authored
173 version (Windows)
e80ecfb @AndrejMitrovic Implement process piping. This is still highly experimental, and there a...
authored
174 {
6f1adb8 @AndrejMitrovic Preliminary profiling support.
authored
175 version (Profile) { auto sw = ProfWatch(); sw.restart(); }
89dd83d @AndrejMitrovic Woops, forgot about our friend Linux. Still have to test...
authored
176 auto procInfo = createProcessPipes();
150c844 @AndrejMitrovic Fix 2.057 compatibility.
authored
177 version (Profile) writefln("--Profiler-- Pipes created in %s msecs.", sw.time);
6f1adb8 @AndrejMitrovic Preliminary profiling support.
authored
178
89dd83d @AndrejMitrovic Woops, forgot about our friend Linux. Still have to test...
authored
179 string sys = cmd.join(" ");
e80ecfb @AndrejMitrovic Implement process piping. This is still highly experimental, and there a...
authored
180
6f1adb8 @AndrejMitrovic Preliminary profiling support.
authored
181 version (Profile) sw.restart();
89dd83d @AndrejMitrovic Woops, forgot about our friend Linux. Still have to test...
authored
182 auto result = runProcess(sys, procInfo);
150c844 @AndrejMitrovic Fix 2.057 compatibility.
authored
183 version (Profile) writefln("--Profiler-- Run compiler process done in %s msecs.", sw.time);
6f1adb8 @AndrejMitrovic Preliminary profiling support.
authored
184
185 version (Profile) sw.restart();
89dd83d @AndrejMitrovic Woops, forgot about our friend Linux. Still have to test...
authored
186 auto output = readProcessPipeString(procInfo);
150c844 @AndrejMitrovic Fix 2.057 compatibility.
authored
187 version (Profile) writefln("--Profiler-- Reading pipes done in %s msecs.", sw.time);
89dd83d @AndrejMitrovic Woops, forgot about our friend Linux. Still have to test...
authored
188
189 if (result != 0)
190 {
191 string errorMsg = format("\"%s\" returned %s with error message:\n\n%s",
192 sys,
193 result,
194 output);
195
196 throw new ProcessExecutionException(errorMsg, __FILE__, __LINE__);
197 }
198 }
199 else
200 {
150c844 @AndrejMitrovic Fix 2.057 compatibility.
authored
201 version (Profile) { auto sw = ProfWatch(); sw.restart(); }
89dd83d @AndrejMitrovic Woops, forgot about our friend Linux. Still have to test...
authored
202 string sys = cmd.join(" ");
203 int result = system(sys);
150c844 @AndrejMitrovic Fix 2.057 compatibility.
authored
204 version (Profile) writefln("--Profiler-- Invoke/Read process done in %s msecs.", sw.time);
205
89dd83d @AndrejMitrovic Woops, forgot about our friend Linux. Still have to test...
authored
206 if (result != 0)
207 {
208 string errorMsg = format("\"%s\" returned %s.",
209 sys,
210 result);
211
212 throw new ProcessExecutionException(errorMsg, __FILE__, __LINE__);
213 }
ac0b94b @AndrejMitrovic process ported, partially.
authored
214 }
215 }
216
f138900 @AndrejMitrovic +verbose has a nicer output for threads now.
authored
217 version (MultiThreaded)
218 {
219 // @BUG@ 7036
220 //~ shared int value;
221 __gshared int value;
222 }
223 else
224 {
225 __gshared int value;
226 }
3544539 @AndrejMitrovic xfbuild now compiles, serially and in parallel.
authored
227
71be26b @AndrejMitrovic xpath needs to work on relative paths.
authored
228 class Foo { }
229 __gshared Foo mutex;
230
ac0b94b @AndrejMitrovic process ported, partially.
authored
231 void executeCompilerViaResponseFile(string compiler, string[] args, size_t affinity)
232 {
71be26b @AndrejMitrovic xpath needs to work on relative paths.
authored
233 string rspFile;
f141c77 @AndrejMitrovic linux support
authored
234 version (MultiThreaded)
235 {
71be26b @AndrejMitrovic xpath needs to work on relative paths.
authored
236 synchronized (mutex)
237 {
238 atomicOp!"+="(value, 1);
239 rspFile = format("xfbuild.%s.rsp", value);
240 }
f141c77 @AndrejMitrovic linux support
authored
241 }
242 else
243 {
244 value += 1;
71be26b @AndrejMitrovic xpath needs to work on relative paths.
authored
245 rspFile = format("xfbuild.%s.rsp", value);
f141c77 @AndrejMitrovic linux support
authored
246 }
71be26b @AndrejMitrovic xpath needs to work on relative paths.
authored
247
ac0b94b @AndrejMitrovic process ported, partially.
authored
248 string rspData = args.join("\n");
249
7455e3b @AndrejMitrovic latest.
authored
250 scope (failure)
ac0b94b @AndrejMitrovic process ported, partially.
authored
251 {
252 if (globalParams.removeRspOnFail)
253 {
254 std.file.remove(rspFile);
255 }
256 }
257
7455e3b @AndrejMitrovic latest.
authored
258 scope (success)
ac0b94b @AndrejMitrovic process ported, partially.
authored
259 {
260 std.file.remove(rspFile);
71be26b @AndrejMitrovic xpath needs to work on relative paths.
authored
261 }
262
263 /+if (globalParams.verbose) {
264 writefln("running the compiler with:\n%s", rspData);
265 }+/
266 auto file = File(rspFile, "w");
267 file.write(rspData);
3544539 @AndrejMitrovic xfbuild now compiles, serially and in parallel.
authored
268 file.close();
71be26b @AndrejMitrovic xpath needs to work on relative paths.
authored
269
ac0b94b @AndrejMitrovic process ported, partially.
authored
270 executeAndCheckFail([compiler, "@" ~ rspFile], affinity);
271 }
272
273 size_t getNthAffinityMaskBit(size_t n)
274 {
275 version (Windows)
276 {
277 /*
278 * This basically asks the system for the affinity
279 * mask and uses the N-th set bit in it, where
280 * N == thread id % number of bits set in the mask.
281 *
282 * Could be rewritten with intrinsics, but only
283 * DMD seems to have these.
284 */
285
286 size_t sysAffinity, thisAffinity;
287
288 if (!GetProcessAffinityMask(
289 GetCurrentProcess(),
290 &thisAffinity,
291 &sysAffinity
292 ) || 0 == sysAffinity)
293 {
294 throw new Exception("GetProcessAffinityMask failed");
295 }
296
297 size_t i = n;
298 size_t affinityMask = 1;
299
300 while (i-- != 0)
301 {
302 do
303 {
304 affinityMask <<= 1;
305
306 if (0 == affinityMask)
307 {
308 affinityMask = 1;
309 }
310 }
311 while (0 == (affinityMask & thisAffinity));
312 }
313
314 affinityMask &= thisAffinity;
315 assert(affinityMask != 0);
316 }
317 else
318 {
319 // TODO
320
321 assert(n < size_t.sizeof * 8);
322 size_t affinityMask = 1;
323 affinityMask <<= n;
324 }
325
326 return affinityMask;
327 }
Something went wrong with that request. Please try again.