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.hpp 8.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. // \file child.hpp
  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. /*
  23. \brief The child module provides classes to spawn and communicate
  24. with child processes.
  25. */
  26. #ifndef CHILD_HPP
  27. #define CHILD_HPP
  28. #ifdef _WIN32
  29. #include <windows.h>
  30. #endif
  31. #include <cstdint>
  32. #include <streambuf>
  33. #include <iostream>
  34. #include <string>
  35. #include <vector>
  36. namespace CodeDweller {
  37. /**
  38. \namespace CodeDweller
  39. The CodeDweller namespace contains components providing high-level
  40. functionality for applications.
  41. */
  42. /** Class that abstracts the communication with a child process.
  43. This class provides functionality to create a child process,
  44. communicate with the child process via streams and signals, and
  45. obtain the exit code of the child process.
  46. */
  47. class ChildStream : public std::iostream {
  48. private:
  49. /// Streambuf class for reading from the standard output and
  50. /// writing to the standard input of the child process.
  51. class ChildStreambuf : public std::streambuf {
  52. friend class ChildStream;
  53. public:
  54. /// Constructor.
  55. //
  56. // \param[in] bufSize is the size in bytes of the input
  57. // buffer and output buffer.
  58. //
  59. explicit ChildStreambuf(std::size_t bufSize = 4096);
  60. /// Thread start function to send data to the child.
  61. void sendToChild();
  62. #ifdef _WIN32
  63. /// Set the handle to read the standard output of the child
  64. /// process.
  65. //
  66. // \param[in] inHandle is the input handle for the standard
  67. // output of the child process.
  68. //
  69. void setInputHandle(HANDLE inHandle);
  70. /// Set the handle to write the standard input of the child
  71. /// process.
  72. //
  73. // \param[in] outHandle is the output handle for the standard
  74. // input of the child process.
  75. //
  76. void setOutputHandle(HANDLE outHandle);
  77. #else
  78. /// Set the file descriptor to read the standard output of the
  79. /// child process.
  80. //
  81. // \param[in] inFd is the input file descriptor for the standard
  82. // output of the child process.
  83. //
  84. void setInputFileDescriptor(int inFd);
  85. /// Set the file descriptor to write the standard input of the
  86. /// child process.
  87. //
  88. // \param[in] outFd is the output file descriptor for the
  89. // standard input of the child process.
  90. //
  91. void setOutputFileDescriptor(int outFd);
  92. #endif
  93. private:
  94. /** Return the number of bytes that can be read without
  95. blocking.
  96. This method checks if any input is available from the pipe,
  97. and returns the number of bytes in the input buffer plus 1.
  98. Reading that number of bytes will not block. Reading a
  99. larger number of bytes might block.
  100. \returns minimum number of bytes that can be read without
  101. blocking.
  102. */
  103. size_t numBytesAvailable() const;
  104. /// Override streambuf::underflow().
  105. int_type underflow();
  106. /// Flush the output buffer.
  107. void flushBuffer();
  108. /// Override streambuf::overflow().
  109. int_type overflow(int_type ch);
  110. /// Override streambuf::sync().
  111. int sync();
  112. /// Input and output handles.
  113. #ifdef _WIN32
  114. HANDLE inputHandle;
  115. HANDLE outputHandle;
  116. #else
  117. int inputFileDescriptor;
  118. int outputFileDescriptor;
  119. #endif
  120. /// Size of buffers.
  121. std::size_t bufferSize;
  122. /// Read buffer.
  123. std::vector<char> readBuffer;
  124. /// Write buffer.
  125. std::vector<char> writeBuffer;
  126. /// Copy constructor not implemented.
  127. ChildStreambuf(const ChildStreambuf &) = delete;
  128. /// Assignment operator not implemented.
  129. ChildStreambuf &operator=(const ChildStreambuf &) = delete;
  130. };
  131. /// Stream buffer for reading from the stdout and writing to the
  132. /// stdin of the child process.
  133. ChildStreambuf childStreambuf;
  134. public:
  135. /** Constructor for spawning with command-line parameters.
  136. The constructor configures the object, and spawns the child
  137. process.
  138. \param[in] args contains the child executable file name and
  139. command-line parameters. args[0] contains the full path of the
  140. executable, and args[1] thru args[n] are the command-line
  141. parameters.
  142. \param[in] bufSize is the input and output buffer size of the
  143. stream used to communicate with the child process.
  144. \throws runtime_error if an error occurs.
  145. */
  146. ChildStream(std::vector<std::string> const &args, size_t bufSize = 4096);
  147. /** Constructor for spawning without command-line parameters.
  148. The constructor configures the object, and spawns the child
  149. process.
  150. \param[in] childpath contains the child executable file name.
  151. \param[in] bufSize is the input and output buffer size of the
  152. stream used to communicate with the child process.
  153. \throws runtime_error if an error occurs.
  154. */
  155. ChildStream(std::string const &childpath, size_t bufSize = 4096);
  156. /** Constructor.
  157. The constructor configures the I/O buffers, but doesn't spawn
  158. any child process.
  159. \param[in] bufSize is the input and output buffer size of the
  160. stream used to communicate with the child process.
  161. */
  162. ChildStream(size_t bufSize = 4096);
  163. /** Destructor terminates the child process. */
  164. ~ChildStream();
  165. /** Spawn the child process.
  166. \param[in] args contains the child executable file name and
  167. command-line parameters. args[0] contains the full path of the
  168. executable, and args[1] thru args[n] are the command-line
  169. parameters.
  170. \throws runtime_error if an error occurs.
  171. \throws runtime_error if an error occurs.
  172. */
  173. void open(std::vector<std::string> const &args);
  174. /** Spawn the child process.
  175. \param[in] childpath contains the child executable file name.
  176. \throws runtime_error if an error occurs.
  177. */
  178. void open(std::string const &childpath);
  179. /** Get the number of bytes available for input.
  180. @returns number of bytes that can be read without blocking.
  181. */
  182. size_t numBytesAvailable() const;
  183. /** Check whether the child process is running.
  184. \returns True if the child process is running, false
  185. otherwise.
  186. */
  187. bool isRunning() const;
  188. /** Terminite the child process.
  189. \throws runtime_error if an error occurs.
  190. \throws logic_error if the child process is not running.
  191. */
  192. void close();
  193. /** Check whether the child process has exited.
  194. \returns True if the child process has exited, false
  195. otherwise.
  196. \throws runtime_error if an error occurs.
  197. \throws logic_error if the child process is not running.
  198. */
  199. bool isDone();
  200. /** Get the exit value of the child process.
  201. \returns The exit value of the child process if the child
  202. process has exited.
  203. \throws runtime_error if an error occurs.
  204. \throws logic_error if the child process has not exited.
  205. \throws logic_error if the child process is not running.
  206. */
  207. int32_t result();
  208. private:
  209. /** Spawn the child process.
  210. \throws runtime_error if an error occurs.
  211. */
  212. void run();
  213. /// Exit code to use when terminating the child process.
  214. static const uint32_t terminateExitCode = 0;
  215. /// True if the child process was successfully started.
  216. bool childStarted;
  217. /// True if the child process has exited.
  218. bool childExited;
  219. /// Initialize data members.
  220. void init();
  221. /// Child executable path and command-line parameters.
  222. std::vector<std::string> cmdArgs;
  223. #ifdef _WIN32
  224. /// Child's process handle.
  225. HANDLE childProcess;
  226. /// Child's thread handle.
  227. HANDLE childThread;
  228. #else
  229. /// Child process ID.
  230. pid_t childPid;
  231. #endif
  232. /// Exit value of the process.
  233. int32_t exitCode;
  234. /// True if the exit code has been obtained.
  235. bool exitCodeObtainedFlag;
  236. /// Return text for the most recent error.
  237. //
  238. // \returns Human-readable description of the most recent error.
  239. //
  240. static std::string getErrorText();
  241. };
  242. }
  243. #endif // CHILD_HPP