21 #if !defined(WIN32) && !defined(__MINGW32__)
43 #include <sys/select.h>
45 #include <sys/types.h>
53 #include <sys/loadavg.h>
56 #if defined(__linux__)
57 #include <sys/prctl.h>
67 :
Executor(files, fileSettings, settings, suppressions, errorLogger)
68 , mExecuteCommand(std::move(executeCommand))
76 enum PipeSignal {REPORT_OUT=
'1',REPORT_ERROR=
'2', CHILD_END=
'5'};
78 explicit PipeWriter(
int pipe) : mWpipe(pipe) {}
80 void reportOut(
const std::string &outmsg,
Color c)
override {
81 writeToPipe(REPORT_OUT,
static_cast<char>(c) + outmsg);
85 writeToPipe(REPORT_ERROR, msg.
serialize());
88 void writeEnd(
const std::string& str)
const {
89 writeToPipe(CHILD_END, str);
94 void writeToPipeInternal(PipeSignal type,
const void* data, std::size_t to_write)
const
96 const ssize_t bytes_written = write(mWpipe, data, to_write);
97 if (bytes_written <= 0) {
98 const int err = errno;
99 std::cerr <<
"#### ThreadExecutor::writeToPipeInternal() error for type " << type <<
": " << std::strerror(err) << std::endl;
100 std::exit(EXIT_FAILURE);
103 if (bytes_written != to_write) {
104 std::cerr <<
"#### ThreadExecutor::writeToPipeInternal() error for type " << type <<
": insufficient data written (expected: " << to_write <<
" / got: " << bytes_written <<
")" << std::endl;
105 std::exit(EXIT_FAILURE);
109 void writeToPipe(PipeSignal type,
const std::string &data)
const
112 const auto t =
static_cast<char>(type);
113 writeToPipeInternal(type, &t, 1);
116 const auto len =
static_cast<unsigned int>(data.length());
118 static constexpr std::size_t l_size =
sizeof(
unsigned int);
119 writeToPipeInternal(type, &len, l_size);
122 writeToPipeInternal(type, data.c_str(), len);
131 std::size_t bytes_to_read;
135 bytes_to_read =
sizeof(char);
136 bytes_read = read(rpipe, &type, bytes_to_read);
137 if (bytes_read <= 0) {
147 if (bytes_read != bytes_to_read) {
148 std::cerr <<
"#### ThreadExecutor::handleRead(" << filename <<
") error (type): insufficient data read (expected: " << bytes_to_read <<
" / got: " << bytes_read <<
")" << std::endl;
149 std::exit(EXIT_FAILURE);
152 if (type != PipeWriter::REPORT_OUT && type != PipeWriter::REPORT_ERROR && type != PipeWriter::CHILD_END) {
153 std::cerr <<
"#### ThreadExecutor::handleRead(" << filename <<
") invalid type " << int(type) << std::endl;
154 std::exit(EXIT_FAILURE);
157 unsigned int len = 0;
158 bytes_to_read =
sizeof(len);
159 bytes_read = read(rpipe, &len, bytes_to_read);
160 if (bytes_read <= 0) {
161 const int err = errno;
162 std::cerr <<
"#### ThreadExecutor::handleRead(" << filename <<
") error (len) for type " << int(type) <<
": " << std::strerror(err) << std::endl;
163 std::exit(EXIT_FAILURE);
165 if (bytes_read != bytes_to_read) {
166 std::cerr <<
"#### ThreadExecutor::handleRead(" << filename <<
") error (len) for type" << int(type) <<
": insufficient data read (expected: " << bytes_to_read <<
" / got: " << bytes_read <<
")" << std::endl;
167 std::exit(EXIT_FAILURE);
170 std::string buf(len,
'\0');
171 char *data_start = &buf[0];
174 bytes_read = read(rpipe, data_start, bytes_to_read);
175 if (bytes_read <= 0) {
176 const int err = errno;
177 std::cerr <<
"#### ThreadExecutor::handleRead(" << filename <<
") error (buf) for type" << int(type) <<
": " << std::strerror(err) << std::endl;
178 std::exit(EXIT_FAILURE);
180 bytes_to_read -= bytes_read;
181 data_start += bytes_read;
182 }
while (bytes_to_read != 0);
185 if (type == PipeWriter::REPORT_OUT) {
190 }
else if (type == PipeWriter::REPORT_ERROR) {
195 std::cerr <<
"#### ThreadExecutor::handleRead(" << filename <<
") internal error: " << e.
errorMessage << std::endl;
196 std::exit(EXIT_FAILURE);
201 }
else if (type == PipeWriter::CHILD_END) {
202 result += std::stoi(buf);
211 #if defined(__QNX__) || defined(__HAIKU__)
220 if (getloadavg(&sample, 1) != 1) {
233 unsigned int fileCount = 0;
234 unsigned int result = 0;
236 const std::size_t totalfilesize = std::accumulate(
mFiles.cbegin(),
mFiles.cend(), std::size_t(0), [](std::size_t v,
const FileWithDetails& p) {
240 std::list<int> rpipes;
241 std::map<pid_t, std::string> childFile;
242 std::map<int, std::string> pipeFile;
243 std::size_t processedsize = 0;
244 std::list<FileWithDetails>::const_iterator iFile =
mFiles.cbegin();
245 std::list<FileSettings>::const_iterator iFileSettings =
mFileSettings.cbegin();
248 const size_t nchildren = childFile.size();
251 if (pipe(pipes) == -1) {
252 std::cerr <<
"#### ThreadExecutor::check, pipe() failed: "<< std::strerror(errno) << std::endl;
253 std::exit(EXIT_FAILURE);
256 const int flags = fcntl(pipes[0], F_GETFL, 0);
258 std::cerr <<
"#### ThreadExecutor::check, fcntl(F_GETFL) failed: "<< std::strerror(errno) << std::endl;
259 std::exit(EXIT_FAILURE);
262 if (fcntl(pipes[0], F_SETFL, flags) < 0) {
263 std::cerr <<
"#### ThreadExecutor::check, fcntl(F_SETFL) failed: "<< std::strerror(errno) << std::endl;
264 std::exit(EXIT_FAILURE);
267 const pid_t pid = fork();
270 std::cerr <<
"#### ThreadExecutor::check, Failed to create child process: "<< std::strerror(errno) << std::endl;
271 std::exit(EXIT_FAILURE);
272 }
else if (pid == 0) {
273 #if defined(__linux__)
274 prctl(PR_SET_PDEATHSIG, SIGHUP);
278 PipeWriter pipewriter(pipes[1]);
281 unsigned int resultOfCheck = 0;
284 resultOfCheck = fileChecker.
check(*iFileSettings);
289 resultOfCheck = fileChecker.
check(iFile->path());
293 pipewriter.writeEnd(std::to_string(resultOfCheck));
294 std::exit(EXIT_SUCCESS);
298 rpipes.push_back(pipes[0]);
300 childFile[pid] = iFileSettings->filename() +
' ' + iFileSettings->cfg;
301 pipeFile[pipes[0]] = iFileSettings->filename() +
' ' + iFileSettings->cfg;
304 childFile[pid] = iFile->path();
305 pipeFile[pipes[0]] = iFile->path();
309 if (!rpipes.empty()) {
312 for (std::list<int>::const_iterator rp = rpipes.cbegin(); rp != rpipes.cend(); ++rp)
317 const int r = select(*std::max_element(rpipes.cbegin(), rpipes.cend()) + 1, &rfds,
nullptr,
nullptr, &tv);
320 std::list<int>::iterator rp = rpipes.begin();
321 while (rp != rpipes.end()) {
322 if (FD_ISSET(*rp, &rfds)) {
324 const std::map<int, std::string>::iterator p = pipeFile.find(*rp);
325 if (p != pipeFile.end()) {
328 const bool readRes =
handleRead(*rp, result, name);
330 std::size_t size = 0;
331 if (p != pipeFile.end()) {
334 return entry.path() == name;
342 processedsize += size;
347 rp = rpipes.erase(rp);
355 if (!childFile.empty()) {
357 const pid_t child = waitpid(0, &stat, WNOHANG);
359 std::string childname;
360 const std::map<pid_t, std::string>::iterator c = childFile.find(child);
361 if (c != childFile.end()) {
362 childname = c->second;
366 if (WIFEXITED(stat)) {
367 const int exitstatus = WEXITSTATUS(stat);
368 if (exitstatus != EXIT_SUCCESS) {
369 std::ostringstream oss;
370 oss <<
"Child process exited with " << exitstatus;
373 }
else if (WIFSIGNALED(stat)) {
374 std::ostringstream oss;
375 oss <<
"Child process crashed with signal " << WTERMSIG(stat);
380 if (iFile ==
mFiles.end() && iFileSettings ==
mFileSettings.end() && rpipes.empty() && childFile.empty()) {
395 std::list<ErrorMessage::FileLocation> locations;
396 locations.emplace_back(childname, 0, 0);
400 "Internal error: " + msg,
This is the base class which will use other classes to do static code analysis for C and C++ code to ...
static void printTimerResults(SHOWTIME_MODES mode)
Settings & settings()
Get reference to current settings.
std::function< int(std::string, std::vector< std::string >, std::string, std::string &)> ExecuteCmdFn
unsigned int check(const std::string &path)
This starts the actual checking.
void analyseClangTidy(const FileSettings &fileSettings)
Analyze all files using clang-tidy.
This is an interface, which the class responsible of error logging should implement.
virtual void reportErr(const ErrorMessage &msg)=0
Information about found errors and warnings is directed here.
virtual void reportOut(const std::string &outmsg, Color c=Color::Reset)=0
Information about progress is directed here.
Wrapper for error messages, provided by reportErr()
std::string serialize() const
void deserialize(const std::string &data)
This class will take a list of filenames and settings and check then all files using threads.
bool hasToLog(const ErrorMessage &msg)
Check if message is being suppressed and unique.
const std::list< FileSettings > & mFileSettings
SuppressionList & mSuppressions
const std::list< FileWithDetails > & mFiles
void reportStatus(std::size_t fileindex, std::size_t filecount, std::size_t sizedone, std::size_t sizetotal)
Information about how many files have been checked.
ErrorLogger & mErrorLogger
const Settings & mSettings
void reportInternalChildErr(const std::string &childname, const std::string &msg)
Reports internal errors related to child processes.
CppCheck::ExecuteCmdFn mExecuteCommand
bool checkLoadAverage(size_t nchildren)
Check load average condition.
bool handleRead(int rpipe, unsigned int &result, const std::string &filename)
Read from the pipe, parse and handle what ever is in there.
unsigned int check() override
ProcessExecutor(const std::list< FileWithDetails > &files, const std::list< FileSettings > &fileSettings, const Settings &settings, SuppressionList &suppressions, ErrorLogger &errorLogger, CppCheck::ExecuteCmdFn executeCommand)
This is just a container for general settings so that we don't need to pass individual values to func...
bool quiet
Is –quiet given?
int loadAverage
Load average value.
bool clangTidy
Use clang-tidy.
unsigned int jobs
How many processes/threads should do checking at the same time.
SHOWTIME_MODES showtime
show timing information (–showtime=file|summary|top5)
class for handling suppressions
bool isSuppressed(const ErrorMessage &errmsg, bool global=true)
Returns true if this message should not be shown to the user.
static const std::string emptyString
@ error
Programming error.
Simple container to be thrown when internal error is detected.