diff --git a/include/eepp/system/process.hpp b/include/eepp/system/process.hpp index 679b409e6..bc941a840 100644 --- a/include/eepp/system/process.hpp +++ b/include/eepp/system/process.hpp @@ -3,8 +3,8 @@ #include #include +#include #include -#include #include #include #include @@ -49,7 +49,7 @@ class EE_API Process { /** @brief Create a process. ** @param command Command line to execute for this process. ** @param options A bit field of Options's to pass. */ - Process( const std::string& command, const Uint32& options = getDefaultOptions(), + Process( const std::string& command, Uint32 options = getDefaultOptions(), const std::unordered_map& environment = {}, const std::string& workingDirectory = "", const size_t& bufferSize = 132072 ); @@ -59,7 +59,7 @@ class EE_API Process { ** @param command Command line to execute for this process. ** @param options A bit field of Options's to pass. ** @return On success true is returned. */ - bool create( const std::string& command, const Uint32& options = getDefaultOptions(), + bool create( const std::string& command, Uint32 options = getDefaultOptions(), const std::unordered_map& environment = {}, const std::string& workingDirectory = "" ); @@ -69,7 +69,7 @@ class EE_API Process { ** @param options A bit field of Options's to pass. ** @return On success true is returned. */ bool create( const std::string& command, const std::string& args, - const Uint32& options = getDefaultOptions(), + Uint32 options = getDefaultOptions(), const std::unordered_map& environment = {}, const std::string& workingDirectory = "" ); @@ -84,7 +84,7 @@ class EE_API Process { ** The only safe way to read from the standard output of a process during it's ** execution is to use the `Option::EnableAsync` option in ** conjuction with this method. */ - size_t readAllStdOut( std::string& buffer ); + size_t readAllStdOut( std::string& buffer, Time timeout = Time::Zero ); /** @brief Read the standard output from the child process. ** @param buffer The buffer to read into. @@ -115,7 +115,7 @@ class EE_API Process { ** The only safe way to read from the standard error of a process during it's ** execution is to use the `Option::EnableAsync` option in ** conjuction with this method. */ - size_t readAllStdErr( std::string& buffer ); + size_t readAllStdErr( std::string& buffer, Time timeout = Time::Zero ); /** @brief Read the standard error from the child process. ** @param buffer The buffer to read into. @@ -216,7 +216,7 @@ class EE_API Process { ReadFn mReadStdOutFn; ReadFn mReadStdErrFn; - size_t readAll( std::string& buffer, bool readErr ); + size_t readAll( std::string& buffer, bool readErr, Time timeout = Time::Zero ); }; }} // namespace EE::System diff --git a/src/eepp/system/process.cpp b/src/eepp/system/process.cpp index 66bcfb5f6..059a4e633 100644 --- a/src/eepp/system/process.cpp +++ b/src/eepp/system/process.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -29,7 +30,7 @@ namespace EE { namespace System { Process::Process() {} -Process::Process( const std::string& command, const Uint32& options, +Process::Process( const std::string& command, Uint32 options, const std::unordered_map& environment, const std::string& workingDirectory, const size_t& bufferSize ) : mBufferSize( bufferSize ) { @@ -47,7 +48,7 @@ Process::~Process() { eeFree( mProcess ); } -bool Process::create( const std::string& command, const Uint32& options, +bool Process::create( const std::string& command, Uint32 options, const std::unordered_map& environment, const std::string& workingDirectory ) { if ( mProcess ) @@ -90,7 +91,7 @@ bool Process::create( const std::string& command, const Uint32& options, return ret; } -bool Process::create( const std::string& command, const std::string& args, const Uint32& options, +bool Process::create( const std::string& command, const std::string& args, Uint32 options, const std::unordered_map& environment, const std::string& workingDirectory ) { if ( mProcess ) @@ -140,8 +141,8 @@ bool Process::create( const std::string& command, const std::string& args, const return ret; } -size_t Process::readAllStdOut( std::string& buffer ) { - return readAll( buffer, false ); +size_t Process::readAllStdOut( std::string& buffer, Time timeout ) { + return readAll( buffer, false, timeout ); } size_t Process::readStdOut( std::string& buffer ) { @@ -153,8 +154,8 @@ size_t Process::readStdOut( char* const buffer, const size_t& size ) { return subprocess_read_stdout( PROCESS_PTR, buffer, size ); } -size_t Process::readAllStdErr( std::string& buffer ) { - return readAll( buffer, true ); +size_t Process::readAllStdErr( std::string& buffer, Time timeout ) { + return readAll( buffer, true, timeout ); } size_t Process::readStdErr( std::string& buffer ) { @@ -227,24 +228,31 @@ const bool& Process::isShuttingDown() { return mShuttingDown; } -size_t Process::readAll( std::string& buffer, bool readErr ) { +size_t Process::readAll( std::string& buffer, bool readErr, Time timeout ) { eeASSERT( mProcess != nullptr ); if ( buffer.empty() || buffer.size() < CHUNK_SIZE ) buffer.resize( CHUNK_SIZE ); size_t totalBytesRead = 0; + Clock clock; #if EE_PLATFORM == EE_PLATFORM_WIN while ( !mShuttingDown && isAlive() ) { unsigned n = readErr ? subprocess_read_stderr( PROCESS_PTR, buffer.data() + totalBytesRead, CHUNK_SIZE ) : subprocess_read_stdout( PROCESS_PTR, buffer.data() + totalBytesRead, CHUNK_SIZE ); - if ( n == 0 ) - break; + if ( n == 0 ) { + if ( timeout != Time::Zero && clock.getElapsedTime() >= timeout ) + break; + continue; + } totalBytesRead += n; if ( totalBytesRead + CHUNK_SIZE > buffer.size() ) buffer.resize( totalBytesRead + CHUNK_SIZE ); + clock.restart(); } #elif defined( EE_PLATFORM_POSIX ) + if ( !isAlive() ) + return 0; auto stdOutFd = fileno( readErr ? PROCESS_PTR->stderr_file : PROCESS_PTR->stdout_file ); pollfd pollfd = {}; pollfd.fd = @@ -255,9 +263,13 @@ size_t Process::readAll( std::string& buffer, bool readErr ) { ssize_t n = 0; while ( anyOpen && !mShuttingDown && isAlive() && errno != EINTR ) { int res = poll( &pollfd, static_cast( 1 ), 100 ); - if ( res <= 0 ) + if ( res <= 0 ) { + if ( timeout != Time::Zero && clock.getElapsedTime() >= timeout ) + break; continue; + } anyOpen = false; + clock.restart(); if ( pollfd.revents & POLLIN ) { n = read( pollfd.fd, buffer.data() + totalBytesRead, CHUNK_SIZE ); if ( n > 0 ) { diff --git a/src/eepp/window/backend/SDL2/windowsdl2.cpp b/src/eepp/window/backend/SDL2/windowsdl2.cpp index 5c84693ea..7a80efbe5 100644 --- a/src/eepp/window/backend/SDL2/windowsdl2.cpp +++ b/src/eepp/window/backend/SDL2/windowsdl2.cpp @@ -28,6 +28,7 @@ #endif #if EE_PLATFORM == EE_PLATFORM_WIN +#include #include #include #include diff --git a/src/tools/ecode/plugins/formatter/formatterplugin.cpp b/src/tools/ecode/plugins/formatter/formatterplugin.cpp index f72d29d11..ead302ef9 100644 --- a/src/tools/ecode/plugins/formatter/formatterplugin.cpp +++ b/src/tools/ecode/plugins/formatter/formatterplugin.cpp @@ -74,7 +74,7 @@ void FormatterPlugin::onRegister( UICodeEditor* editor ) { if ( editor->hasDocument() ) { editor->getDocument().setCommand( "format-doc", [this]( TextDocument::Client* client ) { - formatDoc( static_cast( client ) ); + formatDocAsync( static_cast( client ) ); } ); } @@ -99,7 +99,7 @@ void FormatterPlugin::onRegister( UICodeEditor* editor ) { mPluginManager && !String::startsWith( editor->getDocument().getFilePath(), mPluginManager->getPluginsPath() ) ) - formatDoc( editor ); + formatDocAsync( editor ); } } ) ); @@ -332,6 +332,10 @@ FormatterPlugin::Formatter FormatterPlugin::getFormatterForLang( const std::stri return {}; } +void FormatterPlugin::formatDocAsync( UICodeEditor* editor ) { + mThreadPool->run( [editor, this] { formatDoc( editor ); } ); +} + void FormatterPlugin::formatDoc( UICodeEditor* editor ) { ScopedOp op( [this]() { @@ -441,16 +445,14 @@ void FormatterPlugin::runFormatter( UICodeEditor* editor, const Formatter& forma String::replaceAll( cmd, "$FILENAME", "\"" + path + "\"" ); Process process; if ( process.create( cmd ) ) { - int returnCode; std::string data; - process.readAllStdOut( data ); + process.readAllStdOut( data, Seconds( 30 ) ); if ( mShuttingDown ) { process.kill(); return; } - process.join( &returnCode ); process.destroy(); // Log::info( "Formatter result:\n%s", data.c_str() ); diff --git a/src/tools/ecode/plugins/formatter/formatterplugin.hpp b/src/tools/ecode/plugins/formatter/formatterplugin.hpp index 31224b064..cc0d8ae8d 100644 --- a/src/tools/ecode/plugins/formatter/formatterplugin.hpp +++ b/src/tools/ecode/plugins/formatter/formatterplugin.hpp @@ -98,6 +98,8 @@ class FormatterPlugin : public Plugin { void formatDoc( UICodeEditor* editor ); + void formatDocAsync( UICodeEditor* editor ); + void runFormatter( UICodeEditor* editor, const Formatter& formatter, const std::string& path ); size_t formatterFilePatternPosition( const std::vector& patterns ); diff --git a/src/tools/ecode/plugins/linter/linterplugin.cpp b/src/tools/ecode/plugins/linter/linterplugin.cpp index 8e0d80189..d27a42645 100644 --- a/src/tools/ecode/plugins/linter/linterplugin.cpp +++ b/src/tools/ecode/plugins/linter/linterplugin.cpp @@ -812,7 +812,7 @@ void LinterPlugin::runLinter( std::shared_ptr doc, const Linter& l mManager->getWorkspaceFolder() ) ) { int returnCode; std::string data; - process.readAllStdOut( data ); + process.readAllStdOut( data, Seconds( 30 ) ); if ( mShuttingDown ) { process.kill();