1
+ // Copyright 2024 Autoware Foundation
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
+ * @file cgroup_setter.cpp
17
+ * @brief Cgroup setter class
18
+ */
19
+
20
+ #include " cgroup_setter.hpp"
21
+ #include < iostream>
22
+ #include < fstream>
23
+ #include < sstream>
24
+ #include < cstring>
25
+ #include < unistd.h>
26
+ #include < boost/process.hpp>
27
+ #include < yaml-cpp/yaml.h>
28
+
29
+ namespace bp = boost::process;
30
+
31
+ CgroupSetter::CgroupSetter (const rclcpp::NodeOptions & options)
32
+ : Node(" cgroup_setter_node" , options),
33
+ updater_(this )
34
+ {
35
+ try {
36
+ std::string yaml_path = this ->declare_parameter <std::string>(" cgroup_setting_config_path" );
37
+ YAML::Node config = YAML::LoadFile (yaml_path);
38
+ if (config[" base_path" ]) {
39
+ base_path_ = config[" base_path" ].as <std::string>();
40
+ } else {
41
+ RCLCPP_ERROR (this ->get_logger (), " base_path is not set in the config file." );
42
+ return ;
43
+ }
44
+
45
+ if (!config[" settings" ]) {
46
+ RCLCPP_ERROR (this ->get_logger (), " settings is not set in the config file." );
47
+ return ;
48
+ }
49
+
50
+ for (auto setting : config[" settings" ]) {
51
+ if (!setting[" directory" ] || !setting[" search_word" ]) {
52
+ RCLCPP_ERROR (this ->get_logger (), " directory or search_word is not set in the config file." );
53
+ return ;
54
+ }
55
+
56
+ for (auto word : setting[" search_word" ]) {
57
+ std::pair<std::string, std::string> tmp_pair = std::make_pair (setting[" directory" ].as <std::string>(), word.as <std::string>());
58
+ cgroup_map_[tmp_pair] = false ;
59
+ }
60
+ }
61
+ } catch (const std::exception & e) {
62
+ RCLCPP_ERROR (this ->get_logger (), " Failed to load the config file." );
63
+ return ;
64
+ }
65
+
66
+ gethostname (hostname_, sizeof (hostname_));
67
+ updater_.setHardwareID (hostname_);
68
+ updater_.add (" Cgroup Setting" , this , &CgroupSetter::checkCgroup);
69
+
70
+ // Timer
71
+ using namespace std ::chrono_literals;
72
+ timer_ = rclcpp::create_timer (
73
+ this , this ->get_clock (), 1s, std::bind (&CgroupSetter::checkProcessAndAddToCgroup, this ));
74
+ }
75
+
76
+ void CgroupSetter::checkCgroup (diagnostic_updater::DiagnosticStatusWrapper & stat) {
77
+ bool allOK = true ;
78
+ for (auto & entry : cgroup_map_) {
79
+ if (entry.second ) {
80
+ stat.add (entry.first .first + " " + entry.first .second , " OK" );
81
+ } else {
82
+ allOK = false ;
83
+ stat.add (entry.first .first + " " + entry.first .second , " NG" );
84
+ }
85
+ }
86
+ if (allOK) {
87
+ if (timer_->is_active ()) timer->cancel ();
88
+ stat.summary (diagnostic_msgs::msg::DiagnosticStatus::OK, " All processes are added to cgroup." );
89
+ } else {
90
+ stat.summary (diagnostic_msgs::msg::DiagnosticStatus::WARN, " Some processes are not added to cgroup." );
91
+ }
92
+ }
93
+
94
+ void CgroupSetter::checkProcessAndAddToCgroup () {
95
+ for (auto & entry : cgroup_map_) {
96
+ if (entry.second ) {
97
+ continue ;
98
+ }
99
+ std::string word = entry.first .second ;
100
+ std::string result = executeCommand (word);
101
+ if (!result.empty ()) {
102
+ std::istringstream iss (result);
103
+ std::string pid;
104
+ bool allAdded = true ;
105
+ while (std::getline (iss, pid, ' \n ' )) {
106
+ if (!pid.empty () && addToCgroup (entry.first .first , pid)) {
107
+ if (checkPIDExists (base_path_ + " /" + entry.first .first + " /cgroup.procs" , pid)) {
108
+ RCLCPP_INFO (this ->get_logger (), " Added all PIDs to cgroup. %s %s" , entry.first .second .c_str (), pid.c_str ());
109
+ } else {
110
+ allAdded = false ;
111
+ RCLCPP_ERROR (this ->get_logger (), " Failed to add PID %s to cgroup. %s %s" , pid.c_str (), entry.first .second .c_str (), result.c_str ());
112
+ }
113
+ } else {
114
+ allAdded = false ;
115
+ RCLCPP_ERROR (this ->get_logger (), " Failed to add PID %s to cgroup. %s %s" , pid.c_str (), entry.first .second .c_str (), result.c_str ());
116
+ }
117
+ }
118
+ if (allAdded) {
119
+ entry.second = true ;
120
+ }
121
+ } else {
122
+ RCLCPP_ERROR (this ->get_logger (), " Failed to get PID. %s %s" , entry.first .second .c_str (), result.c_str ());
123
+ }
124
+ }
125
+ }
126
+
127
+ std::string CgroupSetter::executeCommand (const std::string& search_word) {
128
+ int out_fd[2 ];
129
+ if (pipe2 (out_fd, O_CLOEXEC) != 0 ) {
130
+ RCLCPP_ERROR (this ->get_logger (), " pipe2 error" );
131
+ return " " ;
132
+ }
133
+ bp::pipe out_pipe{out_fd[0 ], out_fd[1 ]};
134
+ bp::ipstream is_out{std::move (out_pipe)};
135
+
136
+ int err_fd[2 ];
137
+ if (pipe2 (err_fd, O_CLOEXEC) != 0 ) {
138
+ RCLCPP_ERROR (this ->get_logger (), " pipe2 error" );
139
+ return " " ;
140
+ }
141
+ bp::pipe err_pipe{err_fd[0 ], err_fd[1 ]};
142
+ bp::ipstream is_err{std::move (err_pipe)};
143
+ auto cmd=bp::search_path (" pgrep" );
144
+ std::vector<std::string> args;
145
+ args.push_back (" -f" );
146
+ args.push_back (search_word);
147
+ bp::child c (cmd, bp::args=args, bp::std_out > is_out, bp::std_err > is_err);
148
+ c.wait ();
149
+ if (c.exit_code () != 0 ) {
150
+ std::ostringstream os;
151
+ is_err >> os.rdbuf ();
152
+ RCLCPP_ERROR (this ->get_logger (), os.str ().c_str ());
153
+ return " " ;
154
+ } else {
155
+ std::ostringstream os;
156
+ os << is_out.rdbuf ();
157
+ std::string output = os.str ();
158
+ return output;
159
+ }
160
+ }
161
+
162
+ bool CgroupSetter::checkPIDExists (const std::string& filePath, const std::string & pid) {
163
+ std::ifstream file (filePath);
164
+ if (!file.is_open ()) {
165
+ RCLCPP_ERROR (this ->get_logger (), " Failed to open %s" , filePath.c_str ());
166
+ return false ;
167
+ }
168
+
169
+ std::string line;
170
+ while (std::getline (file, line)) {
171
+ if (line == pid) {
172
+ return true ;
173
+ }
174
+ }
175
+ return false ;
176
+ }
177
+
178
+ bool CgroupSetter::addToCgroup (const std::string& cgroupPath, const std::string& pid) {
179
+ std::string cgroupProcFile = base_path_ + " /" + cgroupPath + " /cgroup.procs" ;
180
+ std::ofstream ofs (cgroupProcFile, std::ofstream::app);
181
+ if (!ofs) {
182
+ std::cerr << " Failed to open " << cgroupProcFile << std::endl;
183
+ ofs.close ();
184
+ return false ;
185
+ }
186
+ ofs << pid;
187
+ if (!ofs) {
188
+ std::cerr << " Failed to write to " << cgroupProcFile << std::endl;
189
+ ofs.close ();
190
+ return false ;
191
+ }
192
+ ofs.close ();
193
+ return true ;
194
+ }
195
+
196
+ int main (int argc, char ** argv) {
197
+ rclcpp::init (argc, argv);
198
+ rclcpp::executors::SingleThreadedExecutor executor;
199
+ auto options = rclcpp::NodeOptions ();
200
+ auto node = std::make_shared<CgroupSetter>(options);
201
+ executor.add_node (node);
202
+ executor.spin ();
203
+ executor.remove_node (node);
204
+ rclcpp::shutdown ();
205
+ }
0 commit comments