a Code for the Combination of Indirect and Direct Constraints on High Energy Physics Models Logo
WaitingOnSubprocessExecutor.cpp
Go to the documentation of this file.
1/*
2 * WaitingOnSubprocessExecutor.cpp
3 *
4 * Created on: Jan 8, 2012
5 * Author: Ben O'Leary (benjamin.oleary@gmail.com)
6 *
7 * This file is part of BOLlib, released under the
8 * GNU General Public License. Please see the accompanying
9 * README.BOLlib.txt file for a full list of files, brief documentation
10 * on how to use these classes, and further details on the license.
11 */
12
14
15namespace BOL
16{
18
20 std::string const& executableStringIncludingArguments,
21 bool const isVerbose,
22 int const patienceMilliseconds ) :
23 processId( 0 ),
24 isVerbose( isVerbose ),
25 executableNameAndArguments( 0 ),
26 argumentListAsArray( NULL ),
27 patienceTicks( ( ( patienceMilliseconds * CLOCKS_PER_SEC ) / 1000 ) ),
28 killingTime()
29 {
30 StringParser::parseByChar( executableStringIncludingArguments,
33 }
34
36 {
37 delete[] argumentListAsArray;
38 }
39
40
41 bool
43 /* this forks off a new process, then checks if this process is the parent
44 * or the child subprocess. if it's the parent, it waits until the child
45 * returns a value or until the "patience" time runs out, at which point it
46 * kills the child subprocess if it has not returned a value. if it is the
47 * child, it runs execv with its arguments & returns the return value from
48 * the execv process.
49 */
50 {
51 killingTime = ( clock() + patienceTicks );
52 int processStatus( 0 );
53 // this keeps track of the status of the process.
54 int returnValue( 0 );
55 // this keeps track of what processes return.
56 bool subprocessReturned( true );
57 // assume that the subprocess won't have to be killed.
58 int forkReturnValue( fork() );
59 if( 0 > forkReturnValue )
60 // if fork failed to do what it should do...
61 {
62 std::cout
63 << std::endl
64 << "BOL::error! WaitingOnSubprocessExecutor::forkAndExecvAndWait() was"
65 << " unable to create the subprocess; there was an error and fork()"
66 << " returned " << forkReturnValue << std::endl;
67 // print error message.
68 }
69 else if( 0 == forkReturnValue )
70 // otherwise if this is the subprocess
71 // [since it got the 0 from fork()]...
72 {
73 processId = getpid();
74 if( isVerbose )
75 {
76 std::cout
77 << std::endl
78 << "now executing \"" << argumentListAsArray[ 0 ];
79 for( int argumentWritingCounter( 1 );
80 executableNameAndArguments.getSize() > argumentWritingCounter;
81 ++argumentWritingCounter )
82 {
83 std::cout
84 << " " << argumentListAsArray[ argumentWritingCounter ];
85 }
86 std::cout
87 << "\", with process id " << getpid() << ", real user id " << getuid()
88 << " & effective user id " << geteuid() << std::endl;
89 }
90 returnValue = execv( argumentListAsArray[ 0 ],
91 (char* const*)argumentListAsArray );
92 // run the executable with its arguments.
93 exit( returnValue );
94 }
95 else if( 0 < forkReturnValue )
96 // otherwise this is the parent process, since it got given the process
97 // id of the subprocess.
98 {
99 bool subprocessFinished( false );
100 // the tracker of whether the subprocess has changed state or not.
101 while( clock() < killingTime )
102 {
103 if( waitpid( forkReturnValue,
104 &processStatus,
105 WNOHANG ) == forkReturnValue )
106 /* if the waitpid() function waited for the subprocess (with
107 * process id fork_return) and the subprocess changed state, so
108 * that waitpid() returned the subprocess's process id...
109 */
110 {
111 killingTime = clock() - 1;
112 // note that we don't have to wait any more.
113 subprocessFinished = true;
114 // note that the subprocess changed state.
115 }
116 else
117 {
118 usleep( sleepingMicroseconds );
119 // wait 1000 microseconds = 1 millisecond.
120 }
121 }
122 if( false == subprocessFinished )
123 // if we have waited over (patienceTicks/1000) seconds & the
124 // subprocess has not changed state...
125 {
126 if( isVerbose )
127 {
128 std::cout
129 << std::endl
130 << "killing forked process " << forkReturnValue
131 << " due to it taking over " << patienceTicks << " milliseconds"
132 << std::endl;
133 // print warning about hanging subprocess.
134 }
135 kill( forkReturnValue,
136 9 );
137 // kill the hanging process.
138 waitpid( -1,
139 &processStatus,
140 0 );
141 // wait for all this killing to finish? I'm not entirely sure.
142 subprocessReturned = false;
143 // note that the subprocess had to be killed because it did not
144 // return a value.
145 }
146 returnValue = WEXITSTATUS( processStatus );
147 } // end of fork() statement.
148 return subprocessReturned;
149 }
150
151}
static void parseByChar(std::string const &stringToParse, VectorlikeArray< std::string > &destinationArray, std::string const &divisionCharSet=whitespaceChars)
VectorlikeArray< std::string > executableNameAndArguments
WaitingOnSubprocessExecutor(std::string const &executableStringIncludingArguments, bool const isVerbose, int const patienceMilliseconds=10000)