Skip to content

Commit ff82304

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 ff82304

File tree

3 files changed

+94
-79
lines changed

3 files changed

+94
-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: 88 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& e) {
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& e) {
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,18 @@ 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+
}
723735

724736
try {
725-
if (m_process->valid() && m_process->running()) {
726-
m_process->wait();
737+
if (m_process->valid()) {
738+
std::error_code ec;
739+
m_process->wait(ec);
740+
if (ec) {
741+
xsink->raiseException("PROCESS-WAIT-ERROR", "cannot wait on process: %s", ec.message().c_str());
742+
return false;
743+
}
727744

728745
// get exit code if possible
729746
getExitCode(xsink);
@@ -736,30 +753,26 @@ bool ProcessPriv::wait(ExceptionSink* xsink) {
736753
}
737754
return true;
738755
} catch (const std::exception& ex) {
739-
// ignore errors if the process has already terminated
740756
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-
}
757+
xsink->raiseException("PROCESS-WAIT-ERROR", err);
751758
}
752759

753760
return false;
754761
}
755762

756763
bool ProcessPriv::wait(int64 t, ExceptionSink* xsink) {
757-
if (!processCheck(xsink))
764+
if (!processCheck(xsink)) {
758765
return false;
766+
}
759767

760768
try {
761-
if (m_process->valid() && m_process->running()) {
762-
bool rv = m_process->wait_for(std::chrono::milliseconds(t));
769+
if (m_process->valid()) {
770+
std::error_code ec;
771+
bool rv = m_process->wait_for(std::chrono::milliseconds(t), ec);
772+
if (ec) {
773+
xsink->raiseException("PROCESS-WAIT-ERROR", "cannot wait on process: %s", ec.message().c_str());
774+
return false;
775+
}
763776
if (rv) {
764777
// get exit code if possible
765778
getExitCode(xsink);
@@ -775,45 +788,41 @@ bool ProcessPriv::wait(int64 t, ExceptionSink* xsink) {
775788
}
776789
return false;
777790
} catch (const std::exception& ex) {
778-
// ignore errors if the process has already terminated
779791
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-
}
792+
xsink->raiseException("PROCESS-WAIT-ERROR", err);
791793
}
792794

793795
return false;
794796
}
795797

796798
bool ProcessPriv::detach(ExceptionSink* xsink) {
797-
if (!processCheck(xsink))
799+
if (!processCheck(xsink)) {
798800
return false;
801+
}
799802

800-
m_process->detach();
803+
try {
804+
m_process->detach();
805+
} catch (const std::exception& ex) {
806+
const char* err = ex.what();
807+
xsink->raiseException("PROCESS-WAIT-ERROR", err);
808+
return false;
809+
}
801810
detached = true;
802811
return true;
803812
}
804813

805814
bool ProcessPriv::terminate(ExceptionSink* xsink) {
806-
if (!processCheck(xsink))
815+
if (!processCheck(xsink)) {
807816
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());
814817
}
815818

816-
return false;
819+
std::error_code ec;
820+
m_process->terminate(ec);
821+
if (ec) {
822+
xsink->raiseException("PROCESS-TERMINATE-ERROR", "cannot terminate process: %s", ec.message().c_str());
823+
return false;
824+
}
825+
return true;
817826
}
818827

819828
QoreStringNode* ProcessPriv::readStderr(size_t n, ExceptionSink* xsink) {
@@ -985,8 +994,9 @@ BinaryNode* ProcessPriv::readStdoutBinaryTimeout(size_t n, int64 millis, Excepti
985994
}
986995

987996
void ProcessPriv::write(const char* val, size_t n, ExceptionSink* xsink) {
988-
if (!processCheck(xsink))
997+
if (!processCheck(xsink)) {
989998
return;
999+
}
9901000

9911001
if (!val || !n)
9921002
return;

0 commit comments

Comments
 (0)