1
1
/*
2
2
Qore Programming Language process Module
3
3
4
- Copyright (C) 2003 - 2020 Qore Technologies, s.r.o.
4
+ Copyright (C) 2003 - 2021 Qore Technologies, s.r.o.
5
5
6
6
Permission is hereby granted, free of charge, to any person obtaining a
7
7
copy of this software and associated documentation files (the "Software"),
@@ -46,18 +46,18 @@ DLLLOCAL extern const TypedHashDecl* hashdeclMemorySummaryInfo;
46
46
static int page_size = sysconf(_SC_PAGESIZE);
47
47
48
48
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)) {
61
61
try {
62
62
int i = boost::numeric_cast<int >(pid);
63
63
m_process = new bp::child (i);
@@ -70,21 +70,21 @@ ProcessPriv::ProcessPriv(pid_t pid, ExceptionSink* xsink) :
70
70
static constexpr unsigned process_buf_size = 4096 ;
71
71
72
72
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),
77
77
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),
81
81
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),
84
84
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)) {
88
88
// get handler pointers
89
89
ResolvedCallReferenceNode* on_success = optsExecutor (" on_success" , opts, xsink);
90
90
ResolvedCallReferenceNode* on_setup = optsExecutor (" on_setup" , opts, xsink);
@@ -389,7 +389,7 @@ boost::filesystem::path ProcessPriv::optsPath(const char* command, const QoreHas
389
389
}
390
390
} catch (std::runtime_error& ex) {
391
391
xsink->raiseException (" PROCESS-SEARCH-PATH-ERROR" , ex.what ());
392
- return ret;
392
+ return ret;
393
393
}
394
394
395
395
if (ret.empty ()) {
@@ -594,7 +594,11 @@ void ProcessPriv::launchChild(boost::filesystem::path p,
594
594
m_out_buf.reassignThread ();
595
595
m_err_buf.reassignThread ();
596
596
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
+ }
598
602
599
603
m_out_buf.unassignThread ();
600
604
m_err_buf.unassignThread ();
@@ -604,15 +608,17 @@ void ProcessPriv::launchChild(boost::filesystem::path p,
604
608
}
605
609
606
610
int ProcessPriv::exitCode (ExceptionSink* xsink) {
607
- if (!processCheck (xsink))
611
+ if (!processCheck (xsink)) {
608
612
return -1 ;
613
+ }
609
614
610
615
return exit_code;
611
616
}
612
617
613
618
int ProcessPriv::id (ExceptionSink* xsink) {
614
- if (!processCheck (xsink))
619
+ if (!processCheck (xsink)) {
615
620
return -1 ;
621
+ }
616
622
617
623
try {
618
624
return m_process->id ();
@@ -624,8 +630,9 @@ int ProcessPriv::id(ExceptionSink* xsink) {
624
630
}
625
631
626
632
bool ProcessPriv::valid (ExceptionSink* xsink) {
627
- if (!processCheck (xsink))
633
+ if (!processCheck (xsink)) {
628
634
return false ;
635
+ }
629
636
630
637
try {
631
638
return m_process->valid ();
@@ -637,23 +644,27 @@ bool ProcessPriv::valid(ExceptionSink* xsink) {
637
644
}
638
645
639
646
bool ProcessPriv::running (ExceptionSink* xsink) {
640
- if (!processCheck (xsink))
647
+ if (!processCheck (xsink)) {
641
648
return false ;
642
-
643
- try {
644
- return m_process->running ();
645
- } catch (const std::exception& ex) {
646
- xsink->raiseException (" PROCESS-RUNNING-ERROR" , ex.what ());
647
649
}
648
650
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;
650
657
}
651
658
652
659
void ProcessPriv::finalizeStreams (ExceptionSink* xsink) {
653
660
// the asio context is stopped in the process handler unless the proces has been detached
654
661
if (detached) {
655
662
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
+ }
657
668
}
658
669
659
670
// wait for future
@@ -718,12 +729,23 @@ void ProcessPriv::getExitCode(ExceptionSink* xsink) {
718
729
}
719
730
720
731
bool ProcessPriv::wait (ExceptionSink* xsink) {
721
- if (!processCheck (xsink))
732
+ if (!processCheck (xsink)) {
722
733
return false ;
734
+ }
735
+
736
+ // return immediately if we already have an exit code
737
+ if (exit_code != -1 ) {
738
+ return true ;
739
+ }
723
740
724
741
try {
725
742
if (m_process->valid ()) {
726
- m_process->wait ();
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
+ }
727
749
728
750
// get exit code if possible
729
751
getExitCode (xsink);
@@ -733,30 +755,31 @@ bool ProcessPriv::wait(ExceptionSink* xsink) {
733
755
}
734
756
return true ;
735
757
} catch (const std::exception& ex) {
736
- // ignore errors if the process has already terminated
737
758
const char * err = ex.what ();
738
- if (!strcmp (" wait error: No child processes" , err)) {
739
- // get exit code if possible
740
- getExitCode (xsink);
741
-
742
- // rethrows any background exceptions
743
- finalizeStreams (xsink);
744
- return true ;
745
- } else {
746
- xsink->raiseException (" PROCESS-WAIT-ERROR" , err);
747
- }
759
+ xsink->raiseException (" PROCESS-WAIT-ERROR" , err);
748
760
}
749
761
750
762
return false ;
751
763
}
752
764
753
765
bool ProcessPriv::wait (int64 t, ExceptionSink* xsink) {
754
- if (!processCheck (xsink))
766
+ if (!processCheck (xsink)) {
755
767
return false ;
768
+ }
769
+
770
+ // return immediately if we already have an exit code
771
+ if (exit_code != -1 ) {
772
+ return true ;
773
+ }
756
774
757
775
try {
758
- if (m_process->valid () && m_process->running ()) {
759
- bool rv = m_process->wait_for (std::chrono::milliseconds (t));
776
+ if (m_process->valid ()) {
777
+ std::error_code ec;
778
+ bool rv = m_process->wait_for (std::chrono::milliseconds (t), ec);
779
+ if (ec) {
780
+ xsink->raiseException (" PROCESS-WAIT-ERROR" , " cannot wait on process: %s" , ec.message ().c_str ());
781
+ return false ;
782
+ }
760
783
if (rv) {
761
784
// get exit code if possible
762
785
getExitCode (xsink);
@@ -769,47 +792,41 @@ bool ProcessPriv::wait(int64 t, ExceptionSink* xsink) {
769
792
}
770
793
return false ;
771
794
} catch (const std::exception& ex) {
772
- // ignore errors if the process has already terminated
773
795
const char * err = ex.what ();
774
- if (!strcmp (" wait error: No child processes" , err)) {
775
- // get exit code if possible
776
- try {
777
- exit_code = m_process->exit_code ();
778
- } catch (const std::exception& ex) {
779
- xsink->raiseException (" PROCESS-EXITCODE-ERROR" , ex.what ());
780
- }
781
- // rethrows any background exceptions
782
- finalizeStreams (xsink);
783
- return true ;
784
- } else {
785
- xsink->raiseException (" PROCESS-WAIT-ERROR" , err);
786
- }
796
+ xsink->raiseException (" PROCESS-WAIT-ERROR" , err);
787
797
}
788
798
789
799
return false ;
790
800
}
791
801
792
802
bool ProcessPriv::detach (ExceptionSink* xsink) {
793
- if (!processCheck (xsink))
803
+ if (!processCheck (xsink)) {
794
804
return false ;
805
+ }
795
806
796
- m_process->detach ();
807
+ try {
808
+ m_process->detach ();
809
+ } catch (const std::exception& ex) {
810
+ const char * err = ex.what ();
811
+ xsink->raiseException (" PROCESS-WAIT-ERROR" , err);
812
+ return false ;
813
+ }
797
814
detached = true ;
798
815
return true ;
799
816
}
800
817
801
818
bool ProcessPriv::terminate (ExceptionSink* xsink) {
802
- if (!processCheck (xsink))
819
+ if (!processCheck (xsink)) {
803
820
return false ;
804
-
805
- try {
806
- m_process->terminate ();
807
- return true ;
808
- } catch (const std::exception& ex) {
809
- xsink->raiseException (" PROCESS-TERMINATE-ERROR" , ex.what ());
810
821
}
811
822
812
- return false ;
823
+ std::error_code ec;
824
+ m_process->terminate (ec);
825
+ if (ec) {
826
+ xsink->raiseException (" PROCESS-TERMINATE-ERROR" , " cannot terminate process: %s" , ec.message ().c_str ());
827
+ return false ;
828
+ }
829
+ return true ;
813
830
}
814
831
815
832
QoreStringNode* ProcessPriv::readStderr (size_t n, ExceptionSink* xsink) {
@@ -981,8 +998,9 @@ BinaryNode* ProcessPriv::readStdoutBinaryTimeout(size_t n, int64 millis, Excepti
981
998
}
982
999
983
1000
void ProcessPriv::write (const char * val, size_t n, ExceptionSink* xsink) {
984
- if (!processCheck (xsink))
1001
+ if (!processCheck (xsink)) {
985
1002
return ;
1003
+ }
986
1004
987
1005
if (!val || !n)
988
1006
return ;
0 commit comments