Project
Loading...
Searching...
No Matches
GeneratorFileOrCmd.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
13
16// For fifo's and system call
17#include <cstdlib>
18#include <sys/types.h> // POSIX only
19#include <sys/stat.h> // POSIX only
20#include <csignal>
21#include <sys/wait.h>
22#include <cstdio>
23// For filesystem operations
24#include <filesystem>
25// Waits
26#include <thread>
27// Log messages
28#include <fairlogger/Logger.h>
29#include <SimConfig/SimConfig.h>
30
31namespace
32{
33std::string ltrim(const std::string& s, const std::string& what = "\" ' ")
34{
35 auto start = s.find_first_not_of(what);
36 if (start == std::string::npos) {
37 return "";
38 }
39
40 return s.substr(start);
41}
42
43std::string rtrim(const std::string& s, const std::string& what = "\"' ")
44{
45 auto end = s.find_last_not_of(what);
46 return s.substr(0, end + 1);
47}
48
49std::string trim(const std::string& s, const std::string& what = "\"' ")
50{
51 return rtrim(ltrim(s, what), what);
52}
53} // namespace
54
55namespace o2
56{
57namespace eventgen
58{
59// -----------------------------------------------------------------
61 const conf::SimConfig& config)
62{
63 setFileNames(param.fileNames);
64 setCmd(param.cmd);
65 setOutputSwitch(trim(param.outputSwitch));
66 setSeedSwitch(trim(param.seedSwitch));
67 setBmaxSwitch(trim(param.bMaxSwitch));
68 setNEventsSwitch(trim(param.nEventsSwitch));
69 setBackgroundSwitch(trim(param.backgroundSwitch));
70 setSeed(config.getStartSeed());
71 setNEvents(config.getNEvents());
72 setBmax(config.getBMax());
73}
74// -----------------------------------------------------------------
75// Switches are permanently set to default values
77 const conf::SimConfig& config)
78{
79 setFileNames(param.fileNames);
80 setCmd(param.cmd);
81 setOutputSwitch(">");
82 setSeedSwitch("-s");
83 setBmaxSwitch("-b");
84 setNEventsSwitch("-n");
86 setSeed(config.getStartSeed());
87 setNEvents(config.getNEvents());
88 setBmax(config.getBMax());
89}
90// -----------------------------------------------------------------
91void GeneratorFileOrCmd::setFileNames(const std::string& filenames)
92{
93 std::stringstream s(filenames);
94 std::string f;
95 while (std::getline(s, f, ',')) {
96 mFileNames.push_back(f);
97 }
98}
99// -----------------------------------------------------------------
101{
102 std::string fileName = mFileNames.front();
103 std::stringstream s;
104 s << mCmd << " ";
105 if (not mSeedSwitch.empty() and mSeedSwitch != "none") {
106 s << mSeedSwitch << " " << mSeed << " ";
107 }
108 if (not mNEventsSwitch.empty() and mNEventsSwitch != "none") {
109 s << mNEventsSwitch << " " << mNEvents << " ";
110 }
111 if (not mBmaxSwitch.empty() and mBmax >= 0 and mBmaxSwitch != "none") {
112 s << mBmaxSwitch.c_str() << " " << mBmax << " ";
113 }
114
115 s << mOutputSwitch << " " << fileName << " "
117 return s.str();
118}
119// -----------------------------------------------------------------
120bool GeneratorFileOrCmd::executeCmdLine(const std::string& cmd)
121{
122 LOG(info) << "Command line to execute: \"" << cmd << "\"";
123 // Fork a new process
124 pid_t pid = fork();
125 if (pid == -1) {
126 LOG(fatal) << "Failed to fork process: " << std::strerror(errno);
127 return false;
128 }
129
130 if (pid == 0) {
131 // Child process
132 setsid();
133 execl("/bin/sh", "sh", "-c", cmd.c_str(), (char*)nullptr);
134 // If execl returns, there was an error, otherwise following lines will not be executed
135 LOG(fatal) << "Failed to execute command: " << std::strerror(errno);
136 _exit(EXIT_FAILURE);
137 } else {
138 // Parent process
139 setCmdPid(pid);
140 LOG(info) << "Child spawned process group is running with PID: " << mCmdPid;
141 }
142 return true;
143}
144// -----------------------------------------------------------------
146{
147 if (mCmdPid == -1) {
148 LOG(info) << "No command is currently running";
149 return false;
150 }
151
152 LOG(info) << "Terminating process ID group " << mCmdPid;
153 if (kill(-mCmdPid, SIGKILL) == -1) {
154 LOG(fatal) << "Failed to kill process: " << std::strerror(errno);
155 return false;
156 }
157
158 // Wait for the process to terminate
159 int status;
160 if (waitpid(mCmdPid, &status, 0) == -1) {
161 LOG(fatal) << "Failed to wait for process termination: " << std::strerror(errno);
162 return false;
163 }
164
165 mCmdPid = -1; // Reset the process ID
166 return true;
167}
168// -----------------------------------------------------------------
169bool GeneratorFileOrCmd::makeTemp(const bool& fromName)
170{
171 if (fromName) {
172 if (mFileNames.empty()) {
173 LOG(fatal) << "No file names to make temporary file from";
174 return false;
175 } else if (mFileNames.size() > 1) {
176 LOG(warning) << "More than one file name to make temporary file from";
177 LOG(warning) << "Using the first one: " << mFileNames.front();
178 LOG(warning) << "Removing all the others";
179 mFileNames.erase(++mFileNames.begin(), mFileNames.end());
180 } else {
181 LOG(debug) << "Making temporary file from: " << mFileNames.front();
182 }
183 std::ofstream ofs(mFileNames.front().c_str());
184 if (!ofs) {
185 LOG(fatal) << "Failed to create temporary file: " << mFileNames.front();
186 return false;
187 }
188 mTemporary = std::string(mFileNames.front());
189 ofs.close();
190 } else {
191 mFileNames.clear();
192 char buf[] = "generatorFifoXXXXXX";
193 auto fp = mkstemp(buf);
194 if (fp < 0) {
195 LOG(fatal) << "Failed to make temporary file: "
196 << std::strerror(errno);
197 return false;
198 }
199 mTemporary = std::string(buf);
200 mFileNames.push_back(mTemporary);
201 close(fp);
202 }
203 return true;
204}
205// -----------------------------------------------------------------
207{
208 if (mTemporary.empty()) {
209 LOG(info) << "Temporary file name empty, nothing to remove";
210 return false;
211 }
212
213 // Get the file we're reading from
214 std::filesystem::path p(mTemporary);
215
216 // Check if the file exists
217 if (not std::filesystem::exists(p)) {
218 LOG(info) << "Temporary file " << p << " does not exist";
219 return true;
220 }
221
222 // Remove temporary file
223 std::error_code ec;
224 std::filesystem::remove(p, ec);
225 if (ec) {
226 LOG(warn) << "When removing " << p << ": " << ec.message();
227 }
228
229 // Ignore errors when removing the temporary file
230 return true;
231}
232// -----------------------------------------------------------------
234{
235 // First remove the temporary file if it exists,
236 // otherwise we may not be able to make the FIFO
237 removeTemp();
238
239 std::string fileName = mFileNames.front();
240
241 int ret = mkfifo(fileName.c_str(), 0600);
242 if (ret != 0) {
243 LOG(fatal) << "Failed to make fifo \"" << fileName << "\": "
244 << std::strerror(errno);
245 return false;
246 }
247
248 return true;
249}
250// -----------------------------------------------------------------
252{
253 try {
254 for (auto& f : mFileNames) {
255 auto c = std::filesystem::canonical(std::filesystem::path(f));
256 f = c.c_str();
257 }
258 } catch (std::exception& e) {
259 LOG(error) << e.what();
260 return false;
261 }
262 return true;
263}
264// -----------------------------------------------------------------
265void GeneratorFileOrCmd::waitForData(const std::string& filename) const
266{
267 using namespace std::chrono_literals;
268
269 // Get the file we're reading from
270 std::filesystem::path p(filename);
271
272 LOG(debug) << "Waiting for data on " << p;
273
274 // Wait until child process creates the file
275 while (not std::filesystem::exists(p)) {
276 std::this_thread::sleep_for(mWait * 1ms);
277 }
278
279 // Wait until we have more data in the file than just the file
280 // header
281 while (std::filesystem::file_size(p) <= 256) {
282 std::this_thread::sleep_for(mWait * 1ms);
283 }
284
285 // Give the child process 1 second to post the data to the file
286 LOG(debug) << "Got data in " << p << ", sleeping for a while";
287 std::this_thread::sleep_for(mWait * 2ms);
288}
289
290} /* namespace eventgen */
291} /* namespace o2 */
Utility functions for MC particles.
uint16_t pid
Definition RawData.h:2
uint32_t c
Definition RawData.h:2
std::ostringstream debug
ULong_t getStartSeed() const
Definition SimConfig.h:170
float getBMax() const
Definition SimConfig.h:161
unsigned int getNEvents() const
Definition SimConfig.h:156
GLuint GLuint end
Definition glcorearb.h:469
GLdouble f
Definition glcorearb.h:310
GLuint start
Definition glcorearb.h:469
GLenum GLfloat param
Definition glcorearb.h:271
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition glcorearb.h:2514
std::string trim(std::string const &str)
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
std::string filename()
void setCmdPid(const pid_t cmdPid)
void setBackgroundSwitch(const std::string &opt)
void setSeedSwitch(const std::string &opt)
void setFileNames(const std::string &filenames)
void setup(const GeneratorFileOrCmdParam &param, const conf::SimConfig &config)
std::list< std::string > mFileNames
void setSeed(unsigned long seed)
void setNEventsSwitch(const std::string &opt)
void setOutputSwitch(const std::string &opt)
void setCmd(const std::string &cmd)
virtual std::string makeCmdLine() const
virtual void waitForData(const std::string &filename) const
virtual bool executeCmdLine(const std::string &cmd)
virtual bool makeTemp(const bool &)
void setBmaxSwitch(const std::string &opt)
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"