Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 : Copyright (c) 2019-2023 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. 128 : Handler contStop() noexcept { 129 16 : return Handler(this); 130 : } 131 : }; 132 : 133 : template <class T> 134 32 : Subprocess& operator<<(Subprocess& ep,const T &t) { 135 32 : ep.parent_to_child<<t; 136 32 : return ep; 137 : } 138 : 139 : } 140 : 141 : #endif 142 :