1 // mongo/shell/shell_utils_launcher.h 2 3 /** 4 * Copyright (C) 2018-present MongoDB, Inc. 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the Server Side Public License, version 1, 8 * as published by MongoDB, Inc. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * Server Side Public License for more details. 14 * 15 * You should have received a copy of the Server Side Public License 16 * along with this program. If not, see 17 * <http://www.mongodb.com/licensing/server-side-public-license>. 18 * 19 * As a special exception, the copyright holders give permission to link the 20 * code of portions of this program with the OpenSSL library under certain 21 * conditions as described in each individual source file and distribute 22 * linked combinations including the program with the OpenSSL library. You 23 * must comply with the Server Side Public License in all respects for 24 * all of the code used other than as permitted herein. If you modify file(s) 25 * with this exception, you may extend this exception to your version of the 26 * file(s), but you are not obligated to do so. If you do not wish to do so, 27 * delete this exception statement from your version. If you delete this 28 * exception statement from all source files in the program, then also delete 29 * it in the license file. 30 */ 31 32 #pragma once 33 34 #include <boost/filesystem/convenience.hpp> 35 #include <map> 36 #include <sstream> 37 #include <string> 38 #include <utility> 39 #include <vector> 40 41 #include "mongo/bson/bsonobj.h" 42 #include "mongo/platform/process_id.h" 43 #include "mongo/platform/unordered_map.h" 44 #include "mongo/platform/unordered_set.h" 45 #include "mongo/stdx/mutex.h" 46 #include "mongo/stdx/thread.h" 47 48 namespace mongo { 49 50 class Scope; 51 52 namespace shell_utils { 53 54 // Scoped management of mongo program instances. Simple implementation: 55 // destructor kills all mongod instances created by the shell. 56 struct MongoProgramScope { MongoProgramScopeMongoProgramScope57 MongoProgramScope() {} // Avoid 'unused variable' warning. 58 ~MongoProgramScope(); 59 }; 60 int KillMongoProgramInstances(); 61 62 // Returns true if there are running child processes. 63 std::vector<ProcessId> getRunningMongoChildProcessIds(); 64 65 void installShellUtilsLauncher(Scope& scope); 66 67 /** Record log lines from concurrent programs. All public members are thread safe. */ 68 class ProgramOutputMultiplexer { 69 public: 70 void appendLine(int port, ProcessId pid, const std::string& name, const std::string& line); 71 std::string str() const; 72 void clear(); 73 74 private: 75 std::stringstream _buffer; 76 }; 77 78 /** 79 * A registry of spawned programs that are identified by a bound port or else a system pid. 80 * All public member functions are thread safe. 81 */ 82 class ProgramRegistry { 83 public: 84 bool isPortRegistered(int port) const; 85 /** @return pid for a registered port. */ 86 ProcessId pidForPort(int port) const; 87 /** @return port (-1 if doesn't exist) for a registered pid. */ 88 int portForPid(ProcessId pid) const; 89 /** Register an unregistered program. */ 90 void registerProgram(ProcessId pid, int port = -1); 91 /** Registers the reader thread for the PID. Must be called before `joinReaderThread`. */ 92 void registerReaderThread(ProcessId pid, stdx::thread reader); 93 /** Closes the registered program's write pipe and waits for all of the written output to be 94 * consumed by the reader thread, then removes the program from the registry */ 95 void unregisterProgram(ProcessId pid); 96 97 bool isPidRegistered(ProcessId pid) const; 98 void getRegisteredPorts(std::vector<int>& ports); 99 void getRegisteredPids(std::vector<ProcessId>& pids); 100 101 private: 102 stdx::unordered_set<ProcessId> _registeredPids; 103 stdx::unordered_map<int, ProcessId> _portToPidMap; 104 stdx::unordered_map<ProcessId, stdx::thread> _outputReaderThreads; 105 mutable stdx::recursive_mutex _mutex; 106 107 #ifdef _WIN32 108 private: 109 std::map<ProcessId, HANDLE> _handles; 110 111 public: 112 HANDLE getHandleForPid(ProcessId pid); 113 void eraseHandleForPid(ProcessId pid); 114 std::size_t countHandleForPid(ProcessId pid); 115 void insertHandleForPid(ProcessId pid, HANDLE handle); 116 117 #endif 118 }; 119 120 /** Helper class for launching a program and logging its output. */ 121 class ProgramRunner { 122 public: 123 /** @param args The program's arguments, including the program name. 124 * @param env Environment to run the program with, which will override any set by the local 125 * environment 126 * @param isMongo Indicator variable, true if runs as a mongo process. 127 */ 128 ProgramRunner(const BSONObj& args, const BSONObj& env, bool isMongo); 129 /** Launch the program. */ 130 void start(); 131 /** Continuously read the program's output, generally from a special purpose thread. */ 132 void operator()(); pid()133 ProcessId pid() const { 134 return _pid; 135 } port()136 int port() const { 137 return _port; 138 } 139 140 private: 141 boost::filesystem::path findProgram(const std::string& prog); 142 void launchProcess(int child_stdout); 143 144 std::vector<std::string> _argv; 145 std::map<std::string, std::string> _envp; 146 int _port; 147 int _pipe; 148 ProcessId _pid; 149 std::string _name; 150 }; 151 } 152 } 153