Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

child.cpp 17KB

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