You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

child.cpp 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  1. // \file child.cpp
  2. //
  3. // Copyright (C) 2014 MicroNeil Research Corporation.
  4. //
  5. // This program is part of the MicroNeil Research Open Library Project. For
  6. // more information go to http://www.microneil.com/OpenLibrary/index.html
  7. //
  8. // This program is free software; you can redistribute it and/or modify it
  9. // under the terms of the GNU General Public License as published by the
  10. // Free Software Foundation; either version 2 of the License, or (at your
  11. // option) any later version.
  12. //
  13. // This program is distributed in the hope that it will be useful, but WITHOUT
  14. // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15. // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  16. // more details.
  17. //
  18. // You should have received a copy of the GNU General Public License along with
  19. // this program; if not, write to the Free Software Foundation, Inc., 59 Temple
  20. // Place, Suite 330, Boston, MA 02111-1307 USA
  21. //==============================================================================
  22. #ifndef _WIN32
  23. #include <unistd.h>
  24. #include <sys/types.h>
  25. #include <sys/wait.h>
  26. #include <signal.h>
  27. #include <sys/select.h>
  28. #include <cstring>
  29. #include <cerrno>
  30. #endif
  31. #include <stdexcept>
  32. #include "child.hpp"
  33. namespace CodeDweller {
  34. Child::Child(std::vector<std::string> args, size_t bufSize) :
  35. readStreambuf(bufSize),
  36. writeStreambuf(bufSize),
  37. reader(&readStreambuf),
  38. writer(&writeStreambuf),
  39. cmdArgs(args) {
  40. init();
  41. }
  42. Child::Child(std::string childpath, size_t bufSize) :
  43. readStreambuf(bufSize),
  44. writeStreambuf(bufSize),
  45. reader(&readStreambuf),
  46. writer(&writeStreambuf),
  47. cmdline(childpath) {
  48. cmdArgs.push_back(childpath);
  49. init();
  50. }
  51. Child::~Child() {
  52. // Close handles.
  53. }
  54. void
  55. Child::init() {
  56. if (cmdArgs.empty()) {
  57. throw std::invalid_argument("A child executable must be specified.");
  58. }
  59. reader.exceptions(std::istream::failbit | std::istream::badbit);
  60. writer.exceptions(std::ostream::failbit | std::ostream::badbit);
  61. childStarted = false;
  62. childExited = false;
  63. exitCodeObtainedFlag = false;
  64. exitCode = 0;
  65. }
  66. size_t
  67. Child::numBytesAvailable() const {
  68. return readStreambuf.numBytesAvailable();
  69. }
  70. void
  71. Child::run() {
  72. if (childStarted) {
  73. throw std::logic_error("Child process was active when "
  74. "run() was called");
  75. }
  76. #ifdef _WIN32
  77. // Set the bInheritHandle flag so pipe handles are inherited.
  78. SECURITY_ATTRIBUTES securityAttributes;
  79. securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
  80. securityAttributes.bInheritHandle = true;
  81. securityAttributes.lpSecurityDescriptor = NULL;
  82. // Create a pipe for the child process's STDOUT.
  83. HANDLE childStdOutAtChild;
  84. HANDLE childStdOutAtParent;
  85. HANDLE childStdInAtChild;
  86. HANDLE childStdInAtParent;
  87. int bufferSize = 0;
  88. if (!CreatePipe(&childStdOutAtParent,
  89. &childStdOutAtChild,
  90. &securityAttributes,
  91. bufferSize)) {
  92. throw std::runtime_error("Error from CreatePipe for stdout: " +
  93. getErrorText());
  94. }
  95. // Ensure the read handle to the pipe for STDOUT is not inherited.
  96. int inheritFlag = 0;
  97. if (!SetHandleInformation(childStdOutAtParent,
  98. HANDLE_FLAG_INHERIT,
  99. inheritFlag) ) {
  100. throw std::runtime_error("Error from GetHandleInformation for stdout: " +
  101. getErrorText());
  102. }
  103. // Create a pipe for the child process's STDIN.
  104. if (! CreatePipe(&childStdInAtChild,
  105. &childStdInAtParent,
  106. &securityAttributes,
  107. bufferSize)) {
  108. throw std::runtime_error("Error from CreatePipe for stdin: " +
  109. getErrorText());
  110. }
  111. // Ensure the write handle to the pipe for STDIN is not inherited.
  112. if (!SetHandleInformation(childStdInAtParent,
  113. HANDLE_FLAG_INHERIT,
  114. inheritFlag)) {
  115. throw std::runtime_error("Error from GetHandleInformation for stdin: " +
  116. getErrorText());
  117. }
  118. // Set up members of the PROCESS_INFORMATION structure.
  119. PROCESS_INFORMATION processInfo;
  120. std::fill((char *) &processInfo,
  121. ((char *) &processInfo) + sizeof(PROCESS_INFORMATION),
  122. 0);
  123. // Set up members of the STARTUPINFO structure. This structure
  124. // specifies the STDIN and STDOUT handles for redirection.
  125. STARTUPINFO startInfo;
  126. std::fill((char *) &startInfo,
  127. ((char *) &startInfo) + sizeof(STARTUPINFO),
  128. 0);
  129. startInfo.cb = sizeof(STARTUPINFO);
  130. startInfo.hStdError = childStdOutAtChild;
  131. startInfo.hStdOutput = childStdOutAtChild;
  132. startInfo.hStdInput = childStdInAtChild;
  133. startInfo.dwFlags |= STARTF_USESTDHANDLES;
  134. // Assemble the command line.
  135. std::string cmdline;
  136. if (cmdArgs.size() == 1) {
  137. cmdline = cmdArgs[0];
  138. } else {
  139. // Append all but last command-line arguments.
  140. for (size_t i = 0; i < cmdArgs.size() - 1; i++) {
  141. cmdline += cmdArgs[i] + " ";
  142. }
  143. cmdline += cmdArgs.back(); // Append last command-line argument.
  144. }
  145. // Create the child process.
  146. bool status;
  147. status = CreateProcess(NULL,
  148. (char *) cmdline.c_str(),
  149. NULL, // process security attributes
  150. NULL, // primary thread security attributes
  151. true, // handles are inherited
  152. 0, // creation flags
  153. NULL, // use parent's environment
  154. NULL, // use parent's current directory
  155. &startInfo, // STARTUPINFO pointer
  156. &processInfo); // receives PROCESS_INFORMATION
  157. // If an error occurs, exit the application.
  158. if (!status ) {
  159. throw std::runtime_error("Error from CreateProcess with "
  160. "command line \"" + cmdline + "\": " +
  161. getErrorText());
  162. }
  163. // Provide the stream buffers with the handles for communicating
  164. // with the child process.
  165. readStreambuf.setInputHandle(childStdOutAtParent);
  166. writeStreambuf.setOutputHandle(childStdInAtParent);
  167. // Save the handles to the child process and its primary thread.
  168. childProcess = processInfo.hProcess;
  169. childThread = processInfo.hThread;
  170. // Close the child's end of the pipes.
  171. if (!CloseHandle(childStdOutAtChild)) {
  172. throw std::runtime_error("Error closing the child process "
  173. "stdout handle: " + getErrorText());
  174. }
  175. if (!CloseHandle(childStdInAtChild)) {
  176. throw std::runtime_error("Error closing the child process "
  177. "stdin handle: " + getErrorText());
  178. }
  179. #else
  180. // Create the pipes for the stdin and stdout.
  181. int childStdInPipe[2];
  182. int childStdOutPipe[2];
  183. if (pipe(childStdInPipe) != 0) {
  184. throw std::runtime_error("Error creating pipe for stdin: " +
  185. getErrorText());
  186. }
  187. if (pipe(childStdOutPipe) != 0) {
  188. close(childStdInPipe[0]);
  189. close(childStdInPipe[1]);
  190. throw std::runtime_error("Error creating pipe for stdout: " +
  191. getErrorText());
  192. }
  193. // Create the child process.
  194. childPid = fork();
  195. if (-1 == childPid) {
  196. for (int i = 0; i < 2; i++) {
  197. close(childStdInPipe[i]);
  198. close(childStdOutPipe[i]);
  199. }
  200. throw std::runtime_error("Error creating child process: " +
  201. getErrorText());
  202. }
  203. if (0 == childPid) {
  204. // The child executes this. Redirect stdin.
  205. if (dup2(childStdInPipe[0], STDIN_FILENO) == -1) {
  206. std::string errMsg;
  207. // Send message to parent.
  208. errMsg = "Error redirecting stdin in the child: " + getErrorText();
  209. write(childStdOutPipe[1], errMsg.data(), errMsg.size());
  210. exit(-1);
  211. }
  212. // Redirect stdout.
  213. if (dup2(childStdOutPipe[1], STDOUT_FILENO) == -1) {
  214. std::string errMsg;
  215. // Send message to parent.
  216. errMsg = "Error redirecting stdout in the child: " + getErrorText();
  217. write(childStdOutPipe[1], errMsg.data(), errMsg.size());
  218. exit(-1);
  219. }
  220. // Close pipes.
  221. if ( (close(childStdInPipe[0]) != 0) ||
  222. (close(childStdInPipe[1]) != 0) ||
  223. (close(childStdOutPipe[0]) != 0) ||
  224. (close(childStdOutPipe[1]) != 0) ) {
  225. std::string errMsg;
  226. // Send message to parent.
  227. errMsg = "Error closing the pipes in the child: " + getErrorText();
  228. write(STDOUT_FILENO, errMsg.data(), errMsg.size());
  229. exit(-1);
  230. }
  231. // Prepare the arguments.
  232. std::vector<const char *> execvArgv;
  233. for (auto &arg : cmdArgs) {
  234. execvArgv.push_back(arg.c_str());
  235. }
  236. execvArgv.push_back((char *) NULL);
  237. // Run the child process image.
  238. (void) execv(execvArgv[0], (char * const *) &(execvArgv[0]));
  239. // Error from exec.
  240. std::string errMsg;
  241. // Send message to parent.
  242. errMsg = "Error from exec: " + getErrorText();
  243. write(STDOUT_FILENO, errMsg.data(), errMsg.size());
  244. exit(-1);
  245. }
  246. // std::cout << "Child pid: " << childPid << std::endl; // DEBUG.
  247. // Provide the stream buffers with the file descriptors for
  248. // communicating with the child process.
  249. readStreambuf.setInputFileDescriptor(childStdOutPipe[0]);
  250. writeStreambuf.setOutputFileDescriptor(childStdInPipe[1]);
  251. // Close the child's end of the pipes.
  252. if ( (close(childStdInPipe[0]) != 0) ||
  253. (close(childStdOutPipe[1]) != 0) ) {
  254. std::string errMsg;
  255. throw std::runtime_error("Error closing child's end of pipes in "
  256. "the parent: " + getErrorText());
  257. }
  258. #endif
  259. childStarted = true;
  260. }
  261. void
  262. Child::terminate() {
  263. if (isDone()) {
  264. return;
  265. }
  266. #ifdef _WIN32
  267. if (!TerminateProcess(childProcess, terminateExitCode)) {
  268. #else
  269. if (kill(childPid, SIGTERM) != 0) {
  270. #endif
  271. throw std::runtime_error("Error terminating the child process: " +
  272. getErrorText());
  273. }
  274. }
  275. bool
  276. Child::isDone() {
  277. if (childExited) {
  278. return true;
  279. }
  280. if (!childStarted) {
  281. throw std::logic_error("Child process was not started "
  282. "when isDone() was called");
  283. }
  284. int result;
  285. #ifdef _WIN32
  286. if (!GetExitCodeProcess(childProcess, (LPDWORD) &result)) {
  287. throw std::runtime_error("Error checking status of child process: " +
  288. getErrorText());
  289. }
  290. if (STILL_ACTIVE == result) {
  291. return false;
  292. }
  293. // Child process has exited. Save the exit code.
  294. exitCode = result;
  295. exitCodeObtainedFlag = true;
  296. #else
  297. int status = 0;
  298. result = waitpid(childPid, &status, WNOHANG);
  299. // std::cout << "isDone(). waitpid(" << childPid << ",...) returned " << result << std::endl; // DEBUG
  300. if (-1 == result) {
  301. throw std::runtime_error("Error checking status of child process: " +
  302. getErrorText());
  303. } else if (0 == result) {
  304. // Child is still running.
  305. // std::cout << "isDone(). Child is still running..." << std::endl; // DEBUG.
  306. return false;
  307. }
  308. // std::cout << "isDone(). Child exited." << std::endl; // DEBUG.
  309. if (WIFEXITED(status)) {
  310. // Child exited normally.
  311. exitCode = WEXITSTATUS(status);
  312. exitCodeObtainedFlag = true;
  313. //std::cout << "isDone(). Child exited normally. Exit code: " << exitCode << std::endl; // DEBUG.
  314. }
  315. #endif
  316. childExited = true;
  317. return true;
  318. }
  319. int32_t
  320. Child::result() {
  321. if (exitCodeObtainedFlag) {
  322. return exitCode;
  323. }
  324. // Check whether the process is running, and get the exit code.
  325. if (!isDone()) {
  326. throw std::logic_error("Child process was still running "
  327. "when result() was called");
  328. }
  329. // Child process has exited.
  330. if (!exitCodeObtainedFlag) {
  331. // Exit code is not available.
  332. throw std::runtime_error("Child process has exited but the exit "
  333. "code is not available");
  334. }
  335. return exitCode;
  336. }
  337. std::string
  338. Child::getErrorText() {
  339. #ifdef _WIN32
  340. LPVOID winMsgBuf;
  341. DWORD lastError = GetLastError();
  342. FormatMessage(
  343. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  344. FORMAT_MESSAGE_FROM_SYSTEM |
  345. FORMAT_MESSAGE_IGNORE_INSERTS,
  346. NULL,
  347. lastError,
  348. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  349. (char *) &winMsgBuf,
  350. 0, NULL );
  351. std::string errMsg((char *) winMsgBuf);
  352. LocalFree(winMsgBuf);
  353. return errMsg;
  354. #else
  355. return strerror(errno);
  356. #endif
  357. }
  358. Child::ReadStreambuf::ReadStreambuf(std::size_t bufferSize) :
  359. #ifdef _WIN32
  360. inputHandle(0),
  361. #else
  362. inputFileDescriptor(-1),
  363. #endif
  364. buffer(bufferSize + 1) {
  365. char *end = &(buffer.front()) + buffer.size();
  366. // Indicate to underflow that underflow has not been called.
  367. setg(end, end, end);
  368. }
  369. #ifdef _WIN32
  370. void
  371. Child::ReadStreambuf::setInputHandle(HANDLE inHandle) {
  372. inputHandle = inHandle;
  373. }
  374. #else
  375. void
  376. Child::ReadStreambuf::setInputFileDescriptor(int inFd) {
  377. inputFileDescriptor = inFd;
  378. }
  379. #endif
  380. size_t
  381. Child::ReadStreambuf::numBytesAvailable() const {
  382. size_t nBytesAvailable = egptr() - gptr();
  383. fd_set readFd;
  384. int retVal;
  385. struct timeval timeout = {0, 0};
  386. FD_ZERO(&readFd);
  387. FD_SET(inputFileDescriptor, &readFd);
  388. // Check if input is available.
  389. retVal = select(inputFileDescriptor + 1, &readFd, NULL, NULL, &timeout);
  390. if (-1 == retVal) {
  391. throw std::runtime_error("Error from select(): " + getErrorText());
  392. } else if (retVal > 0) {
  393. nBytesAvailable++;
  394. }
  395. return nBytesAvailable;
  396. }
  397. std::streambuf::int_type
  398. Child::ReadStreambuf::underflow() {
  399. // Check for empty buffer.
  400. if (gptr() < egptr()) {
  401. // Not empty.
  402. return traits_type::to_int_type(*gptr());
  403. }
  404. // Need to fill the buffer.
  405. char *base = &(buffer.front());
  406. char *start = base;
  407. // Check whether this is the first fill.
  408. if (eback() == base) {
  409. // Not the first fill. Copy one putback character.
  410. *(eback()) = *(egptr() - 1);
  411. start++;
  412. }
  413. // start points to the start of the buffer. Fill buffer.
  414. #ifdef _WIN32
  415. DWORD nBytesRead;
  416. if (!ReadFile(inputHandle,
  417. start,
  418. buffer.size() - (start - base),
  419. &nBytesRead,
  420. NULL)) {
  421. return traits_type::eof();
  422. }
  423. #else
  424. ssize_t nBytesRead;
  425. nBytesRead = read(inputFileDescriptor,
  426. start,
  427. buffer.size() - (start - base));
  428. if (-1 == nBytesRead) {
  429. return traits_type::eof();
  430. }
  431. #endif
  432. // Check for EOF.
  433. if (0 == nBytesRead) {
  434. return traits_type::eof();
  435. }
  436. // Update buffer pointers.
  437. setg(base, start, start + nBytesRead);
  438. return traits_type::to_int_type(*gptr());
  439. }
  440. Child::WriteStreambuf::WriteStreambuf(std::size_t bufferSize) :
  441. #ifdef _WIN32
  442. outputHandle(0),
  443. #else
  444. outputFileDescriptor(-1),
  445. #endif
  446. buffer(bufferSize + 1) {
  447. char *base = &(buffer.front());
  448. // Indicate to overflow that overflow has not been called.
  449. setp(base, base + buffer.size() - 1);
  450. }
  451. #ifdef _WIN32
  452. void
  453. Child::WriteStreambuf::setOutputHandle(HANDLE outHandle) {
  454. outputHandle = outHandle;
  455. }
  456. #else
  457. void
  458. Child::WriteStreambuf::setOutputFileDescriptor(int outFd) {
  459. outputFileDescriptor = outFd;
  460. }
  461. #endif
  462. void
  463. Child::WriteStreambuf::flushBuffer() {
  464. // Write.
  465. std::ptrdiff_t nBytes = pptr() - pbase();
  466. #ifdef _WIN32
  467. DWORD nBytesWritten;
  468. if (!WriteFile(outputHandle,
  469. pbase(),
  470. nBytes,
  471. &nBytesWritten,
  472. NULL)) {
  473. // Clear the output buffer.
  474. pbump(-nBytes);
  475. throw std::runtime_error("Error writing to child process: " +
  476. getErrorText());
  477. }
  478. #else
  479. ssize_t nBytesWritten;
  480. nBytesWritten = write(outputFileDescriptor, pbase(), nBytes);
  481. #endif
  482. // Clear the output buffer.
  483. pbump(-nBytes);
  484. if (nBytes != nBytesWritten) {
  485. throw std::runtime_error("Not all data was written to to child "
  486. "process: " + getErrorText());
  487. }
  488. return;
  489. }
  490. std::streambuf::int_type
  491. Child::WriteStreambuf::overflow(int_type ch) {
  492. // Check whether we're writing EOF.
  493. if (traits_type::eof() != ch) {
  494. // Not writing EOF.
  495. *(pptr()) = ch;
  496. pbump(1);
  497. // Write.
  498. flushBuffer();
  499. // Success.
  500. return ch;
  501. }
  502. return traits_type::eof();
  503. }
  504. int
  505. Child::WriteStreambuf::sync() {
  506. flushBuffer(); // Throws exception on failure.
  507. // Success.
  508. return 1;
  509. }
  510. }