1 /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2    Copyright (c) 2019-2021 The plumed team
3    (see the PEOPLE file at the root of the distribution for a list of names)
4 
5    See http://www.plumed.org for more information.
6 
7    This file is part of plumed, version 2.
8 
9    plumed is free software: you can redistribute it and/or modify
10    it under the terms of the GNU Lesser General Public License as published by
11    the Free Software Foundation, either version 3 of the License, or
12    (at your option) any later version.
13 
14    plumed is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU Lesser General Public License for more details.
18 
19    You should have received a copy of the GNU Lesser General Public License
20    along with plumed.  If not, see <http://www.gnu.org/licenses/>.
21 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
22 #ifndef __PLUMED_tools_Subprocess_h
23 #define __PLUMED_tools_Subprocess_h
24 
25 #include "OFile.h"
26 #include "IFile.h"
27 #include <string>
28 #include <cstdio>
29 #include <memory>
30 
31 namespace PLMD {
32 
33 /// Small class to avoid including unistd.h here
34 class SubprocessPid;
35 
36 /**
37 Class managing a subprocess.
38 
39 The subprocess is launched and one can interact with it through a pipe.
40 
41 In order not to consume resources, it might be possible to use this syntax:
42 
43 \verbatim
44 // at construction:
45 Subprocess sp;
46 sp.stop();
47 
48 // when needed
49 {
50   auto h=sp.contStop();
51   sp<<"command\n";
52   sp.flush();
53   sp.getline(answer);
54 }
55 // when h goes out of scope, subprocess is stopped again.
56 // If an exception is raised in the block, the subprocess is stopped as well.
57 \endverbatim
58 
59 \warning
60 Currently `stop` and `cont` are giving problems with some MPI implementation,
61 In addition, notice that the stop signal is only sent to the child process and
62 not to the subsequently spawn processes, so it might not work as intended.
63 This feature is left here but is probably no a good idea to use it.
64 It can be enabled with `export PLUMED_ENABLE_SIGNALS=1`.
65 
66 */
67 class Subprocess {
68   /// Process ID.
69   /// We store this rather than pid_t to avoid including <unistd.h> in this header file.
70   /// This remains nullptr in the child process.
71   std::unique_ptr<SubprocessPid> pid;
72   /// File descriptor, parent to child
73   int fpc=0;
74   /// File descriptor, child to parent
75   int fcp=0;
76   /// File pointer, parent to child
77   FILE* fppc=NULL;
78   /// File pointer, child to parent
79   FILE* fpcp=NULL;
80   /// PLUMED file object, parent to child.
81   /// Used to simplify formatting
82   OFile parent_to_child;
83   /// PLUMED file object, child to parent.
84   /// Used to simplify formatting
85   IFile child_to_parent;
86 public:
87   /// Class used to cont/stop a Subprocess in an exception safe manner.
88   class Handler {
89     Subprocess* sp=nullptr;
90     /// Private constructor.
91     /// Only to be called by Subprocess::contStop()
92     explicit Handler(Subprocess* sp) noexcept;
93     friend class Subprocess;
94   public:
95     /// Default constructor
96     Handler() = default;
97     /// Destructor stops the subprocess.
98     ~Handler();
99     /// Default copy constructor is deleted (not copyable)
100     Handler(const Handler &) = delete;
101     /// Default copy assignment is deleted (not copyable)
102     Handler & operator=(const Handler & handler) = delete;
103     /// Move constructor.
104     Handler(Handler &&) noexcept;
105     /// Move assignment.
106     Handler & operator=(Handler && handler) noexcept;
107   };
108 /// Constructor with a command line.
109   explicit Subprocess(const std::string & cmd);
110 /// Destructor
111   ~Subprocess();
112 /// Flush communication to process.
113   void flush();
114 /// Check if subprocess facilities are available.
115 /// If it returns false, any call to Subprocess constructor will raise an exception.
116   static bool available() noexcept;
117 /// Get a line from the subprocess.
118   Subprocess & getline(std::string &);
119 /// Write something to the subprocess.
120   template <class T> friend Subprocess& operator<<(Subprocess& ep,const T &t);
121 /// Send a SIGCONT to the subprocess.
122 /// Better used through contStop() method.
123   void cont() noexcept;
124 /// Send a SIGSTOP to the subprocess.
125 /// Better used through contStop() method.
126   void stop() noexcept;
127 /// Returns a handler to temporarily resume the process.
contStop()128   Handler contStop() noexcept {
129     return Handler(this);
130   }
131 };
132 
133 template <class T>
134 Subprocess& operator<<(Subprocess& ep,const T &t) {
135   ep.parent_to_child<<t;
136   return ep;
137 }
138 
139 }
140 
141 #endif
142 
143