Skip to content

Commit 1255072

Browse files
committed
refs qorelanguage/qore#4272 fixed issues related to returning the process status with already-terminated processes; addressed exception-handling issues
1 parent 74ca8fb commit 1255072

File tree

3 files changed

+99
-79
lines changed

3 files changed

+99
-79
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ option(USE_INTERNAL_BOOST "Enforce using internal copy of boost libraries" OFF)
88

99
set (VERSION_MAJOR 1)
1010
set (VERSION_MINOR 0)
11-
set (VERSION_PATCH 0)
11+
set (VERSION_PATCH 1)
1212

1313
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
1414
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake )

src/process.qpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt)
5353

5454
@section process_relnotes Process Module Release History
5555

56+
@subsection process_v1_0_1 process v1.0.1
57+
- fixed bugs handling retrieving process status for already-terminated processes; addressed exception handling
58+
issues
59+
(<a href="https://github.com/qorelanguage/qore/issues/4272">issue 4272</a>)
60+
5661
@subsection process_v1_0_0 process v1.0.0
5762
- added:
5863
- @ref Qore::Process::Process::readStdoutBinary() "Process::readStdoutBinary()"

src/processpriv.cpp

Lines changed: 93 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
Qore Programming Language process Module
33
4-
Copyright (C) 2003 - 2020 Qore Technologies, s.r.o.
4+
Copyright (C) 2003 - 2021 Qore Technologies, s.r.o.
55
66
Permission is hereby granted, free of charge, to any person obtaining a
77
copy of this software and associated documentation files (the "Software"),
@@ -46,18 +46,18 @@ DLLLOCAL extern const TypedHashDecl* hashdeclMemorySummaryInfo;
4646
static int page_size = sysconf(_SC_PAGESIZE);
4747

