Handle external simulator output gracefully
On Windows, ngspice doesn't output messages to stdout or stderr, it starts the gui which causes KiCad to hang until ngspice is terminated. We want to handle immediate responses but not get hung by the external process. Passing a process class to wxExecute allows us to detach the process (it will terminate and free itself) while still handling the immediate output and errors Fixes https://gitlab.com/kicad/code/kicad/-/issues/15446
This commit is contained in:
parent
1a2f2d418c
commit
4a19bef2ac
|
@ -52,6 +52,7 @@
|
||||||
#include <wx/filedlg.h>
|
#include <wx/filedlg.h>
|
||||||
#include <wx/msgdlg.h>
|
#include <wx/msgdlg.h>
|
||||||
#include <wx/regex.h>
|
#include <wx/regex.h>
|
||||||
|
#include <wx/txtstrm.h>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -565,47 +566,68 @@ bool DIALOG_EXPORT_NETLIST::TransferDataFromWindow()
|
||||||
|
|
||||||
if( !commandLine.IsEmpty() )
|
if( !commandLine.IsEmpty() )
|
||||||
{
|
{
|
||||||
wxArrayString output;
|
wxProcess* process = new wxProcess( GetEventHandler(), wxID_ANY );
|
||||||
wxArrayString errors;
|
process->Redirect();
|
||||||
wxExecute( commandLine, output, errors, wxEXEC_ASYNC );
|
wxExecute( commandLine, wxEXEC_ASYNC, process );
|
||||||
|
|
||||||
reporter.ReportHead( commandLine, RPT_SEVERITY_ACTION );
|
reporter.ReportHead( commandLine, RPT_SEVERITY_ACTION );
|
||||||
|
process->Activate();
|
||||||
|
|
||||||
if( output.GetCount() )
|
sleep( 1 ); // give the process time to start and output any data or errors
|
||||||
|
|
||||||
|
if( process->IsInputAvailable() )
|
||||||
{
|
{
|
||||||
for( unsigned ii = 0; ii < output.GetCount(); ii++ )
|
wxInputStream* in = process->GetInputStream();
|
||||||
reporter.Report( output[ii], RPT_SEVERITY_INFO );
|
wxTextInputStream textstream( *in );
|
||||||
|
|
||||||
|
while( in->CanRead() )
|
||||||
|
{
|
||||||
|
wxString line = textstream.ReadLine();
|
||||||
|
|
||||||
|
if( !line.IsEmpty() )
|
||||||
|
reporter.Report( line, RPT_SEVERITY_INFO );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( errors.GetCount() )
|
if( process->IsErrorAvailable() )
|
||||||
{
|
{
|
||||||
for( unsigned ii = 0; ii < errors.GetCount(); ii++ )
|
wxInputStream* err = process->GetErrorStream();
|
||||||
{
|
wxTextInputStream textstream( *err );
|
||||||
// wxExecute returns -1 for all error conditions, so we've no choice but
|
|
||||||
// to scrape the stderr messages for the error code(s).
|
|
||||||
|
|
||||||
if( errors[ii].EndsWith( wxS( "failed with error 2!" ) ) ) // ENOENT
|
while( err->CanRead() )
|
||||||
|
{
|
||||||
|
wxString line = textstream.ReadLine();
|
||||||
|
|
||||||
|
if( !line.IsEmpty() )
|
||||||
{
|
{
|
||||||
reporter.Report( _( "external simulator not found" ), RPT_SEVERITY_ERROR );
|
if( line.EndsWith( wxS( "failed with error 2!" ) ) ) // ENOENT
|
||||||
reporter.Report( _( "Note: command line is usually: "
|
{
|
||||||
"<tt><path to SPICE binary> \"%I\"</tt>" ),
|
reporter.Report( _( "external simulator not found" ), RPT_SEVERITY_ERROR );
|
||||||
RPT_SEVERITY_INFO );
|
reporter.Report( _( "Note: command line is usually: "
|
||||||
}
|
"<tt><path to SPICE binary> \"%I\"</tt>" ),
|
||||||
else if( errors[ii].EndsWith( wxS( "failed with error 8!" ) ) ) // ENOEXEC
|
RPT_SEVERITY_INFO );
|
||||||
{
|
}
|
||||||
reporter.Report( _( "external simulator has the wrong format or "
|
else if( line.EndsWith( wxS( "failed with error 8!" ) ) ) // ENOEXEC
|
||||||
"architecture" ), RPT_SEVERITY_ERROR );
|
{
|
||||||
}
|
reporter.Report( _( "external simulator has the wrong format or "
|
||||||
else if( errors[ii].EndsWith( "failed with error 13!" ) ) // EACCES
|
"architecture" ), RPT_SEVERITY_ERROR );
|
||||||
{
|
}
|
||||||
reporter.Report( _( "permission denied" ), RPT_SEVERITY_ERROR );
|
else if( line.EndsWith( "failed with error 13!" ) ) // EACCES
|
||||||
}
|
{
|
||||||
else
|
reporter.Report( _( "permission denied" ), RPT_SEVERITY_ERROR );
|
||||||
{
|
}
|
||||||
reporter.Report( errors[ii], RPT_SEVERITY_ERROR );
|
else
|
||||||
|
{
|
||||||
|
reporter.Report( line, RPT_SEVERITY_ERROR );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
process->CloseOutput();
|
||||||
|
process->Detach();
|
||||||
|
|
||||||
|
// Do not delete process, it will delete itself when it terminates
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue