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

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