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 37KB

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