diff options
Diffstat (limited to 'source')
| -rw-r--r-- | source/compiler-core/slang-json-rpc-connection.h | 9 | ||||
| -rw-r--r-- | source/core/slang-http.cpp | 49 | ||||
| -rw-r--r-- | source/core/unix/slang-unix-process.cpp | 16 |
3 files changed, 66 insertions, 8 deletions
diff --git a/source/compiler-core/slang-json-rpc-connection.h b/source/compiler-core/slang-json-rpc-connection.h index b566140ef..263baf799 100644 --- a/source/compiler-core/slang-json-rpc-connection.h +++ b/source/compiler-core/slang-json-rpc-connection.h @@ -130,8 +130,8 @@ public: JSONRPCConnection():m_container(nullptr) {} protected: - RefPtr<Slang::Process> m_process; ///< Backing process (optional) - RefPtr<Slang::HTTPPacketConnection> m_connection; ///< The underlying 'transport' connection, whilst HTTP currently doesn't have to be + RefPtr<Process> m_process; ///< Backing process (optional) + RefPtr<HTTPPacketConnection> m_connection; ///< The underlying 'transport' connection, whilst HTTP currently doesn't have to be DiagnosticSink m_diagnosticSink; ///< Holds any diagnostics typically generated by parsing JSON, producing JSON from native types @@ -140,10 +140,7 @@ protected: JSONValue m_jsonRoot; ///< The root JSON value for the currently read message. - /// Default timeout is 10 seconds - Int m_timeOutInMs = 10 * 1000; - /// Termination timeout - Int m_terminationTimeOutInMs = 1 * 1000; + Int m_terminationTimeOutInMs = 1 * 1000; ///< Time to wait for termination response. Default is 1 second }; // --------------------------------------------------------------------------- diff --git a/source/core/slang-http.cpp b/source/core/slang-http.cpp index 6a4bb4f92..bb5994635 100644 --- a/source/core/slang-http.cpp +++ b/source/core/slang-http.cpp @@ -287,6 +287,46 @@ SlangResult HTTPPacketConnection::update() return m_readResult; } + +namespace { // anonymous + +// Handles binary backoff like sleeping mechanism. +struct SleepState +{ + void sleep() + { + Process::sleepCurrentThread(m_intervalInMs); + _update(); + } + void reset() + { + m_intervalInMs = 0; + m_count = 0; + } + void _update() + { + const Int maxIntervalInMs = 32; + const Int initialCountThreshold = 4; + + ++m_count; + + const Int countThreshold = (m_intervalInMs == 0) ? initialCountThreshold : 1; + + // If we hit the count change the interval + if (m_count >= countThreshold) + { + m_intervalInMs = (m_intervalInMs == 0) ? 1 : Math::Min(m_intervalInMs * 2, maxIntervalInMs); + // Reset the count + m_count = 0; + } + } + + Int m_intervalInMs = 0; + Int m_count = 0; +}; + +} // anonymous + SlangResult HTTPPacketConnection::waitForResult(Int timeOutInMs) { m_readResult = SLANG_OK; @@ -300,6 +340,8 @@ SlangResult HTTPPacketConnection::waitForResult(Int timeOutInMs) startTick = Process::getClockTick(); } + SleepState sleepState; + while (m_readState == ReadState::Header || m_readState == ReadState::Content) { @@ -320,8 +362,11 @@ SlangResult HTTPPacketConnection::waitForResult(Int timeOutInMs) if (prevCount == m_readStream->getCount()) { - // Yield if it appears nothing was read. - Process::sleepCurrentThread(0); + sleepState.sleep(); + } + else + { + sleepState.reset(); } } diff --git a/source/core/unix/slang-unix-process.cpp b/source/core/unix/slang-unix-process.cpp index 5131e37ec..4e8344486 100644 --- a/source/core/unix/slang-unix-process.cpp +++ b/source/core/unix/slang-unix-process.cpp @@ -349,6 +349,8 @@ SlangResult UnixPipeStream::write(const void* buffer, size_t length) return StringEscapeUtil::getHandler(StringEscapeUtil::Style::Space); } +static const int kCannotExecute = 126; + /* static */SlangResult Process::create(const CommandLine& commandLine, Process::Flags flags, RefPtr<Process>& outProcess) { List<char const*> argPtrs; @@ -376,6 +378,12 @@ SlangResult UnixPipeStream::write(const void* buffer, size_t length) return SLANG_FAIL; } + // TODO(JS): + // Ideally we'd have a mechanism to test if execvp can be successfully executed (at least in principal) before + // doing fork. Once we have forked we then have the problem of communicating to the parent process somehow. + // + // We could do a search down PATH and test files etc, but this seems to repeat a lot of the functionality of exec. + // pid_t childPid = fork(); if (childPid == -1) { @@ -402,6 +410,11 @@ SlangResult UnixPipeStream::write(const void* buffer, size_t length) ::close(stdinPipe[0]); ::close(stdinPipe[1]); + // TODO(JS): Strictly speaking if m_executableType is 'Path' then we shouldn't be searching. Ie which + // exec we use here should be dependent on the executable type. + + // Path = execvp + // Filename = execv ::execvp(argPtrs[0], (char* const*)&argPtrs[0]); // If we get here, then `exec` failed @@ -410,6 +423,9 @@ SlangResult UnixPipeStream::write(const void* buffer, size_t length) // the terminal but in the stderrPipe. fprintf(stderr, "error: `exec` failed\n"); + // Terminate with failure. + exit(kCannotExecute); + return SLANG_FAIL; } else |
