Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

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