4848
ProcessPriv::ProcessPriv(pid_t pid, ExceptionSink* xsink) :
49-
m_asio_ctx(),
50-
m_in_pipe(m_asio_ctx),
51-
m_out_pipe(m_asio_ctx),
52-
m_err_pipe(m_asio_ctx),
53-
54-
m_in_buf(&bg_xsink),
55-
m_out_buf(&bg_xsink),
56-
m_err_buf(&bg_xsink),
57-
58-
m_in_asiobuf(boost::asio::buffer(m_in_vec)),
59-
m_out_asiobuf(boost::asio::buffer(m_out_vec)),
60-
m_err_asiobuf(boost::asio::buffer(m_err_vec)) {
49+
m_asio_ctx(),
50+
m_in_pipe(m_asio_ctx),
51+
m_out_pipe(m_asio_ctx),
52+
m_err_pipe(m_asio_ctx),
53+
54+
m_in_buf(&bg_xsink),
55+
m_out_buf(&bg_xsink),
56+
m_err_buf(&bg_xsink),
57+
58+
m_in_asiobuf(boost::asio::buffer(m_in_vec)),
59+
m_out_asiobuf(boost::asio::buffer(m_out_vec)),
60+
m_err_asiobuf(boost::asio::buffer(m_err_vec)) {
6161
try {
6262
int i = boost::numeric_cast<int>(pid);
6363
m_process = new bp::child(i);
@@ -70,21 +70,21 @@ ProcessPriv::ProcessPriv(pid_t pid, ExceptionSink* xsink) :
7070
static constexpr unsigned process_buf_size = 4096;
7171

7272
ProcessPriv::ProcessPriv(const char* command, const QoreListNode* arguments, const QoreHashNode *opts, ExceptionSink* xsink) :
73-
m_asio_ctx(),
74-
m_in_pipe(m_asio_ctx),
75-
m_out_pipe(m_asio_ctx),
76-
m_err_pipe(m_asio_ctx),
73+
m_asio_ctx(),
74+
m_in_pipe(m_asio_ctx),
75+
m_out_pipe(m_asio_ctx),
76+
m_err_pipe(m_asio_ctx),
7777

78-
m_in_buf(&bg_xsink),
79-
m_out_buf(&bg_xsink),
80-
m_err_buf(&bg_xsink),
78+
m_in_buf(&bg_xsink),
79+
m_out_buf(&bg_xsink),
80+
m_err_buf(&bg_xsink),
8181

82-
m_out_vec(process_buf_size),
83-
m_err_vec(process_buf_size),
82+
m_out_vec(process_buf_size),
83+
m_err_vec(process_buf_size),
8484

85-
m_in_asiobuf(boost::asio::buffer(m_in_vec)),
86-
m_out_asiobuf(boost::asio::buffer(m_out_vec)),
87-
m_err_asiobuf(boost::asio::buffer(m_err_vec)) {
85+
m_in_asiobuf(boost::asio::buffer(m_in_vec)),
86+
m_out_asiobuf(boost::asio::buffer(m_out_vec)),
87+
m_err_asiobuf(boost::asio::buffer(m_err_vec)) {
8888
// get handler pointers
8989
ResolvedCallReferenceNode* on_success = optsExecutor("on_success", opts, xsink);
9090
ResolvedCallReferenceNode* on_setup = optsExecutor("on_setup", opts, xsink);
@@ -389,7 +389,7 @@ boost::filesystem::path ProcessPriv::optsPath(const char* command, const QoreHas
389389
}
390390
} catch (std::runtime_error& ex) {
391391
xsink->raiseException("PROCESS-SEARCH-PATH-ERROR", ex.what());
392-
return ret;
392+
return ret;
393393
}
394394

395395
if (ret.empty()) {
@@ -594,7 +594,11 @@ void ProcessPriv::launchChild(boost::filesystem::path p,
594594
m_out_buf.reassignThread();
595595
m_err_buf.reassignThread();
596596

597-
m_asio_ctx.run();
597+
try {
598+
m_asio_ctx.run();
599+
} catch (const std::exception& ex) {
600+
printd(0, "exception in m_asio_ctx.run() in m_asio_ctx_run_future: %s", ex.what());
601+
}
598602

599603
m_out_buf.unassignThread();
600604
m_err_buf.unassignThread();
@@ -604,15 +608,17 @@ void ProcessPriv::launchChild(boost::filesystem::path p,
604608
}
605609

606610
int ProcessPriv::exitCode(ExceptionSink* xsink) {
607-
if (!processCheck(xsink))
611+
if (!processCheck(xsink)) {
608612
return -1;
613+
}
609614

610615
return exit_code;
611616
}
612617

613618
int ProcessPriv::id(ExceptionSink* xsink) {
614-
if (!processCheck(xsink))
619+
if (!processCheck(xsink)) {
615620
return -1;
621+
}
616622

617623
try {
618624
return m_process->id();
@@ -624,8 +630,9 @@ int ProcessPriv::id(ExceptionSink* xsink) {
624630
}
625631

626632
bool ProcessPriv::valid(ExceptionSink* xsink) {
627-
if (!processCheck(xsink))
633+
if (!processCheck(xsink)) {
628634
return false;
635+
}
629636

630637
try {
631638
return m_process->valid();
@@ -637,23 +644,27 @@ bool ProcessPriv::valid(ExceptionSink* xsink) {
637644
}
638645

639646
bool ProcessPriv::running(ExceptionSink* xsink) {
640-
if (!processCheck(xsink))
647+
if (!processCheck(xsink)) {
641648
return false;
642-
643-
try {
644-
return m_process->running();
645-
} catch (const std::exception& ex) {
646-
xsink->raiseException("PROCESS-RUNNING-ERROR", ex.what());
647649
}
648650

649-
return false;
651+
std::error_code ec;
652+
bool rc = m_process->running(ec);
653+
if (ec) {
654+
xsink->raiseException("PROCESS-RUNNING-ERROR", "Process::running() failed: %s", ec.message().c_str());
655+
}
656+
return rc;
650657
}
651658

652659
void ProcessPriv::finalizeStreams(ExceptionSink* xsink) {
653660
// the asio context is stopped in the process handler unless the proces has been detached
654661
if (detached) {
655662
m_asio_ctx.stop();
656-
m_asio_ctx.run();
663+
try {
664+
m_asio_ctx.run();
665+
} catch (const std::exception& ex) {
666+
printd(0, "exception in m_asio_ctx.run() in ProcessPriv::finalizeStreams(): %s", ex.what());
667+
}
657668
}
658669

659670
// wait for future
@@ -718,12 +729,23 @@ void ProcessPriv::getExitCode(ExceptionSink* xsink) {
718729
}
719730

720731
bool ProcessPriv::wait(ExceptionSink* xsink) {
721-
if (!processCheck(xsink))
732+
if (!processCheck(xsink)) {
722733
return false;
734+
}
735+
736+
// return immediately if we already have an exit code
737+
if (exit_code != -1) {
738+
return true;
739+
}
723740

724741
try {
725-
if (m_process->valid() && m_process->running()) {
726-
m_process->wait();
742+
if (m_process->valid()) {
743+
std::error_code ec;
744+
m_process->wait(ec);
745+
if (ec) {
746+
xsink->raiseException("PROCESS-WAIT-ERROR", "cannot wait on process: %s", ec.message().c_str());
747+
return false;
748+
}
727749

728750
// get exit code if possible
729751
getExitCode(xsink);
@@ -736,30 +758,26 @@ bool ProcessPriv::wait(ExceptionSink* xsink) {
736758
}
737759
return true;
738760
} catch (const std::exception& ex) {
739-
// ignore errors if the process has already terminated
740761
const char* err = ex.what();
741-
if (!strcmp("wait error: No child processes", err)) {
742-
// get exit code if possible
743-
getExitCode(xsink);
744-
745-
// rethrows any background exceptions
746-
finalizeStreams(xsink);
747-
return true;
748-
} else {
749-
xsink->raiseException("PROCESS-WAIT-ERROR", err);
750-
}
762+
xsink->raiseException("PROCESS-WAIT-ERROR", err);
751763
}
752764

753765
return false;
754766
}
755767

756768
bool ProcessPriv::wait(int64 t, ExceptionSink* xsink) {
757-
if (!processCheck(xsink))
769+
if (!processCheck(xsink)) {
758770
return false;
771+
}
759772

760773
try {
761-
if (m_process->valid() && m_process->running()) {
762-
bool rv = m_process->wait_for(std::chrono::milliseconds(t));
774+
if (m_process->valid()) {
775+
std::error_code ec;
776+
bool rv = m_process->wait_for(std::chrono::milliseconds(t), ec);
777+
if (ec) {
778+
xsink->raiseException("PROCESS-WAIT-ERROR", "cannot wait on process: %s", ec.message().c_str());
779+
return false;
780+
}
763781
if (rv) {
764782
// get exit code if possible
765783
getExitCode(xsink);
@@ -775,45 +793,41 @@ bool ProcessPriv::wait(int64 t, ExceptionSink* xsink) {
775793
}
776794
return false;
777795
} catch (const std::exception& ex) {
778-
// ignore errors if the process has already terminated
779796
const char* err = ex.what();
780-
if (!strcmp("wait error: No child processes", err)) {
781-
// get exit code if possible
782-
getExitCode(xsink);
783-
784-
// rethrows any background exceptions
785-
finalizeStreams(xsink);
786-
787-
return true;
788-
} else {
789-
xsink->raiseException("PROCESS-WAIT-ERROR", err);
790-
}
797+
xsink->raiseException("PROCESS-WAIT-ERROR", err);
791798
}
792799

793800
return false;
794801
}
795802

796803
bool ProcessPriv::detach(ExceptionSink* xsink) {
797-
if (!processCheck(xsink))
804+
if (!processCheck(xsink)) {
798805
return false;
806+
}
799807

800-
m_process->detach();
808+
try {
809+
m_process->detach();
810+
} catch (const std::exception& ex) {
811+
const char* err = ex.what();
812+
xsink->raiseException("PROCESS-WAIT-ERROR", err);
813+
return false;
814+
}
801815
detached = true;
802816
return true;
803817
}
804818

805819
bool ProcessPriv::terminate(ExceptionSink* xsink) {
806-
if (!processCheck(xsink))
820+
if (!processCheck(xsink)) {
807821
return false;
808-
809-
try {
810-
m_process->terminate();
811-
return true;
812-
} catch (const std::exception& ex) {
813-
xsink->raiseException("PROCESS-TERMINATE-ERROR", ex.what());
814822
}
815823

816-
return false;
824+
std::error_code ec;
825+
m_process->terminate(ec);
826+
if (ec) {
827+
xsink->raiseException("PROCESS-TERMINATE-ERROR", "cannot terminate process: %s", ec.message().c_str());
828+
return false;
829+
}
830+
return true;
817831
}
818832

819833
QoreStringNode* ProcessPriv::readStderr(size_t n, ExceptionSink* xsink) {
@@ -985,8 +999,9 @@ BinaryNode* ProcessPriv::readStdoutBinaryTimeout(size_t n, int64 millis, Excepti
985999
}
9861000

9871001
void ProcessPriv::write(const char* val, size_t n, ExceptionSink* xsink) {
988-
if (!processCheck(xsink))
1002+
if (!processCheck(xsink)) {
9891003
return;
1004+
}
9901005

9911006
if (!val || !n)
9921007
return;

0 commit comments

Comments
 (0)