| /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying | |
| file LICENSE.rst or https://cmake.org/licensing for details. */ | |
| #include "cmUVProcessChain.h" | |
| #include <array> | |
| #include <csignal> | |
| #include <cstdio> | |
| #include <istream> // IWYU pragma: keep | |
| #include <utility> | |
| #include <cm/memory> | |
| #include <cm3p/uv.h> | |
| #include "cmsys/Process.h" | |
| #include "cm_fileno.hxx" | |
| #include "cmGetPipes.h" | |
| #include "cmUVHandlePtr.h" | |
| struct cmUVProcessChain::InternalData | |
| { | |
| struct StreamData | |
| { | |
| cm::uv_pipe_ptr BuiltinStream; | |
| uv_stdio_container_t Stdio; | |
| }; | |
| struct ProcessData | |
| { | |
| cmUVProcessChain::InternalData* Data; | |
| cm::uv_process_ptr Process; | |
| cm::uv_pipe_ptr InputPipe; | |
| cm::uv_pipe_ptr OutputPipe; | |
| Status ProcessStatus; | |
| void Finish(); | |
| }; | |
| cmUVProcessChainBuilder const* Builder = nullptr; | |
| bool Valid = false; | |
| cm::uv_loop_ptr BuiltinLoop; | |
| uv_loop_t* Loop; | |
| StreamData InputStreamData; | |
| StreamData OutputStreamData; | |
| StreamData ErrorStreamData; | |
| cm::uv_pipe_ptr TempOutputPipe; | |
| cm::uv_pipe_ptr TempErrorPipe; | |
| unsigned int ProcessesCompleted = 0; | |
| std::vector<std::unique_ptr<ProcessData>> Processes; | |
| bool Prepare(cmUVProcessChainBuilder const* builder); | |
| void SpawnProcess( | |
| std::size_t index, | |
| cmUVProcessChainBuilder::ProcessConfiguration const& config, bool first, | |
| bool last); | |
| void Finish(); | |
| void Terminate(); | |
| }; | |
| cmUVProcessChainBuilder::cmUVProcessChainBuilder() = default; | |
| cmUVProcessChainBuilder& cmUVProcessChainBuilder::AddCommand( | |
| std::vector<std::string> arguments) | |
| { | |
| if (!arguments.empty()) { | |
| this->Processes.emplace_back(); | |
| this->Processes.back().Arguments = std::move(arguments); | |
| } | |
| return *this; | |
| } | |
| cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetBuiltinLoop() | |
| { | |
| this->Loop = nullptr; | |
| return *this; | |
| } | |
| cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetExternalLoop( | |
| uv_loop_t& loop) | |
| { | |
| this->Loop = &loop; | |
| return *this; | |
| } | |
| cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetNoStream(Stream stdio) | |
| { | |
| switch (stdio) { | |
| case Stream_INPUT: | |
| case Stream_OUTPUT: | |
| case Stream_ERROR: { | |
| auto& streamData = this->Stdio[stdio]; | |
| streamData.Type = None; | |
| break; | |
| } | |
| } | |
| return *this; | |
| } | |
| cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetBuiltinStream( | |
| Stream stdio) | |
| { | |
| switch (stdio) { | |
| case Stream_INPUT: | |
| // FIXME | |
| break; | |
| case Stream_OUTPUT: | |
| case Stream_ERROR: { | |
| auto& streamData = this->Stdio[stdio]; | |
| streamData.Type = Builtin; | |
| break; | |
| } | |
| } | |
| return *this; | |
| } | |
| cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetExternalStream( | |
| Stream stdio, int fd) | |
| { | |
| switch (stdio) { | |
| case Stream_INPUT: | |
| case Stream_OUTPUT: | |
| case Stream_ERROR: { | |
| auto& streamData = this->Stdio[stdio]; | |
| streamData.Type = External; | |
| streamData.FileDescriptor = fd; | |
| break; | |
| } | |
| } | |
| return *this; | |
| } | |
| cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetExternalStream( | |
| Stream stdio, FILE* stream) | |
| { | |
| int fd = cm_fileno(stream); | |
| if (fd >= 0) { | |
| return this->SetExternalStream(stdio, fd); | |
| } | |
| return this->SetNoStream(stdio); | |
| } | |
| cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetMergedBuiltinStreams() | |
| { | |
| this->MergedBuiltinStreams = true; | |
| return this->SetBuiltinStream(Stream_OUTPUT).SetBuiltinStream(Stream_ERROR); | |
| } | |
| cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetWorkingDirectory( | |
| std::string dir) | |
| { | |
| this->WorkingDirectory = std::move(dir); | |
| return *this; | |
| } | |
| cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetEnvironment( | |
| std::vector<std::string> env) | |
| { | |
| this->Environment = std::move(env); | |
| return *this; | |
| } | |
| cmUVProcessChainBuilder& cmUVProcessChainBuilder::SetDetached() | |
| { | |
| this->Detached = true; | |
| return *this; | |
| } | |
| uv_loop_t* cmUVProcessChainBuilder::GetLoop() const | |
| { | |
| return this->Loop; | |
| } | |
| cmUVProcessChain cmUVProcessChainBuilder::Start() const | |
| { | |
| cmUVProcessChain chain; | |
| if (!chain.Data->Prepare(this)) { | |
| return chain; | |
| } | |
| for (std::size_t i = 0; i < this->Processes.size(); i++) { | |
| chain.Data->SpawnProcess(i, this->Processes[i], i == 0, | |
| i == this->Processes.size() - 1); | |
| } | |
| chain.Data->Finish(); | |
| return chain; | |
| } | |
| bool cmUVProcessChain::InternalData::Prepare( | |
| cmUVProcessChainBuilder const* builder) | |
| { | |
| this->Builder = builder; | |
| if (this->Builder->Loop) { | |
| this->Loop = this->Builder->Loop; | |
| } else { | |
| this->BuiltinLoop.init(); | |
| this->Loop = this->BuiltinLoop; | |
| } | |
| auto const& input = | |
| this->Builder->Stdio[cmUVProcessChainBuilder::Stream_INPUT]; | |
| auto& inputData = this->InputStreamData; | |
| switch (input.Type) { | |
| case cmUVProcessChainBuilder::None: | |
| inputData.Stdio.flags = UV_IGNORE; | |
| break; | |
| case cmUVProcessChainBuilder::Builtin: { | |
| // FIXME | |
| break; | |
| } | |
| case cmUVProcessChainBuilder::External: | |
| inputData.Stdio.flags = UV_INHERIT_FD; | |
| inputData.Stdio.data.fd = input.FileDescriptor; | |
| break; | |
| } | |
| auto const& output = | |
| this->Builder->Stdio[cmUVProcessChainBuilder::Stream_OUTPUT]; | |
| auto& outputData = this->OutputStreamData; | |
| switch (output.Type) { | |
| case cmUVProcessChainBuilder::None: | |
| outputData.Stdio.flags = UV_IGNORE; | |
| break; | |
| case cmUVProcessChainBuilder::Builtin: { | |
| int pipeFd[2]; | |
| if (cmGetPipes(pipeFd) < 0) { | |
| return false; | |
| } | |
| if (outputData.BuiltinStream.init(*this->Loop, 0) < 0) { | |
| return false; | |
| } | |
| if (uv_pipe_open(outputData.BuiltinStream, pipeFd[0]) < 0) { | |
| return false; | |
| } | |
| if (this->TempOutputPipe.init(*this->Loop, 0) < 0) { | |
| return false; | |
| } | |
| if (uv_pipe_open(this->TempOutputPipe, pipeFd[1]) < 0) { | |
| return false; | |
| } | |
| outputData.Stdio.flags = UV_INHERIT_FD; | |
| outputData.Stdio.data.fd = pipeFd[1]; | |
| } break; | |
| case cmUVProcessChainBuilder::External: | |
| outputData.Stdio.flags = UV_INHERIT_FD; | |
| outputData.Stdio.data.fd = output.FileDescriptor; | |
| break; | |
| } | |
| auto const& error = | |
| this->Builder->Stdio[cmUVProcessChainBuilder::Stream_ERROR]; | |
| auto& errorData = this->ErrorStreamData; | |
| switch (error.Type) { | |
| case cmUVProcessChainBuilder::None: | |
| errorData.Stdio.flags = UV_IGNORE; | |
| break; | |
| case cmUVProcessChainBuilder::Builtin: { | |
| if (this->Builder->MergedBuiltinStreams) { | |
| errorData.Stdio.flags = UV_INHERIT_FD; | |
| errorData.Stdio.data.fd = outputData.Stdio.data.fd; | |
| } else { | |
| int pipeFd[2]; | |
| if (cmGetPipes(pipeFd) < 0) { | |
| return false; | |
| } | |
| if (errorData.BuiltinStream.init(*this->Loop, 0) < 0) { | |
| return false; | |
| } | |
| if (uv_pipe_open(errorData.BuiltinStream, pipeFd[0]) < 0) { | |
| return false; | |
| } | |
| if (this->TempErrorPipe.init(*this->Loop, 0) < 0) { | |
| return false; | |
| } | |
| if (uv_pipe_open(this->TempErrorPipe, pipeFd[1]) < 0) { | |
| return false; | |
| } | |
| errorData.Stdio.flags = UV_INHERIT_FD; | |
| errorData.Stdio.data.fd = pipeFd[1]; | |
| } | |
| } break; | |
| case cmUVProcessChainBuilder::External: | |
| errorData.Stdio.flags = UV_INHERIT_FD; | |
| errorData.Stdio.data.fd = error.FileDescriptor; | |
| break; | |
| } | |
| bool first = true; | |
| for (std::size_t i = 0; i < this->Builder->Processes.size(); i++) { | |
| this->Processes.emplace_back(cm::make_unique<ProcessData>()); | |
| auto& process = *this->Processes.back(); | |
| process.Data = this; | |
| process.ProcessStatus.Finished = false; | |
| if (!first) { | |
| auto& prevProcess = *this->Processes[i - 1]; | |
| int pipeFd[2]; | |
| if (cmGetPipes(pipeFd) < 0) { | |
| return false; | |
| } | |
| if (prevProcess.OutputPipe.init(*this->Loop, 0) < 0) { | |
| return false; | |
| } | |
| if (uv_pipe_open(prevProcess.OutputPipe, pipeFd[1]) < 0) { | |
| return false; | |
| } | |
| if (process.InputPipe.init(*this->Loop, 0) < 0) { | |
| return false; | |
| } | |
| if (uv_pipe_open(process.InputPipe, pipeFd[0]) < 0) { | |
| return false; | |
| } | |
| } | |
| first = false; | |
| } | |
| return true; | |
| } | |
| void cmUVProcessChain::InternalData::SpawnProcess( | |
| std::size_t index, | |
| cmUVProcessChainBuilder::ProcessConfiguration const& config, bool first, | |
| bool last) | |
| { | |
| auto& process = *this->Processes[index]; | |
| auto options = uv_process_options_t(); | |
| // Bounds were checked at add time, first element is guaranteed to exist | |
| options.file = config.Arguments[0].c_str(); | |
| std::vector<char const*> arguments; | |
| arguments.reserve(config.Arguments.size()); | |
| for (auto const& arg : config.Arguments) { | |
| arguments.push_back(arg.c_str()); | |
| } | |
| arguments.push_back(nullptr); | |
| options.args = const_cast<char**>(arguments.data()); | |
| options.flags = UV_PROCESS_WINDOWS_HIDE; | |
| if (this->Builder->Detached) { | |
| options.flags |= UV_PROCESS_DETACHED; | |
| } | |
| #if UV_VERSION_MAJOR > 1 || \ | |
| (UV_VERSION_MAJOR == 1 && UV_VERSION_MINOR >= 48) || \ | |
| !defined(CMAKE_USE_SYSTEM_LIBUV) | |
| options.flags |= UV_PROCESS_WINDOWS_FILE_PATH_EXACT_NAME; | |
| #endif | |
| #if UV_VERSION_MAJOR > 1 || !defined(CMAKE_USE_SYSTEM_LIBUV) | |
| options.flags |= UV_PROCESS_WINDOWS_USE_PARENT_ERROR_MODE; | |
| #endif | |
| if (!this->Builder->WorkingDirectory.empty()) { | |
| options.cwd = this->Builder->WorkingDirectory.c_str(); | |
| } | |
| auto env = std::vector<char const*>{}; | |
| if (!this->Builder->Environment.empty()) { | |
| env.reserve(this->Builder->Environment.size() + 1); | |
| for (auto const& var : this->Builder->Environment) { | |
| env.push_back(var.c_str()); | |
| } | |
| env.push_back(nullptr); | |
| options.env = const_cast<char**>(env.data()); | |
| } | |
| std::array<uv_stdio_container_t, 3> stdio; | |
| if (first) { | |
| stdio[0] = this->InputStreamData.Stdio; | |
| } else { | |
| stdio[0] = uv_stdio_container_t(); | |
| stdio[0].flags = UV_INHERIT_STREAM; | |
| stdio[0].data.stream = process.InputPipe; | |
| } | |
| if (last) { | |
| stdio[1] = this->OutputStreamData.Stdio; | |
| } else { | |
| stdio[1] = uv_stdio_container_t(); | |
| stdio[1].flags = UV_INHERIT_STREAM; | |
| stdio[1].data.stream = process.OutputPipe; | |
| } | |
| stdio[2] = this->ErrorStreamData.Stdio; | |
| options.stdio = stdio.data(); | |
| options.stdio_count = 3; | |
| options.exit_cb = [](uv_process_t* handle, int64_t exitStatus, | |
| int termSignal) { | |
| auto* processData = static_cast<ProcessData*>(handle->data); | |
| processData->ProcessStatus.ExitStatus = exitStatus; | |
| processData->ProcessStatus.TermSignal = termSignal; | |
| processData->Finish(); | |
| }; | |
| if ((process.ProcessStatus.SpawnResult = | |
| process.Process.spawn(*this->Loop, options, &process)) < 0) { | |
| process.Finish(); | |
| } | |
| if (this->Builder->Detached) { | |
| uv_unref((uv_handle_t*)process.Process); | |
| } | |
| process.InputPipe.reset(); | |
| process.OutputPipe.reset(); | |
| } | |
| void cmUVProcessChain::InternalData::Finish() | |
| { | |
| this->TempOutputPipe.reset(); | |
| this->TempErrorPipe.reset(); | |
| this->Valid = true; | |
| } | |
| void cmUVProcessChain::InternalData::Terminate() | |
| { | |
| for (std::unique_ptr<ProcessData> const& p : this->Processes) { | |
| if (!p->ProcessStatus.Finished) { | |
| cmsysProcess_KillPID(static_cast<unsigned long>(p->Process->pid)); | |
| } | |
| } | |
| } | |
| cmUVProcessChain::cmUVProcessChain() | |
| : Data(cm::make_unique<InternalData>()) | |
| { | |
| } | |
| cmUVProcessChain::cmUVProcessChain(cmUVProcessChain&& other) noexcept | |
| : Data(std::move(other.Data)) | |
| { | |
| } | |
| cmUVProcessChain::~cmUVProcessChain() = default; | |
| cmUVProcessChain& cmUVProcessChain::operator=( | |
| cmUVProcessChain&& other) noexcept | |
| { | |
| this->Data = std::move(other.Data); | |
| return *this; | |
| } | |
| uv_loop_t& cmUVProcessChain::GetLoop() | |
| { | |
| return *this->Data->Loop; | |
| } | |
| uv_stream_t* cmUVProcessChain::OutputStream() | |
| { | |
| return this->Data->OutputStreamData.BuiltinStream; | |
| } | |
| uv_stream_t* cmUVProcessChain::ErrorStream() | |
| { | |
| return this->Data->ErrorStreamData.BuiltinStream; | |
| } | |
| bool cmUVProcessChain::Valid() const | |
| { | |
| return this->Data->Valid; | |
| } | |
| bool cmUVProcessChain::Wait(uint64_t milliseconds) | |
| { | |
| bool timeout = false; | |
| cm::uv_timer_ptr timer; | |
| if (milliseconds > 0) { | |
| timer.init(*this->Data->Loop, &timeout); | |
| timer.start( | |
| [](uv_timer_t* handle) { | |
| auto* timeoutPtr = static_cast<bool*>(handle->data); | |
| *timeoutPtr = true; | |
| }, | |
| milliseconds, 0, cm::uv_update_time::yes); | |
| } | |
| while (!timeout && | |
| this->Data->ProcessesCompleted < this->Data->Processes.size()) { | |
| uv_run(this->Data->Loop, UV_RUN_ONCE); | |
| } | |
| return !timeout; | |
| } | |
| std::vector<cmUVProcessChain::Status const*> cmUVProcessChain::GetStatus() | |
| const | |
| { | |
| std::vector<cmUVProcessChain::Status const*> statuses( | |
| this->Data->Processes.size(), nullptr); | |
| for (std::size_t i = 0; i < statuses.size(); i++) { | |
| statuses[i] = &this->GetStatus(i); | |
| } | |
| return statuses; | |
| } | |
| cmUVProcessChain::Status const& cmUVProcessChain::GetStatus( | |
| std::size_t index) const | |
| { | |
| return this->Data->Processes[index]->ProcessStatus; | |
| } | |
| bool cmUVProcessChain::Finished() const | |
| { | |
| return this->Data->ProcessesCompleted >= this->Data->Processes.size(); | |
| } | |
| void* cmUVProcessChain::GetNativeProcessHandle(std::size_t index) const | |
| { | |
| if (index >= this->Data->Processes.size()) { | |
| return nullptr; | |
| } | |
| #ifdef _WIN32 | |
| return this->Data->Processes[index]->Process->process_handle; | |
| #else | |
| static_cast<void>(index); | |
| return nullptr; | |
| #endif | |
| } | |
| void cmUVProcessChain::Terminate() | |
| { | |
| this->Data->Terminate(); | |
| } | |
| std::pair<cmUVProcessChain::ExceptionCode, std::string> | |
| cmUVProcessChain::Status::GetException() const | |
| { | |
| if (this->SpawnResult) { | |
| return std::make_pair(ExceptionCode::Spawn, | |
| uv_strerror(this->SpawnResult)); | |
| } | |
| #ifdef _WIN32 | |
| if (this->Finished && (this->ExitStatus & 0xF0000000) == 0xC0000000) { | |
| // Child terminated due to exceptional behavior. | |
| switch (this->ExitStatus) { | |
| case STATUS_CONTROL_C_EXIT: | |
| return std::make_pair(ExceptionCode::Interrupt, "User interrupt"); | |
| case STATUS_FLOAT_DENORMAL_OPERAND: | |
| return std::make_pair(ExceptionCode::Numerical, | |
| "Floating-point exception (denormal operand)"); | |
| case STATUS_FLOAT_DIVIDE_BY_ZERO: | |
| return std::make_pair(ExceptionCode::Numerical, "Divide-by-zero"); | |
| case STATUS_FLOAT_INEXACT_RESULT: | |
| return std::make_pair(ExceptionCode::Numerical, | |
| "Floating-point exception (inexact result)"); | |
| case STATUS_FLOAT_INVALID_OPERATION: | |
| return std::make_pair(ExceptionCode::Numerical, | |
| "Invalid floating-point operation"); | |
| case STATUS_FLOAT_OVERFLOW: | |
| return std::make_pair(ExceptionCode::Numerical, | |
| "Floating-point overflow"); | |
| case STATUS_FLOAT_STACK_CHECK: | |
| return std::make_pair(ExceptionCode::Numerical, | |
| "Floating-point stack check failed"); | |
| case STATUS_FLOAT_UNDERFLOW: | |
| return std::make_pair(ExceptionCode::Numerical, | |
| "Floating-point underflow"); | |
| # ifdef STATUS_FLOAT_MULTIPLE_FAULTS | |
| case STATUS_FLOAT_MULTIPLE_FAULTS: | |
| return std::make_pair(ExceptionCode::Numerical, | |
| "Floating-point exception (multiple faults)"); | |
| # endif | |
| # ifdef STATUS_FLOAT_MULTIPLE_TRAPS | |
| case STATUS_FLOAT_MULTIPLE_TRAPS: | |
| return std::make_pair(ExceptionCode::Numerical, | |
| "Floating-point exception (multiple traps)"); | |
| # endif | |
| case STATUS_INTEGER_DIVIDE_BY_ZERO: | |
| return std::make_pair(ExceptionCode::Numerical, | |
| "Integer divide-by-zero"); | |
| case STATUS_INTEGER_OVERFLOW: | |
| return std::make_pair(ExceptionCode::Numerical, "Integer overflow"); | |
| case STATUS_DATATYPE_MISALIGNMENT: | |
| return std::make_pair(ExceptionCode::Fault, "Datatype misalignment"); | |
| case STATUS_ACCESS_VIOLATION: | |
| return std::make_pair(ExceptionCode::Fault, "Access violation"); | |
| case STATUS_IN_PAGE_ERROR: | |
| return std::make_pair(ExceptionCode::Fault, "In-page error"); | |
| case STATUS_INVALID_HANDLE: | |
| return std::make_pair(ExceptionCode::Fault, "Invalid handle"); | |
| case STATUS_NONCONTINUABLE_EXCEPTION: | |
| return std::make_pair(ExceptionCode::Fault, | |
| "Noncontinuable exception"); | |
| case STATUS_INVALID_DISPOSITION: | |
| return std::make_pair(ExceptionCode::Fault, "Invalid disposition"); | |
| case STATUS_ARRAY_BOUNDS_EXCEEDED: | |
| return std::make_pair(ExceptionCode::Fault, "Array bounds exceeded"); | |
| case STATUS_STACK_OVERFLOW: | |
| return std::make_pair(ExceptionCode::Fault, "Stack overflow"); | |
| case STATUS_ILLEGAL_INSTRUCTION: | |
| return std::make_pair(ExceptionCode::Illegal, "Illegal instruction"); | |
| case STATUS_PRIVILEGED_INSTRUCTION: | |
| return std::make_pair(ExceptionCode::Illegal, | |
| "Privileged instruction"); | |
| case STATUS_NO_MEMORY: | |
| default: { | |
| char buf[256]; | |
| snprintf(buf, sizeof(buf), "Exit code 0x%x", | |
| static_cast<unsigned int>(this->ExitStatus)); | |
| return std::make_pair(ExceptionCode::Other, buf); | |
| } | |
| } | |
| } | |
| #else | |
| if (this->Finished && this->TermSignal) { | |
| switch (this->TermSignal) { | |
| # ifdef SIGSEGV | |
| case SIGSEGV: | |
| return std::make_pair(ExceptionCode::Fault, "Segmentation fault"); | |
| # endif | |
| # ifdef SIGBUS | |
| # if !defined(SIGSEGV) || SIGBUS != SIGSEGV | |
| case SIGBUS: | |
| return std::make_pair(ExceptionCode::Fault, "Bus error"); | |
| # endif | |
| # endif | |
| # ifdef SIGFPE | |
| case SIGFPE: | |
| return std::make_pair(ExceptionCode::Numerical, | |
| "Floating-point exception"); | |
| # endif | |
| # ifdef SIGILL | |
| case SIGILL: | |
| return std::make_pair(ExceptionCode::Illegal, "Illegal instruction"); | |
| # endif | |
| # ifdef SIGINT | |
| case SIGINT: | |
| return std::make_pair(ExceptionCode::Interrupt, "User interrupt"); | |
| # endif | |
| # ifdef SIGABRT | |
| case SIGABRT: | |
| return std::make_pair(ExceptionCode::Other, "Subprocess aborted"); | |
| # endif | |
| # ifdef SIGKILL | |
| case SIGKILL: | |
| return std::make_pair(ExceptionCode::Other, "Subprocess killed"); | |
| # endif | |
| # ifdef SIGTERM | |
| case SIGTERM: | |
| return std::make_pair(ExceptionCode::Other, "Subprocess terminated"); | |
| # endif | |
| # ifdef SIGHUP | |
| case SIGHUP: | |
| return std::make_pair(ExceptionCode::Other, "SIGHUP"); | |
| # endif | |
| # ifdef SIGQUIT | |
| case SIGQUIT: | |
| return std::make_pair(ExceptionCode::Other, "SIGQUIT"); | |
| # endif | |
| # ifdef SIGTRAP | |
| case SIGTRAP: | |
| return std::make_pair(ExceptionCode::Other, "SIGTRAP"); | |
| # endif | |
| # ifdef SIGIOT | |
| # if !defined(SIGABRT) || SIGIOT != SIGABRT | |
| case SIGIOT: | |
| return std::make_pair(ExceptionCode::Other, "SIGIOT"); | |
| # endif | |
| # endif | |
| # ifdef SIGUSR1 | |
| case SIGUSR1: | |
| return std::make_pair(ExceptionCode::Other, "SIGUSR1"); | |
| # endif | |
| # ifdef SIGUSR2 | |
| case SIGUSR2: | |
| return std::make_pair(ExceptionCode::Other, "SIGUSR2"); | |
| # endif | |
| # ifdef SIGPIPE | |
| case SIGPIPE: | |
| return std::make_pair(ExceptionCode::Other, "SIGPIPE"); | |
| # endif | |
| # ifdef SIGALRM | |
| case SIGALRM: | |
| return std::make_pair(ExceptionCode::Other, "SIGALRM"); | |
| # endif | |
| # ifdef SIGSTKFLT | |
| case SIGSTKFLT: | |
| return std::make_pair(ExceptionCode::Other, "SIGSTKFLT"); | |
| # endif | |
| # ifdef SIGCHLD | |
| case SIGCHLD: | |
| return std::make_pair(ExceptionCode::Other, "SIGCHLD"); | |
| # elif defined(SIGCLD) | |
| case SIGCLD: | |
| return std::make_pair(ExceptionCode::Other, "SIGCLD"); | |
| # endif | |
| # ifdef SIGCONT | |
| case SIGCONT: | |
| return std::make_pair(ExceptionCode::Other, "SIGCONT"); | |
| # endif | |
| # ifdef SIGSTOP | |
| case SIGSTOP: | |
| return std::make_pair(ExceptionCode::Other, "SIGSTOP"); | |
| # endif | |
| # ifdef SIGTSTP | |
| case SIGTSTP: | |
| return std::make_pair(ExceptionCode::Other, "SIGTSTP"); | |
| # endif | |
| # ifdef SIGTTIN | |
| case SIGTTIN: | |
| return std::make_pair(ExceptionCode::Other, "SIGTTIN"); | |
| # endif | |
| # ifdef SIGTTOU | |
| case SIGTTOU: | |
| return std::make_pair(ExceptionCode::Other, "SIGTTOU"); | |
| # endif | |
| # ifdef SIGURG | |
| case SIGURG: | |
| return std::make_pair(ExceptionCode::Other, "SIGURG"); | |
| # endif | |
| # ifdef SIGXCPU | |
| case SIGXCPU: | |
| return std::make_pair(ExceptionCode::Other, "SIGXCPU"); | |
| # endif | |
| # ifdef SIGXFSZ | |
| case SIGXFSZ: | |
| return std::make_pair(ExceptionCode::Other, "SIGXFSZ"); | |
| # endif | |
| # ifdef SIGVTALRM | |
| case SIGVTALRM: | |
| return std::make_pair(ExceptionCode::Other, "SIGVTALRM"); | |
| # endif | |
| # ifdef SIGPROF | |
| case SIGPROF: | |
| return std::make_pair(ExceptionCode::Other, "SIGPROF"); | |
| # endif | |
| # ifdef SIGWINCH | |
| case SIGWINCH: | |
| return std::make_pair(ExceptionCode::Other, "SIGWINCH"); | |
| # endif | |
| # ifdef SIGPOLL | |
| case SIGPOLL: | |
| return std::make_pair(ExceptionCode::Other, "SIGPOLL"); | |
| # endif | |
| # ifdef SIGIO | |
| # if !defined(SIGPOLL) || SIGIO != SIGPOLL | |
| case SIGIO: | |
| return std::make_pair(ExceptionCode::Other, "SIGIO"); | |
| # endif | |
| # endif | |
| # ifdef SIGPWR | |
| case SIGPWR: | |
| return std::make_pair(ExceptionCode::Other, "SIGPWR"); | |
| # endif | |
| # ifdef SIGSYS | |
| case SIGSYS: | |
| return std::make_pair(ExceptionCode::Other, "SIGSYS"); | |
| # endif | |
| # ifdef SIGUNUSED | |
| # if !defined(SIGSYS) || SIGUNUSED != SIGSYS | |
| case SIGUNUSED: | |
| return std::make_pair(ExceptionCode::Other, "SIGUNUSED"); | |
| # endif | |
| # endif | |
| default: { | |
| char buf[256]; | |
| snprintf(buf, sizeof(buf), "Signal %d", this->TermSignal); | |
| return std::make_pair(ExceptionCode::Other, buf); | |
| } | |
| } | |
| } | |
| #endif | |
| return std::make_pair(ExceptionCode::None, ""); | |
| } | |
| void cmUVProcessChain::InternalData::ProcessData::Finish() | |
| { | |
| this->ProcessStatus.Finished = true; | |
| this->Data->ProcessesCompleted++; | |
| } |