SMACC2
Loading...
Searching...
No Matches
smacc_ros_launch_client_2.cpp
Go to the documentation of this file.
1// Copyright 2021 RobosoftAI Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15/*****************************************************************************************************************
16 *
17 * Authors: Pablo Inigo Blasco, Brett Aldrich
18 *
19 ******************************************************************************************************************/
20#include <errno.h> // Agrega esta inclusión
21#include <fcntl.h> // Agrega esta inclusión
22#include <poll.h>
23#include <signal.h>
24#include <stdio.h>
25#include <sys/types.h>
26#include <sys/wait.h>
27#include <unistd.h>
28#include <cstdio>
29#include <cstdlib>
30#include <cstring>
31#include <future>
32#include <iostream>
34#include <thread>
35
36namespace smacc2
37{
38namespace client_bases
39{
40using namespace std::chrono_literals;
41ClRosLaunch2::ClRosLaunch2(/*std::string packageName, std::string launchFilename*/)
42: /*packageName_(std::nullopt), launchFileName_(std::nullopt),*/ cancellationToken_(false)
43{
44}
45
47: packageName_(packageName), launchFileName_(launchFilename), cancellationToken_(false)
48{
49}
50
52
54{
55 cancellationToken_.store(false);
56 // Iniciar el hilo para la ejecución del lanzamiento
57 this->result_ = /*std::async([this]()*/
58 // {
60 // });
61}
62
64{
65 // Establecer la bandera de cancelación
66 cancellationToken_.store(true);
67}
68
69std::future<std::string> ClRosLaunch2::executeRosLaunch(
70 std::string packageName, std::string launchFileName, std::function<bool()> cancelCondition,
71 ClRosLaunch2 * client)
72// std::string ClRosLaunch2::executeRosLaunch(std::string packageName, std::string launchFileName, std::function<bool()> cancelCondition)
73{
74 return std::async(
75 std::launch::async,
77 {
78 RCLCPP_WARN_STREAM(rclcpp::get_logger("smacc2"), "[ClRosLaunch2] Starting ros launch thread");
79
80 std::stringstream cmd;
81 cmd << "ros2 launch " << packageName << " " << launchFileName;
82 std::array<char, 128> buffer;
83 std::string result;
84
85 auto child = runProcess(cmd.str().c_str());
86
87 if (!child.pipe)
88 {
89 throw std::runtime_error("popen() failed!");
90 }
91 if (client != nullptr)
92 {
93 client->launchPid_ = child.pid;
94 }
95
96 int fd = fileno(child.pipe);
97
98 int flags = fcntl(fd, F_GETFL, 0);
100
101 bool cancelled = false;
102
103 // while (!cancelCondition())
104 while (!cancelled)
105 {
107 size_t bytesRead = fread(buffer.data(), 1, buffer.size(), /*data*/ child.pipe);
108
109 if (bytesRead > 0)
110 {
111 result.append(buffer.data(), bytesRead);
112 }
113 else if (bytesRead == 0)
114 {
115 // No se han leído más datos
116 std::this_thread::sleep_for(
117 std::chrono::milliseconds(100)); // Espera antes de intentar nuevamente
118 }
119 else
120 {
121 // Error de lectura
122 RCLCPP_ERROR(rclcpp::get_logger("smacc2"), "Error de lectura en pipe");
123 break;
124 }
125 }
126
127 rclcpp::sleep_for(2s);
128 if (child.pid > 0)
129 {
131 rclcpp::sleep_for(2s);
132 }
133
134 int status;
135 pid_t child_pid = child.pid;
136 if (waitpid(child_pid, &status, 0) != -1)
137 {
138 if (WIFEXITED(status))
139 {
142 rclcpp::get_logger("smacc2"), "Child process exited with status: %d", exit_status);
143 }
144 else if (WIFSIGNALED(status))
145 {
148 rclcpp::get_logger("smacc2"), "Child process terminated by signal: %d", term_signal);
149 }
150 }
151 else
152 {
153 RCLCPP_ERROR(rclcpp::get_logger("smacc2"), "Error waiting for child process.");
154 }
155
156 pclose(child.pipe);
157 close(child.pipe->_fileno); // Close pipe file descriptor but not processes
158
159 RCLCPP_WARN_STREAM(rclcpp::get_logger("smacc2"), "[ClRosLaunch2] RESULT:\n" << result);
160
161 // Devuelve una std::future con el resultado
162 // return std::async(std::launch::async, [result]() { return result; });
163 return result;
164 });
165}
166
169
171{
173 info.pid = -1; // Inicializar el PID a -1 (indicando error)
174 info.pipe = nullptr;
175
176 int pipefd[2]; // Descriptor de archivo para el pipe
177
178 if (pipe(pipefd) == -1)
179 {
180 perror("pipe");
181 return info;
182 }
183
184 pid_t pid = fork();
185
186 if (pid == 0)
187 {
188 // Esto se ejecuta en el proceso hijo
189 close(pipefd[0]); // Cerramos el extremo de lectura del pipe en el proceso hijo
190 dup2(pipefd[1], STDOUT_FILENO); // Redireccionamos la salida estándar al pipe
191 close(pipefd[1]); // Cerramos el extremo de escritura del pipe en el proceso hijo
192
193 execl("/bin/sh", "/bin/sh", "-c", command, nullptr); // Ejecuta el comando dado
194
195 // Si execl retorna, significa que hubo un error
196 std::cerr << "Error al ejecutar el comando: " << command << std::endl;
197 _exit(1); // Usar _exit para evitar la ejecución de códigos de salida de manejo de errores
198 }
199 else if (pid > 0)
200 {
201 // Esto se ejecuta en el proceso padre
202 close(pipefd[1]); // Cerramos el extremo de escritura del pipe en el proceso padre
203 info.pid = pid;
204 info.pipe = fdopen(pipefd[0], "r"); // Abrir el descriptor de archivo de lectura en modo texto
205 }
206 else
207 {
208 std::cerr << "Error al crear el proceso hijo." << std::endl;
209 }
210
211 return info;
212}
213
215{
216 std::string command = "pgrep -P " + std::to_string(pid);
217 FILE * pipe = popen(command.c_str(), "r");
218
219 if (!pipe)
220 {
221 std::cerr << "Error executing pgrep command." << std::endl;
222 return;
223 }
224
225 char buffer[128];
226 std::string result = "";
227
228 while (fgets(buffer, sizeof(buffer), pipe) != NULL)
229 {
230 result += buffer;
231 }
232
233 pclose(pipe);
234
235 std::istringstream iss(result);
236 pid_t childPid;
237 std::vector<pid_t> childPids;
238
239 while (iss >> childPid)
240 {
241 childPids.push_back(childPid);
242 }
243
244 // Kill child processes before killing the parent process
245 for (const pid_t & child : childPids)
246 {
248 }
249
250 // After killing all children, kill the parent process
251 int res = kill(pid, SIGTERM);
252 if (res == 0)
253 {
254 RCLCPP_FATAL(rclcpp::get_logger("smacc2"), "Killed process %d", pid);
255 }
256}
257
259} // namespace client_bases
260} // namespace smacc2
261
262/*=============DOCUMENTATION=================*/
263
264/**************BASH VERSION*******************/
265/*************RECURSIVE KILL******************/
266// #!/bin/bash
267
268// # PID del proceso original (cambia esto al PID que desees)
269// original_pid=1119572
270
271// # Función recursiva para matar a los nietos
272// kill_grandchildren() {
273// local parent_pid=$1
274// local children=$(pgrep -P $parent_pid)
275
276// for child in $children; do
277// # Matar al hijo (nieto del proceso original)
278// kill -9 $child
279
280// # Llamar a la función de manera recursiva para matar a los nietos
281// kill_grandchildren $child
282// done
283// }
284
285// # Llamar a la función para matar a los nietos del proceso original
286// kill_grandchildren $original_pid
static std::future< std::string > executeRosLaunch(std::string packageName, std::string launchFilename, std::function< bool()> cancelCondition, ClRosLaunch2 *client=nullptr)
void killGrandchildren(pid_t originalPid)
ProcessInfo runProcess(const char *command)