mirror of https://github.com/buggins/dlangide.git
161 lines
4.2 KiB
D
161 lines
4.2 KiB
D
module ddebug.common.nodebug;
|
|
|
|
import ddebug.common.execution;
|
|
|
|
import core.thread;
|
|
import std.process;
|
|
import dlangui.core.logger;
|
|
|
|
class ProgramExecutionNoDebug : Thread, ProgramExecution {
|
|
|
|
// parameters
|
|
/// provides _executableFile, _executableArgs, _executableWorkingDir, _executableEnvVars parameters and setter function setExecutableParams
|
|
mixin ExecutableParams;
|
|
/// provides _terminalExecutable and setTerminalExecutable setter
|
|
mixin TerminalParams;
|
|
|
|
protected ProgramExecutionStatusListener _listener;
|
|
void setProgramExecutionStatusListener(ProgramExecutionStatusListener listener) {
|
|
_listener = listener;
|
|
}
|
|
|
|
// status
|
|
protected Pid _pid;
|
|
protected ExecutionStatus _status = ExecutionStatus.NotStarted;
|
|
protected int _exitCode = 0;
|
|
|
|
/// initialize but do not run
|
|
this() {
|
|
super(&threadFunc);
|
|
}
|
|
|
|
~this() {
|
|
stop();
|
|
}
|
|
|
|
private bool isProcessActive() {
|
|
if (_pid is null)
|
|
return false;
|
|
auto res = tryWait(_pid);
|
|
if (res.terminated) {
|
|
Log.d("Process ", _executableFile, " is stopped");
|
|
_exitCode = wait(_pid);
|
|
_pid = Pid.init;
|
|
return false;
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
private void killProcess() {
|
|
if (_pid is null)
|
|
return;
|
|
try {
|
|
Log.d("Trying to kill process", _executableFile);
|
|
kill(_pid, 9);
|
|
Log.d("Waiting for process termination");
|
|
_exitCode = wait(_pid);
|
|
_pid = Pid.init;
|
|
Log.d("Killed");
|
|
} catch (Exception e) {
|
|
Log.d("Exception while killing process " ~ _executableFile, e);
|
|
_pid = Pid.init;
|
|
}
|
|
}
|
|
|
|
private void threadFunc() {
|
|
import std.stdio;
|
|
import std.array: empty;
|
|
|
|
// prepare parameter list
|
|
string[] params;
|
|
params ~= _executableFile;
|
|
params ~= _executableArgs;
|
|
|
|
// external console support
|
|
if (!_terminalExecutable.empty) {
|
|
string cmdline = escapeShellCommand(params);
|
|
params.length = 0;
|
|
params ~= _terminalExecutable;
|
|
params ~= "-e";
|
|
params ~= cmdline;
|
|
}
|
|
|
|
File newstdin;
|
|
File newstdout;
|
|
File newstderr;
|
|
version (Windows) {
|
|
} else {
|
|
newstdin = stdin;
|
|
newstdout = stdout;
|
|
newstderr = stderr;
|
|
}
|
|
try {
|
|
_pid = spawnProcess(params, newstdin, newstdout, newstderr, null, Config.none, _executableWorkingDir);
|
|
} catch (Exception e) {
|
|
Log.e("ProgramExecutionNoDebug: Failed to spawn process: ", e);
|
|
killProcess();
|
|
_status = ExecutionStatus.Error;
|
|
}
|
|
|
|
if (_status != ExecutionStatus.Error) {
|
|
// thread loop: poll process status
|
|
while (!_stopRequested) {
|
|
Thread.sleep(dur!"msecs"(50));
|
|
if (!isProcessActive()) {
|
|
_status = ExecutionStatus.Finished;
|
|
break;
|
|
}
|
|
}
|
|
if (_stopRequested) {
|
|
killProcess();
|
|
_status = ExecutionStatus.Killed;
|
|
}
|
|
}
|
|
|
|
// finished
|
|
Log.d("ProgramExecutionNoDebug: finished, execution status: ", _status);
|
|
_listener.onProgramExecutionStatus(this, _status, _exitCode);
|
|
}
|
|
|
|
// implement ProgramExecution interface
|
|
|
|
/// returns true if it's debugger
|
|
@property bool isDebugger() { return false; }
|
|
|
|
/// executable file
|
|
@property string executableFile() { return _executableFile; }
|
|
|
|
/// returns execution status
|
|
@property ExecutionStatus status() { return _status; }
|
|
|
|
/// start execution
|
|
void run() {
|
|
if (_runRequested)
|
|
return; // already running
|
|
assert(_listener !is null);
|
|
_runRequested = true;
|
|
_threadStarted = true;
|
|
_status = ExecutionStatus.Running;
|
|
start();
|
|
}
|
|
|
|
/// stop execution (call from GUI thread)
|
|
void stop() {
|
|
if (!_runRequested)
|
|
return;
|
|
if (_stopRequested)
|
|
return;
|
|
_stopRequested = true;
|
|
if (_threadStarted && !_threadJoined) {
|
|
_threadJoined = true;
|
|
join();
|
|
}
|
|
}
|
|
|
|
protected bool _threadStarted;
|
|
protected bool _threadJoined;
|
|
protected bool _stopRequested;
|
|
protected bool _runRequested;
|
|
}
|