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
- 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
+ }
727
749
728
750
// get exit code if possible
729
751
getExitCode (xsink);
@@ -736,30 +758,26 @@ bool ProcessPriv::wait(ExceptionSink* xsink) {
736
758
}
737
759
return true ;
738
760
} catch (const std::exception& ex) {
739
- // ignore errors if the process has already terminated
740
761
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);
751
763
}
752
764
753
765
return false ;
754
766
}
755
767
756
768
bool ProcessPriv::wait (int64 t, ExceptionSink* xsink) {
757
- if (!processCheck (xsink))
769
+ if (!processCheck (xsink)) {
758
770
return false ;
771
+ }
759
772
760
773
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
+ }
763
781
if (rv) {
764
782
// get exit code if possible
765
783
getExitCode (xsink);
@@ -775,45 +793,41 @@ bool ProcessPriv::wait(int64 t, ExceptionSink* xsink) {
775
793
}
776
794
return false ;
777
795
} catch (const std::exception& ex) {
778
- // ignore errors if the process has already terminated
779
796
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);
791
798
}
792
799
793
800
return false ;
794
801
}
795
802
796
803
bool ProcessPriv::detach (ExceptionSink* xsink) {
797
- if (!processCheck (xsink))
804
+ if (!processCheck (xsink)) {
798
805
return false ;
806
+ }
799
807
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
+ }
801
815
detached = true ;
802
816
return true ;
803
817
}
804
818
805
819
bool ProcessPriv::terminate (ExceptionSink* xsink) {
806
- if (!processCheck (xsink))
820
+ if (!processCheck (xsink)) {
807
821
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 ());
814
822
}
815
823
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 ;
817
831
}
818
832
819
833
QoreStringNode* ProcessPriv::readStderr (size_t n, ExceptionSink* xsink) {
@@ -985,8 +999,9 @@ BinaryNode* ProcessPriv::readStdoutBinaryTimeout(size_t n, int64 millis, Excepti
985
999
}
986
1000
987
1001
void ProcessPriv::write (const char * val, size_t n, ExceptionSink* xsink) {
988
- if (!processCheck (xsink))
1002
+ if (!processCheck (xsink)) {
989
1003
return ;
1004
+ }
990
1005
991
1006
if (!val || !n)
992
1007
return ;
0 commit comments