Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

child.cpp 41KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650
  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 <utility>
  33. #include "CodeDweller/timing.hpp"
  34. #include "CodeDweller/child.hpp"
  35. namespace CodeDweller {
  36. ChildStream::ChildStream(std::vector<std::string> const &args,
  37. size_t bufSize) :
  38. childStreambuf(bufSize),
  39. std::iostream(&childStreambuf),
  40. cmdArgs(args) {
  41. init();
  42. run();
  43. }
  44. ChildStream::ChildStream(std::string const &childpath, size_t bufSize) :
  45. childStreambuf(bufSize),
  46. std::iostream(&childStreambuf) {
  47. cmdArgs.push_back(childpath);
  48. init();
  49. run();
  50. }
  51. ChildStream::ChildStream(size_t bufSize) :
  52. childStreambuf(bufSize),
  53. std::iostream(&childStreambuf) {
  54. init();
  55. }
  56. ChildStream::~ChildStream() {
  57. try {
  58. close();
  59. } catch (std::exception &e) {
  60. ;
  61. }
  62. }
  63. void ChildStream::init() {
  64. childStarted = false;
  65. childExited = false;
  66. exitCodeObtainedFlag = false;
  67. exitCode = 0;
  68. }
  69. void ChildStream::open(std::vector<std::string> const &args) {
  70. cmdArgs = args;
  71. init();
  72. run();
  73. }
  74. void ChildStream::open(std::string const &childpath) {
  75. cmdArgs.clear();
  76. cmdArgs.push_back(childpath);
  77. init();
  78. run();
  79. }
  80. size_t ChildStream::numBytesAvailable() const {
  81. return childStreambuf.numBytesAvailable();
  82. }
  83. bool ChildStream::isRunning() const {
  84. return childStarted && !childExited;
  85. }
  86. void ChildStream::run() {
  87. if (childStarted) {
  88. throw std::logic_error("Child process was active when "
  89. "run() was called");
  90. }
  91. if (cmdArgs.empty()) {
  92. throw std::invalid_argument("A child executable must be specified.");
  93. }
  94. #ifdef _WIN32
  95. // Set the bInheritHandle flag so pipe handles are inherited.
  96. SECURITY_ATTRIBUTES securityAttributes;
  97. securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
  98. securityAttributes.bInheritHandle = true;
  99. securityAttributes.lpSecurityDescriptor = NULL;
  100. // Create a pipe for the child process's STDOUT.
  101. HANDLE childStdOutAtChild;
  102. HANDLE childStdOutAtParent;
  103. HANDLE childStdInAtChild;
  104. HANDLE childStdInAtParent;
  105. int bufferSize = 0;
  106. if (!CreatePipe(&childStdOutAtParent,
  107. &childStdOutAtChild,
  108. &securityAttributes,
  109. bufferSize)) {
  110. throw std::runtime_error("Error from CreatePipe for stdout: " +
  111. getErrorText());
  112. }
  113. // Ensure the read handle to the pipe for STDOUT is not inherited.
  114. int inheritFlag = 0;
  115. if (!SetHandleInformation(childStdOutAtParent,
  116. HANDLE_FLAG_INHERIT,
  117. inheritFlag) ) {
  118. throw std::runtime_error("Error from GetHandleInformation for stdout: " +
  119. getErrorText());
  120. }
  121. // Create a pipe for the child process's STDIN.
  122. if (! CreatePipe(&childStdInAtChild,
  123. &childStdInAtParent,
  124. &securityAttributes,
  125. bufferSize)) {
  126. throw std::runtime_error("Error from CreatePipe for stdin: " +
  127. getErrorText());
  128. }
  129. // Ensure the write handle to the pipe for STDIN is not inherited.
  130. if (!SetHandleInformation(childStdInAtParent,
  131. HANDLE_FLAG_INHERIT,
  132. inheritFlag)) {
  133. throw std::runtime_error("Error from GetHandleInformation for stdin: " +
  134. getErrorText());
  135. }
  136. // Set up members of the PROCESS_INFORMATION structure.
  137. PROCESS_INFORMATION processInfo;
  138. std::fill((char *) &processInfo,
  139. ((char *) &processInfo) + sizeof(PROCESS_INFORMATION),
  140. 0);
  141. // Set up members of the STARTUPINFO structure. This structure
  142. // specifies the STDIN and STDOUT handles for redirection.
  143. STARTUPINFO startInfo;
  144. std::fill((char *) &startInfo,
  145. ((char *) &startInfo) + sizeof(STARTUPINFO),
  146. 0);
  147. startInfo.cb = sizeof(STARTUPINFO);
  148. startInfo.hStdError = childStdOutAtChild;
  149. startInfo.hStdOutput = childStdOutAtChild;
  150. startInfo.hStdInput = childStdInAtChild;
  151. startInfo.dwFlags |= STARTF_USESTDHANDLES;
  152. // Assemble the command line.
  153. std::string cmdline;
  154. if (cmdArgs.size() == 1) {
  155. cmdline = cmdArgs[0];
  156. } else {
  157. // Append all but last command-line arguments.
  158. for (size_t i = 0; i < cmdArgs.size() - 1; i++) {
  159. cmdline += cmdArgs[i] + " ";
  160. }
  161. cmdline += cmdArgs.back(); // Append last command-line argument.
  162. }
  163. // Create the child process.
  164. bool status;
  165. status = CreateProcess(NULL,
  166. (char *) cmdline.c_str(),
  167. NULL, // process security attributes
  168. NULL, // primary thread security attributes
  169. true, // handles are inherited
  170. 0, // creation flags
  171. NULL, // use parent's environment
  172. NULL, // use parent's current directory
  173. &startInfo, // STARTUPINFO pointer
  174. &processInfo); // receives PROCESS_INFORMATION
  175. // If an error occurs, exit the application.
  176. if (!status ) {
  177. throw std::runtime_error("Error from CreateProcess with "
  178. "command line \"" + cmdline + "\": " +
  179. getErrorText());
  180. }
  181. // Provide the stream buffers with the handles for communicating
  182. // with the child process.
  183. childStreambuf.setInputHandle(childStdOutAtParent);
  184. childStreambuf.setOutputHandle(childStdInAtParent);
  185. // Save the handles to the child process and its primary thread.
  186. childProcess = processInfo.hProcess;
  187. childThread = processInfo.hThread;
  188. // Close the child's end of the pipes.
  189. if (!CloseHandle(childStdOutAtChild)) {
  190. throw std::runtime_error("Error closing the child process "
  191. "stdout handle: " + getErrorText());
  192. }
  193. if (!CloseHandle(childStdInAtChild)) {
  194. throw std::runtime_error("Error closing the child process "
  195. "stdin handle: " + getErrorText());
  196. }
  197. #else
  198. // Create the pipes for the stdin and stdout.
  199. int childStdInPipe[2];
  200. int childStdOutPipe[2];
  201. if (pipe(childStdInPipe) != 0) {
  202. throw std::runtime_error("Error creating pipe for stdin: " +
  203. getErrorText());
  204. }
  205. if (pipe(childStdOutPipe) != 0) {
  206. ::close(childStdInPipe[0]);
  207. ::close(childStdInPipe[1]);
  208. throw std::runtime_error("Error creating pipe for stdout: " +
  209. getErrorText());
  210. }
  211. // Create the child process.
  212. childPid = fork();
  213. if (-1 == childPid) {
  214. for (int i = 0; i < 2; i++) {
  215. ::close(childStdInPipe[i]);
  216. ::close(childStdOutPipe[i]);
  217. }
  218. throw std::runtime_error("Error creating child process: " +
  219. getErrorText());
  220. }
  221. if (0 == childPid) {
  222. // The child executes this. Redirect stdin.
  223. if (dup2(childStdInPipe[0], STDIN_FILENO) == -1) {
  224. std::string errMsg;
  225. // Send message to parent.
  226. errMsg = "Error redirecting stdin in the child: " + getErrorText();
  227. ::write(childStdOutPipe[1], errMsg.data(), errMsg.size());
  228. exit(-1);
  229. }
  230. // Redirect stdout.
  231. if (dup2(childStdOutPipe[1], STDOUT_FILENO) == -1) {
  232. std::string errMsg;
  233. // Send message to parent.
  234. errMsg = "Error redirecting stdout in the child: " + getErrorText();
  235. ::write(childStdOutPipe[1], errMsg.data(), errMsg.size());
  236. exit(-1);
  237. }
  238. // Close pipes.
  239. if ( (::close(childStdInPipe[0]) != 0) ||
  240. (::close(childStdInPipe[1]) != 0) ||
  241. (::close(childStdOutPipe[0]) != 0) ||
  242. (::close(childStdOutPipe[1]) != 0) ) {
  243. std::string errMsg;
  244. // Send message to parent.
  245. errMsg = "Error closing the pipes in the child: " + getErrorText();
  246. ::write(STDOUT_FILENO, errMsg.data(), errMsg.size());
  247. exit(-1);
  248. }
  249. // Prepare the arguments.
  250. std::vector<const char *> execvArgv;
  251. for (auto &arg : cmdArgs) {
  252. execvArgv.push_back(arg.c_str());
  253. }
  254. execvArgv.push_back((char *) NULL);
  255. // Run the child process image.
  256. (void) execv(execvArgv[0], (char * const *) &(execvArgv[0]));
  257. // Error from exec.
  258. std::string errMsg;
  259. // Send message to parent.
  260. errMsg = "Error from exec: " + getErrorText();
  261. ::write(STDOUT_FILENO, errMsg.data(), errMsg.size());
  262. exit(-1);
  263. }
  264. // Provide the stream buffers with the file descriptors for
  265. // communicating with the child process.
  266. childStreambuf.setInputFileDescriptor(childStdOutPipe[0]);
  267. childStreambuf.setOutputFileDescriptor(childStdInPipe[1]);
  268. // Close the child's end of the pipes.
  269. if ( (::close(childStdInPipe[0]) != 0) ||
  270. (::close(childStdOutPipe[1]) != 0) ) {
  271. std::string errMsg;
  272. throw std::runtime_error("Error closing child's end of pipes in "
  273. "the parent: " + getErrorText());
  274. }
  275. #endif
  276. childStarted = true;
  277. }
  278. void ChildStream::close() {
  279. if (!childStarted) {
  280. throw std::logic_error("Child process was not started "
  281. "when close() was called");
  282. }
  283. // Terminate the child if it's running.
  284. if (isRunning()) {
  285. std::string errorString;
  286. bool errorOccurred = false;
  287. #ifdef _WIN32
  288. if (!TerminateProcess(childProcess, terminateExitCode)) {
  289. errorString += (errorOccurred ? "\n" : "");
  290. errorString += "Error terminating the child process: " +
  291. getErrorText();
  292. errorOccurred = true;
  293. }
  294. #else
  295. if (kill(childPid, SIGKILL) != 0) {
  296. errorString += (errorOccurred ? "\n" : "");
  297. errorString += "Error terminating the child process: " +
  298. getErrorText();
  299. errorOccurred = true;
  300. } else if (waitpid(childPid, NULL, 0) != childPid) {
  301. errorString += (errorOccurred ? "\n" : "");
  302. errorString += "Error waiting for the child process: " +
  303. getErrorText();
  304. errorOccurred = true;
  305. }
  306. #endif
  307. if (errorOccurred) {
  308. throw std::runtime_error(errorString);
  309. }
  310. }
  311. // Reset.
  312. init();
  313. }
  314. bool ChildStream::isDone() {
  315. if (childExited) {
  316. return true;
  317. }
  318. if (!childStarted) {
  319. throw std::logic_error("Child process was not started "
  320. "when isDone() was called");
  321. }
  322. int result;
  323. #ifdef _WIN32
  324. if (!GetExitCodeProcess(childProcess, (LPDWORD) &result)) {
  325. throw std::runtime_error("Error checking status of child process: " +
  326. getErrorText());
  327. }
  328. if (STILL_ACTIVE == result) {
  329. return false;
  330. }
  331. // Child process has exited. Save the exit code.
  332. exitCode = result;
  333. exitCodeObtainedFlag = true;
  334. #else
  335. int status = 0;
  336. result = waitpid(childPid, &status, WNOHANG);
  337. if (-1 == result) {
  338. throw std::runtime_error("Error checking status of child process: " +
  339. getErrorText());
  340. } else if (0 == result) {
  341. // Child is still running.
  342. return false;
  343. }
  344. if (WIFEXITED(status)) {
  345. // Child exited normally.
  346. exitCode = WEXITSTATUS(status);
  347. exitCodeObtainedFlag = true;
  348. }
  349. #endif
  350. childExited = true;
  351. return true;
  352. }
  353. int32_t ChildStream::result() {
  354. if (exitCodeObtainedFlag) {
  355. return exitCode;
  356. }
  357. // Check whether the process is running, and get the exit code.
  358. if (!isDone()) {
  359. throw std::logic_error("Child process was still running "
  360. "when result() was called");
  361. }
  362. // Child process has exited.
  363. if (!exitCodeObtainedFlag) {
  364. // Exit code is not available.
  365. throw std::runtime_error("Child process has exited but the exit "
  366. "code is not available");
  367. }
  368. return exitCode;
  369. }
  370. std::string ChildStream::getErrorText() {
  371. #ifdef _WIN32
  372. LPVOID winMsgBuf;
  373. DWORD lastError = GetLastError();
  374. FormatMessage(
  375. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  376. FORMAT_MESSAGE_FROM_SYSTEM |
  377. FORMAT_MESSAGE_IGNORE_INSERTS,
  378. NULL,
  379. lastError,
  380. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  381. (char *) &winMsgBuf,
  382. 0, NULL );
  383. std::string errMsg((char *) winMsgBuf);
  384. LocalFree(winMsgBuf);
  385. return errMsg;
  386. #else
  387. return strerror(errno);
  388. #endif
  389. }
  390. ChildStream::ChildStreambuf::ChildStreambuf(std::size_t bufSize) :
  391. #ifdef _WIN32
  392. inputHandle(0),
  393. outputHandle(0),
  394. #else
  395. inputFileDescriptor(-1),
  396. outputFileDescriptor(-1),
  397. #endif
  398. bufferSize(bufSize),
  399. readBuffer(bufferSize + 1),
  400. writeBuffer(bufferSize + 1) {
  401. // Read buffer initialization.
  402. char *end = &(readBuffer.front()) + readBuffer.size();
  403. // Indicate to underflow that underflow has not been called.
  404. setg(end, end, end);
  405. // Write buffer initialization.
  406. char *base = &(writeBuffer.front());
  407. // Indicate to overflow that overflow has not been called.
  408. setp(base, base + writeBuffer.size() - 1);
  409. }
  410. #ifdef _WIN32
  411. void ChildStream::ChildStreambuf::setInputHandle(HANDLE inHandle) {
  412. inputHandle = inHandle;
  413. }
  414. #else
  415. void ChildStream::ChildStreambuf::setInputFileDescriptor(int inFd) {
  416. inputFileDescriptor = inFd;
  417. }
  418. #endif
  419. size_t ChildStream::ChildStreambuf::numBytesAvailable() const {
  420. size_t nBytesAvailable = egptr() - gptr();
  421. #ifdef _WIN32
  422. DWORD lpTotalBytesAvail;
  423. if (!PeekNamedPipe(inputHandle,
  424. NULL,
  425. 0,
  426. NULL,
  427. &lpTotalBytesAvail,
  428. NULL)) {
  429. throw std::runtime_error("Error from PeekNamedPipe: " +
  430. getErrorText());
  431. }
  432. if (lpTotalBytesAvail > 0) {
  433. nBytesAvailable++;
  434. }
  435. #else
  436. fd_set readFd;
  437. int retVal;
  438. struct timeval timeout = {0, 0};
  439. FD_ZERO(&readFd);
  440. FD_SET(inputFileDescriptor, &readFd);
  441. // Check if input is available.
  442. retVal = select(inputFileDescriptor + 1, &readFd, NULL, NULL, &timeout);
  443. if (-1 == retVal) {
  444. throw std::runtime_error("Error from select(): " + getErrorText());
  445. } else if (retVal > 0) {
  446. nBytesAvailable++;
  447. }
  448. #endif
  449. return nBytesAvailable;
  450. }
  451. std::streambuf::int_type ChildStream::ChildStreambuf::underflow() {
  452. // Check for empty buffer.
  453. if (gptr() < egptr()) {
  454. // Not empty.
  455. return traits_type::to_int_type(*gptr());
  456. }
  457. // Need to fill the buffer.
  458. char *base = &(readBuffer.front());
  459. char *start = base;
  460. // Check whether this is the first fill.
  461. if (eback() == base) {
  462. // Not the first fill. Copy one putback character.
  463. *(eback()) = *(egptr() - 1);
  464. start++;
  465. }
  466. // start points to the start of the buffer. Fill buffer.
  467. #ifdef _WIN32
  468. DWORD nBytesRead;
  469. if (!ReadFile(inputHandle,
  470. start,
  471. readBuffer.size() - (start - base),
  472. &nBytesRead,
  473. NULL)) {
  474. return traits_type::eof();
  475. }
  476. #else
  477. ssize_t nBytesRead;
  478. nBytesRead = ::read(inputFileDescriptor,
  479. start,
  480. readBuffer.size() - (start - base));
  481. if (-1 == nBytesRead) {
  482. return traits_type::eof();
  483. }
  484. #endif
  485. // Check for EOF.
  486. if (0 == nBytesRead) {
  487. return traits_type::eof();
  488. }
  489. // Update buffer pointers.
  490. setg(base, start, start + nBytesRead);
  491. return traits_type::to_int_type(*gptr());
  492. }
  493. #ifdef _WIN32
  494. void ChildStream::ChildStreambuf::setOutputHandle(HANDLE outHandle) {
  495. outputHandle = outHandle;
  496. }
  497. #else
  498. void ChildStream::ChildStreambuf::setOutputFileDescriptor(int outFd) {
  499. outputFileDescriptor = outFd;
  500. }
  501. #endif
  502. void ChildStream::ChildStreambuf::flushBuffer() {
  503. // Write.
  504. std::ptrdiff_t nBytes = pptr() - pbase();
  505. #ifdef _WIN32
  506. DWORD nBytesWritten;
  507. if (!WriteFile(outputHandle,
  508. pbase(),
  509. nBytes,
  510. &nBytesWritten,
  511. NULL)) {
  512. // Clear the output buffer.
  513. pbump(-nBytes);
  514. throw std::runtime_error("Error writing to child process: " +
  515. getErrorText());
  516. }
  517. #else
  518. ssize_t nBytesWritten;
  519. nBytesWritten = ::write(outputFileDescriptor, pbase(), nBytes);
  520. #endif
  521. // Clear the output buffer.
  522. pbump(-nBytes);
  523. if (nBytes != nBytesWritten) {
  524. throw std::runtime_error("Not all data was written to to child "
  525. "process: " + getErrorText());
  526. }
  527. return;
  528. }
  529. std::streambuf::int_type ChildStream::ChildStreambuf::overflow(int_type ch) {
  530. // Check whether we're writing EOF.
  531. if (traits_type::eof() != ch) {
  532. // Not writing EOF.
  533. *(pptr()) = ch;
  534. pbump(1);
  535. // Write.
  536. flushBuffer();
  537. // Success.
  538. return ch;
  539. }
  540. return traits_type::eof();
  541. }
  542. int ChildStream::ChildStreambuf::sync() {
  543. flushBuffer(); // Throws exception on failure.
  544. // Success.
  545. return 1;
  546. }
  547. Child::CircularBuffer::CircularBuffer(size_t maxSize) :
  548. buffer(maxSize + 1),
  549. capacity(maxSize) {
  550. iBegin = 0;
  551. iEnd = 0;
  552. }
  553. bool Child::CircularBuffer::empty() const {
  554. return (iBegin == iEnd);
  555. }
  556. size_t Child::CircularBuffer::nUsed() const {
  557. return capacity - nFree();
  558. }
  559. void Child::CircularBuffer::clear() {
  560. iBegin = 0;
  561. iEnd = 0;
  562. }
  563. size_t Child::CircularBuffer::nFree() const {
  564. size_t iLocalBegin = iBegin;
  565. // Correct an invalid value.
  566. if (iLocalBegin >= capacity + 1) {
  567. iLocalBegin = 0;
  568. }
  569. if (iLocalBegin <= iEnd) {
  570. return capacity - (iEnd - iLocalBegin);
  571. }
  572. return iLocalBegin - iEnd - 1;
  573. }
  574. void Child::CircularBuffer::put(char const *ptr, size_t nBytes) {
  575. for (size_t i = 0; i < nBytes; i++) {
  576. buffer[iEnd] = *ptr;
  577. ptr++;
  578. nextIndex(iEnd);
  579. }
  580. }
  581. void Child::CircularBuffer::getAndErase(std::string &buf, size_t nBytes) {
  582. if ( (0 == nBytes) || (nBytes > nUsed()) ) {
  583. nBytes = nUsed();
  584. }
  585. buf.clear();
  586. if (buf.capacity() < nBytes) {
  587. buf.reserve(nBytes);
  588. }
  589. for (size_t i = 0; i < nBytes; i++) {
  590. buf.push_back(buffer[iBegin]);
  591. nextIndex(iBegin);
  592. }
  593. }
  594. Child::Child(std::vector<std::string> const &args,
  595. size_t bufSize,
  596. std::uint16_t nominalAboveMinPollTime_ms,
  597. std::uint16_t deltaPollTime_ms) :
  598. bufferCapacity(bufSize),
  599. readBuffer(bufferCapacity),
  600. writeBuffer(bufferCapacity),
  601. nominalPollTime_ms(nominalAboveMinPollTime_ms +
  602. CodeDweller::MinimumSleeperTime),
  603. maximumPollTime_ms(nominalPollTime_ms + deltaPollTime_ms) {
  604. init();
  605. open(args);
  606. }
  607. Child::Child(std::string const &childpath,
  608. size_t bufSize,
  609. std::uint16_t nominalAboveMinPollTime_ms,
  610. std::uint16_t deltaPollTime_ms) :
  611. bufferCapacity(bufSize),
  612. readBuffer(bufferCapacity),
  613. writeBuffer(bufferCapacity),
  614. nominalPollTime_ms(nominalAboveMinPollTime_ms +
  615. CodeDweller::MinimumSleeperTime),
  616. maximumPollTime_ms(nominalPollTime_ms + deltaPollTime_ms) {
  617. init();
  618. open(childpath);
  619. }
  620. Child::Child(size_t bufSize,
  621. std::uint16_t nominalAboveMinPollTime_ms,
  622. std::uint16_t deltaPollTime_ms) :
  623. bufferCapacity(bufSize),
  624. readBuffer(bufferCapacity),
  625. writeBuffer(bufferCapacity),
  626. nominalPollTime_ms(nominalAboveMinPollTime_ms +
  627. CodeDweller::MinimumSleeperTime),
  628. maximumPollTime_ms(nominalPollTime_ms + deltaPollTime_ms) {
  629. init();
  630. }
  631. Child::~Child() {
  632. try {
  633. close();
  634. } catch (std::exception &e) {
  635. ;
  636. }
  637. }
  638. void Child::open(std::vector<std::string> const &args) {
  639. cmdArgs = args;
  640. if (isRunning()) {
  641. throw std::logic_error("The child process was already active.");
  642. }
  643. init();
  644. run();
  645. }
  646. void Child::open(std::string const &childpath) {
  647. if (isRunning()) {
  648. throw std::logic_error("The child process was already active.");
  649. }
  650. cmdArgs.clear();
  651. cmdArgs.push_back(childpath);
  652. init();
  653. run();
  654. }
  655. void Child::init() {
  656. childStarted = false;
  657. childExited = false;
  658. exitCodeObtainedFlag = false;
  659. exitCode = 0;
  660. readBuffer.clear();
  661. nWriteBytes = 0;
  662. nTransmitBytes = 0;
  663. threadsAreRunning = false;
  664. stopFlag = true;
  665. errorText.clear();
  666. }
  667. bool Child::write(std::string const &data) {
  668. if (!isRunning()) {
  669. throw std::logic_error("No child process is running.");
  670. }
  671. // The free space in the write buffer can be checked without
  672. // locking the mutex because:
  673. //
  674. // 1) bufferCapacity is unchanging, and
  675. //
  676. // 2) nWriteBytes is only decreased by the writer thread.
  677. //
  678. // This means that the calculated free space can only increase by
  679. // the action of the writer thread; the calculated free space is a
  680. // minimum value. In the worst case, this method would return
  681. // false unnecessarily.
  682. if (data.size() > bufferCapacity - nWriteBytes) {
  683. return false;
  684. }
  685. std::lock_guard<std::mutex> lock(writeBufferMutex);
  686. std::copy(data.data(),
  687. data.data() + data.size(),
  688. &(writeBuffer[nWriteBytes]));
  689. nWriteBytes += data.size();
  690. return true;
  691. }
  692. size_t Child::writeAndShrink(std::string &data) {
  693. if (!isRunning()) {
  694. throw std::logic_error("No child process is running.");
  695. }
  696. // See the comment above regarding checking the free space in the
  697. // write buffer without locking the mutex.
  698. size_t nFree = bufferCapacity - nWriteBytes;
  699. if (0 == nFree) {
  700. return 0;
  701. }
  702. std::lock_guard<std::mutex> lock(writeBufferMutex);
  703. size_t nBytesToCopy = data.size();
  704. if (nBytesToCopy > nFree) {
  705. nBytesToCopy = nFree;
  706. }
  707. std::copy(data.data(),
  708. data.data() + nBytesToCopy,
  709. &(writeBuffer[nWriteBytes]));
  710. nWriteBytes += nBytesToCopy;
  711. data.erase(0, nBytesToCopy);
  712. return nBytesToCopy;
  713. }
  714. bool Child::isFinishedWriting() const {
  715. return ( (0 == nWriteBytes) &&
  716. (0 == nTransmitBytes) );
  717. }
  718. size_t Child::read(std::string &data, size_t nBytes) {
  719. if (!isRunning()) {
  720. throw std::logic_error("No child process is running.");
  721. }
  722. data.clear();
  723. // Whether the read circular buffer is empty can be checked
  724. // without locking the mutex because:
  725. //
  726. if (readBuffer.empty()) {
  727. return 0;
  728. }
  729. std::lock_guard<std::mutex> lock(readBufferMutex);
  730. size_t nBytesToRead = nBytes;
  731. if (nBytesToRead > readBuffer.nUsed()) {
  732. nBytesToRead = readBuffer.nUsed();
  733. }
  734. readBuffer.getAndErase(data, nBytesToRead);
  735. return data.size();
  736. }
  737. void Child::close() {
  738. if (!childStarted) {
  739. throw std::logic_error("Child process was not started "
  740. "when close() was called");
  741. }
  742. // Stop the reader and writer threads. Note: None of the error
  743. // conditions that cause an exception to be thrown by join()
  744. // can ever occur.
  745. stopFlag = true;
  746. // Terminate the child if it's running.
  747. if (isRunning()) {
  748. std::string errorString;
  749. bool errorOccurred = false;
  750. #ifdef _WIN32
  751. if (!CloseHandle(inputHandle)) {
  752. errorString = "Error closing input from the child: " + getErrorText();
  753. errorOccurred = true;
  754. }
  755. if (!CloseHandle(outputHandle)) {
  756. errorString += (errorOccurred ? "\n" : "");
  757. errorString += "Error closing output to the child: " + getErrorText();
  758. errorOccurred = true;
  759. }
  760. if (!TerminateProcess(childProcess, terminateExitCode)) {
  761. errorString += (errorOccurred ? "\n" : "");
  762. errorString += "Error terminating the child process: " +
  763. getErrorText();
  764. errorOccurred = true;
  765. }
  766. #else
  767. if (0 != ::close(inputFileDescriptor)) {
  768. errorString = "Error closing input from the child: " + getErrorText();
  769. errorOccurred = true;
  770. }
  771. if (0 != ::close(outputFileDescriptor)) {
  772. errorString += (errorOccurred ? "\n" : "");
  773. errorString += "Error closing output to the child: " + getErrorText();
  774. errorOccurred = true;
  775. }
  776. if (kill(childPid, SIGKILL) != 0) {
  777. errorString += (errorOccurred ? "\n" : "");
  778. errorString += "Error terminating the child process: " +
  779. getErrorText();
  780. errorOccurred = true;
  781. } else if (waitpid(childPid, NULL, 0) != childPid) {
  782. errorString += (errorOccurred ? "\n" : "");
  783. errorString += "Error waiting for the child process: " +
  784. getErrorText();
  785. errorOccurred = true;
  786. }
  787. #endif
  788. if (errorOccurred) {
  789. throw std::runtime_error(errorString);
  790. }
  791. }
  792. if (threadsAreRunning) {
  793. readerThread.join();
  794. writerThread.join();
  795. threadsAreRunning = false;
  796. }
  797. // Reset.
  798. init();
  799. }
  800. bool Child::isRunning() const {
  801. return childStarted && !childExited;
  802. }
  803. bool Child::errorOccurred(std::string &errorDescription) const {
  804. errorDescription = errorText;
  805. return !errorDescription.empty();
  806. }
  807. void Child::run() {
  808. if (childStarted) {
  809. throw std::logic_error("Child process was active when "
  810. "run() was called");
  811. }
  812. if (cmdArgs.empty()) {
  813. throw std::invalid_argument("A child executable must be specified.");
  814. }
  815. #ifdef _WIN32
  816. // Set the bInheritHandle flag so pipe handles are inherited.
  817. SECURITY_ATTRIBUTES securityAttributes;
  818. securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
  819. securityAttributes.bInheritHandle = true;
  820. securityAttributes.lpSecurityDescriptor = NULL;
  821. // Create a pipe for the child process's STDOUT.
  822. HANDLE childStdOutAtChild;
  823. HANDLE childStdOutAtParent;
  824. HANDLE childStdInAtChild;
  825. HANDLE childStdInAtParent;
  826. int bufferSize = 0;
  827. if (!CreatePipe(&childStdOutAtParent,
  828. &childStdOutAtChild,
  829. &securityAttributes,
  830. bufferSize)) {
  831. throw std::runtime_error("Error from CreatePipe for stdout: " +
  832. getErrorText());
  833. }
  834. // Ensure the read handle to the pipe for STDOUT is not inherited.
  835. int inheritFlag = 0;
  836. if (!SetHandleInformation(childStdOutAtParent,
  837. HANDLE_FLAG_INHERIT,
  838. inheritFlag) ) {
  839. throw std::runtime_error("Error from GetHandleInformation for stdout: " +
  840. getErrorText());
  841. }
  842. // Create a pipe for the child process's STDIN.
  843. if (! CreatePipe(&childStdInAtChild,
  844. &childStdInAtParent,
  845. &securityAttributes,
  846. bufferSize)) {
  847. throw std::runtime_error("Error from CreatePipe for stdin: " +
  848. getErrorText());
  849. }
  850. // Ensure the write handle to the pipe for STDIN is not inherited.
  851. if (!SetHandleInformation(childStdInAtParent,
  852. HANDLE_FLAG_INHERIT,
  853. inheritFlag)) {
  854. throw std::runtime_error("Error from GetHandleInformation for stdin: " +
  855. getErrorText());
  856. }
  857. // Set up members of the PROCESS_INFORMATION structure.
  858. PROCESS_INFORMATION processInfo;
  859. std::fill((char *) &processInfo,
  860. ((char *) &processInfo) + sizeof(PROCESS_INFORMATION),
  861. 0);
  862. // Set up members of the STARTUPINFO structure. This structure
  863. // specifies the STDIN and STDOUT handles for redirection.
  864. STARTUPINFO startInfo;
  865. std::fill((char *) &startInfo,
  866. ((char *) &startInfo) + sizeof(STARTUPINFO),
  867. 0);
  868. startInfo.cb = sizeof(STARTUPINFO);
  869. startInfo.hStdError = childStdOutAtChild;
  870. startInfo.hStdOutput = childStdOutAtChild;
  871. startInfo.hStdInput = childStdInAtChild;
  872. startInfo.dwFlags |= STARTF_USESTDHANDLES;
  873. // Assemble the command line.
  874. std::string cmdline;
  875. if (cmdArgs.size() == 1) {
  876. cmdline = cmdArgs[0];
  877. } else {
  878. // Append all but last command-line arguments.
  879. for (size_t i = 0; i < cmdArgs.size() - 1; i++) {
  880. cmdline += cmdArgs[i] + " ";
  881. }
  882. cmdline += cmdArgs.back(); // Append last command-line argument.
  883. }
  884. // Create the child process.
  885. bool status;
  886. status = CreateProcess(NULL,
  887. (char *) cmdline.c_str(),
  888. NULL, // process security attributes
  889. NULL, // primary thread security attributes
  890. true, // handles are inherited
  891. 0, // creation flags
  892. NULL, // use parent's environment
  893. NULL, // use parent's current directory
  894. &startInfo, // STARTUPINFO pointer
  895. &processInfo); // receives PROCESS_INFORMATION
  896. // If an error occurs, exit the application.
  897. if (!status ) {
  898. throw std::runtime_error("Error from CreateProcess with "
  899. "command line \"" + cmdline + "\": " +
  900. getErrorText());
  901. }
  902. // Provide the stream buffers with the handles for communicating
  903. // with the child process.
  904. inputHandle = childStdOutAtParent;
  905. outputHandle = childStdInAtParent;
  906. // Save the handles to the child process and its primary thread.
  907. childProcess = processInfo.hProcess;
  908. childThread = processInfo.hThread;
  909. // Close the child's end of the pipes.
  910. if (!CloseHandle(childStdOutAtChild)) {
  911. throw std::runtime_error("Error closing the child process "
  912. "stdout handle: " + getErrorText());
  913. }
  914. if (!CloseHandle(childStdInAtChild)) {
  915. throw std::runtime_error("Error closing the child process "
  916. "stdin handle: " + getErrorText());
  917. }
  918. #else
  919. // Create the pipes for the stdin and stdout.
  920. int childStdInPipe[2];
  921. int childStdOutPipe[2];
  922. if (pipe(childStdInPipe) != 0) {
  923. throw std::runtime_error("Error creating pipe for stdin: " +
  924. getErrorText());
  925. }
  926. if (pipe(childStdOutPipe) != 0) {
  927. ::close(childStdInPipe[0]);
  928. ::close(childStdInPipe[1]);
  929. throw std::runtime_error("Error creating pipe for stdout: " +
  930. getErrorText());
  931. }
  932. // Create the child process.
  933. childPid = fork();
  934. if (-1 == childPid) {
  935. for (int i = 0; i < 2; i++) {
  936. ::close(childStdInPipe[i]);
  937. ::close(childStdOutPipe[i]);
  938. }
  939. throw std::runtime_error("Error creating child process: " +
  940. getErrorText());
  941. }
  942. if (0 == childPid) {
  943. // The child executes this. Redirect stdin.
  944. if (dup2(childStdInPipe[0], STDIN_FILENO) == -1) {
  945. std::string errMsg;
  946. // Send message to parent.
  947. errMsg = "Error redirecting stdin in the child: " + getErrorText();
  948. ::write(childStdOutPipe[1], errMsg.data(), errMsg.size());
  949. exit(-1);
  950. }
  951. // Redirect stdout.
  952. if (dup2(childStdOutPipe[1], STDOUT_FILENO) == -1) {
  953. std::string errMsg;
  954. // Send message to parent.
  955. errMsg = "Error redirecting stdout in the child: " + getErrorText();
  956. ::write(childStdOutPipe[1], errMsg.data(), errMsg.size());
  957. exit(-1);
  958. }
  959. // Close pipes.
  960. if ( (::close(childStdInPipe[0]) != 0) ||
  961. (::close(childStdInPipe[1]) != 0) ||
  962. (::close(childStdOutPipe[0]) != 0) ||
  963. (::close(childStdOutPipe[1]) != 0) ) {
  964. std::string errMsg;
  965. // Send message to parent.
  966. errMsg = "Error closing the pipes in the child: " + getErrorText();
  967. ::write(STDOUT_FILENO, errMsg.data(), errMsg.size());
  968. exit(-1);
  969. }
  970. // Prepare the arguments.
  971. std::vector<const char *> execvArgv;
  972. for (auto &arg : cmdArgs) {
  973. execvArgv.push_back(arg.c_str());
  974. }
  975. execvArgv.push_back((char *) NULL);
  976. // Run the child process image.
  977. (void) execv(execvArgv[0], (char * const *) &(execvArgv[0]));
  978. // Error from exec.
  979. std::string errMsg;
  980. // Send message to parent.
  981. errMsg = "Error from exec: " + getErrorText();
  982. ::write(STDOUT_FILENO, errMsg.data(), errMsg.size());
  983. exit(-1);
  984. }
  985. // Provide the stream buffers with the file descriptors for
  986. // communicating with the child process.
  987. inputFileDescriptor = childStdOutPipe[0];
  988. outputFileDescriptor = childStdInPipe[1];
  989. // Close the child's end of the pipes.
  990. if ( (::close(childStdInPipe[0]) != 0) ||
  991. (::close(childStdOutPipe[1]) != 0) ) {
  992. std::string errMsg;
  993. throw std::runtime_error("Error closing child's end of pipes in "
  994. "the parent: " + getErrorText());
  995. }
  996. #endif
  997. childStarted = true;
  998. // Start the reader and writer threads.
  999. stopFlag = false;
  1000. try {
  1001. std::thread readerTemp(&Child::readFromChild, this);
  1002. readerThread = std::move(readerTemp);
  1003. } catch (std::exception &e) {
  1004. throw std::runtime_error("Error starting reader thread: " +
  1005. getErrorText());
  1006. }
  1007. try {
  1008. std::thread writerTemp(&Child::writeToChild, this);
  1009. writerThread = std::move(writerTemp);
  1010. } catch (std::exception &e) {
  1011. stopFlag = true;
  1012. readerThread.join();
  1013. throw std::runtime_error("Error starting writer thread: " +
  1014. getErrorText());
  1015. }
  1016. threadsAreRunning = true;
  1017. }
  1018. bool Child::isDone() {
  1019. if (childExited) {
  1020. return true;
  1021. }
  1022. if (!childStarted) {
  1023. throw std::logic_error("Child process was not started "
  1024. "when isDone() was called");
  1025. }
  1026. int result;
  1027. #ifdef _WIN32
  1028. if (!GetExitCodeProcess(childProcess, (LPDWORD) &result)) {
  1029. throw std::runtime_error("Error checking status of child process: " +
  1030. getErrorText());
  1031. }
  1032. if (STILL_ACTIVE == result) {
  1033. return false;
  1034. }
  1035. // Child process has exited. Save the exit code.
  1036. exitCode = result;
  1037. exitCodeObtainedFlag = true;
  1038. #else
  1039. int status = 0;
  1040. result = waitpid(childPid, &status, WNOHANG);
  1041. if (-1 == result) {
  1042. throw std::runtime_error("Error checking status of child process: " +
  1043. getErrorText());
  1044. } else if (0 == result) {
  1045. // Child is still running.
  1046. return false;
  1047. }
  1048. if (WIFEXITED(status)) {
  1049. // Child exited normally.
  1050. exitCode = WEXITSTATUS(status);
  1051. exitCodeObtainedFlag = true;
  1052. }
  1053. #endif
  1054. childExited = true;
  1055. // Stop threads.
  1056. stopFlag = true;
  1057. readerThread.join();
  1058. writerThread.join();
  1059. threadsAreRunning = false;
  1060. return true;
  1061. }
  1062. int32_t Child::result() {
  1063. if (exitCodeObtainedFlag) {
  1064. return exitCode;
  1065. }
  1066. // Check whether the process is running, and get the exit code.
  1067. if (!isDone()) {
  1068. throw std::logic_error("Child process was still running "
  1069. "when result() was called");
  1070. }
  1071. // Child process has exited.
  1072. if (!exitCodeObtainedFlag) {
  1073. // Exit code is not available.
  1074. throw std::runtime_error("Child process has exited but the exit "
  1075. "code is not available");
  1076. }
  1077. return exitCode;
  1078. }
  1079. std::string Child::getErrorText() {
  1080. #ifdef _WIN32
  1081. LPVOID winMsgBuf;
  1082. DWORD lastError = GetLastError();
  1083. FormatMessage(
  1084. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  1085. FORMAT_MESSAGE_FROM_SYSTEM |
  1086. FORMAT_MESSAGE_IGNORE_INSERTS,
  1087. NULL,
  1088. lastError,
  1089. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  1090. (char *) &winMsgBuf,
  1091. 0, NULL );
  1092. std::string errMsg((char *) winMsgBuf);
  1093. LocalFree(winMsgBuf);
  1094. return errMsg;
  1095. #else
  1096. return strerror(errno);
  1097. #endif
  1098. }
  1099. void Child::readFromChild() {
  1100. std::vector<char> rxBuf(bufferCapacity);
  1101. CodeDweller::PollTimer pollTimer(nominalPollTime_ms, maximumPollTime_ms);
  1102. auto sleepTime = std::chrono::milliseconds(maximumPollTime_ms);
  1103. while (!stopFlag) {
  1104. char *bufferPtr;
  1105. bufferPtr = &(rxBuf[0]);
  1106. // Blocking read from the child.
  1107. #ifdef _WIN32
  1108. DWORD nBytesRead;
  1109. if (!ReadFile(inputHandle,
  1110. bufferPtr,
  1111. bufferCapacity,
  1112. &nBytesRead,
  1113. NULL)) {
  1114. if (stopFlag) {
  1115. break;
  1116. }
  1117. errorText = "Error reading from the child process: ";
  1118. errorText += getErrorText();
  1119. break;
  1120. }
  1121. #else
  1122. ssize_t nBytesRead;
  1123. nBytesRead = ::read(inputFileDescriptor,
  1124. bufferPtr,
  1125. bufferCapacity);
  1126. if (-1 == nBytesRead) {
  1127. if (stopFlag) {
  1128. break;
  1129. }
  1130. errorText = "Error reading from the child process: ";
  1131. errorText += getErrorText();
  1132. break;
  1133. } else if (0 == nBytesRead) {
  1134. // EOF; child exited.
  1135. break;
  1136. }
  1137. #endif
  1138. // Copy to the shared read buffer.
  1139. while ((nBytesRead > 0) && !stopFlag) {
  1140. int nBytesToPut, nBytesFree;
  1141. nBytesToPut = nBytesRead;
  1142. // Can be called in the reader thread without locking the
  1143. // mutex.
  1144. nBytesFree = readBuffer.nFree();
  1145. if (nBytesToPut > nBytesFree) {
  1146. nBytesToPut = nBytesFree;
  1147. }
  1148. if (nBytesToPut > 0) {
  1149. std::lock_guard<std::mutex> lock(readBufferMutex);
  1150. readBuffer.put(bufferPtr, nBytesToPut);
  1151. bufferPtr += nBytesToPut;
  1152. nBytesRead -= nBytesToPut;
  1153. pollTimer.reset();
  1154. } else {
  1155. pollTimer.pause();
  1156. }
  1157. }
  1158. }
  1159. }
  1160. void Child::writeToChild() {
  1161. std::vector<char> localWriteBuffer(bufferCapacity);
  1162. size_t nLocalWriteBytes;
  1163. CodeDweller::PollTimer pollTimer(nominalPollTime_ms, maximumPollTime_ms);
  1164. auto sleepTime = std::chrono::milliseconds(maximumPollTime_ms);
  1165. while (!stopFlag) {
  1166. char *bufferPtr;
  1167. // Poll for data in the shared write buffer.
  1168. while ((0 == nWriteBytes) && !stopFlag) {
  1169. pollTimer.pause();
  1170. }
  1171. if (stopFlag) {
  1172. goto exit;
  1173. }
  1174. // Copy from the shared write buffer.
  1175. {
  1176. std::lock_guard<std::mutex> lock(writeBufferMutex);
  1177. localWriteBuffer.swap(writeBuffer);
  1178. nLocalWriteBytes = nWriteBytes;
  1179. nWriteBytes = 0;
  1180. }
  1181. if (stopFlag) {
  1182. goto exit;
  1183. }
  1184. pollTimer.reset();
  1185. // Blocking write to the child.
  1186. bufferPtr = &(localWriteBuffer[0]);
  1187. while (nLocalWriteBytes > 0) {
  1188. #ifdef _WIN32
  1189. DWORD nBytesWritten;
  1190. if (!WriteFile(outputHandle,
  1191. bufferPtr,
  1192. nLocalWriteBytes,
  1193. &nBytesWritten,
  1194. NULL)) {
  1195. if (stopFlag) {
  1196. goto exit;
  1197. }
  1198. errorText = "Error writing to the child process: ";
  1199. errorText += getErrorText();
  1200. goto exit;
  1201. }
  1202. if (stopFlag) {
  1203. goto exit;
  1204. }
  1205. #else
  1206. ssize_t nBytesWritten;
  1207. nBytesWritten = ::write(outputFileDescriptor,
  1208. bufferPtr,
  1209. nLocalWriteBytes);
  1210. if (stopFlag) {
  1211. goto exit;
  1212. }
  1213. if (-1 == nBytesWritten) {
  1214. if (ENOSPC != errno) {
  1215. // Some error other than no space.
  1216. errorText = "Error writing to the child process: ";
  1217. errorText += getErrorText();
  1218. goto exit;
  1219. }
  1220. }
  1221. #endif
  1222. nLocalWriteBytes -= nBytesWritten;
  1223. bufferPtr += nBytesWritten;
  1224. }
  1225. }
  1226. exit: return;
  1227. }
  1228. }