Cppcheck
threadexecutor.cpp
Go to the documentation of this file.
1 /*
2  * Cppcheck - A tool for static C/C++ code analysis
3  * Copyright (C) 2007-2024 Cppcheck team.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
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  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "threadexecutor.h"
20 
21 #include "config.h"
22 #include "cppcheck.h"
23 #include "errorlogger.h"
24 #include "filesettings.h"
25 #include "settings.h"
26 #include "timer.h"
27 
28 #include <algorithm>
29 #include <cassert>
30 #include <cstdlib>
31 #include <future>
32 #include <iostream>
33 #include <list>
34 #include <numeric>
35 #include <mutex>
36 #include <system_error>
37 #include <utility>
38 #include <vector>
39 
40 enum class Color;
41 
42 ThreadExecutor::ThreadExecutor(const std::list<FileWithDetails> &files, const std::list<FileSettings>& fileSettings, const Settings &settings, SuppressionList &suppressions, ErrorLogger &errorLogger, CppCheck::ExecuteCmdFn executeCommand)
43  : Executor(files, fileSettings, settings, suppressions, errorLogger)
44  , mExecuteCommand(std::move(executeCommand))
45 {
46  assert(mSettings.jobs > 1);
47 }
48 
50 {
51 public:
52  explicit SyncLogForwarder(ThreadExecutor &threadExecutor, ErrorLogger &errorLogger)
53  : mThreadExecutor(threadExecutor), mErrorLogger(errorLogger) {}
54 
55  void reportOut(const std::string &outmsg, Color c) override
56  {
57  std::lock_guard<std::mutex> lg(mReportSync);
58 
59  mErrorLogger.reportOut(outmsg, c);
60  }
61 
62  void reportErr(const ErrorMessage &msg) override {
63  if (!mThreadExecutor.hasToLog(msg))
64  return;
65 
66  std::lock_guard<std::mutex> lg(mReportSync);
68  }
69 
70  void reportStatus(std::size_t fileindex, std::size_t filecount, std::size_t sizedone, std::size_t sizetotal) {
71  std::lock_guard<std::mutex> lg(mReportSync);
72  mThreadExecutor.reportStatus(fileindex, filecount, sizedone, sizetotal);
73  }
74 
75 private:
76  std::mutex mReportSync;
79 };
80 
82 {
83 public:
84  ThreadData(ThreadExecutor &threadExecutor, ErrorLogger &errorLogger, const Settings &settings, const std::list<FileWithDetails> &files, const std::list<FileSettings> &fileSettings, CppCheck::ExecuteCmdFn executeCommand)
85  : mFiles(files), mFileSettings(fileSettings), mSettings(settings), mExecuteCommand(std::move(executeCommand)), logForwarder(threadExecutor, errorLogger)
86  {
87  mItNextFile = mFiles.begin();
89 
90  mTotalFiles = mFiles.size() + mFileSettings.size();
91  mTotalFileSize = std::accumulate(mFiles.cbegin(), mFiles.cend(), std::size_t(0), [](std::size_t v, const FileWithDetails& p) {
92  return v + p.size();
93  });
94  }
95 
96  bool next(const std::string *&file, const FileSettings *&fs, std::size_t &fileSize) {
97  std::lock_guard<std::mutex> l(mFileSync);
98  if (mItNextFile != mFiles.end()) {
99  file = &mItNextFile->path();
100  fs = nullptr;
101  fileSize = mItNextFile->size();
102  ++mItNextFile;
103  return true;
104  }
105  if (mItNextFileSettings != mFileSettings.end()) {
106  file = nullptr;
107  fs = &(*mItNextFileSettings);
108  fileSize = 0;
110  return true;
111  }
112 
113  return false;
114  }
115 
116  unsigned int check(ErrorLogger &errorLogger, const std::string *file, const FileSettings *fs) const {
117  CppCheck fileChecker(errorLogger, false, mExecuteCommand);
118  fileChecker.settings() = mSettings; // this is a copy
119 
120  unsigned int result;
121  if (fs) {
122  // file settings..
123  result = fileChecker.check(*fs);
124  if (fileChecker.settings().clangTidy)
125  fileChecker.analyseClangTidy(*fs);
126  } else {
127  // Read file from a file
128  result = fileChecker.check(*file);
129  // TODO: call analyseClangTidy()?
130  }
131  return result;
132  }
133 
134  void status(std::size_t fileSize) {
135  std::lock_guard<std::mutex> l(mFileSync);
136  mProcessedSize += fileSize;
137  mProcessedFiles++;
138  if (!mSettings.quiet)
140  }
141 
142 private:
143  const std::list<FileWithDetails> &mFiles;
144  std::list<FileWithDetails>::const_iterator mItNextFile;
145  const std::list<FileSettings> &mFileSettings;
146  std::list<FileSettings>::const_iterator mItNextFileSettings;
147 
148  std::size_t mProcessedFiles{};
149  std::size_t mTotalFiles{};
150  std::size_t mProcessedSize{};
151  std::size_t mTotalFileSize{};
152 
153  std::mutex mFileSync;
156 
157 public:
159 };
160 
161 static unsigned int STDCALL threadProc(ThreadData *data)
162 {
163  unsigned int result = 0;
164 
165  const std::string *file;
166  const FileSettings *fs;
167  std::size_t fileSize;
168 
169  while (data->next(file, fs, fileSize)) {
170  result += data->check(data->logForwarder, file, fs);
171 
172  data->status(fileSize);
173  }
174 
175  return result;
176 }
177 
178 unsigned int ThreadExecutor::check()
179 {
180  std::vector<std::future<unsigned int>> threadFutures;
181  threadFutures.reserve(mSettings.jobs);
182 
184 
185  for (unsigned int i = 0; i < mSettings.jobs; ++i) {
186  try {
187  threadFutures.emplace_back(std::async(std::launch::async, &threadProc, &data));
188  }
189  catch (const std::system_error &e) {
190  std::cerr << "#### ThreadExecutor::check exception :" << e.what() << std::endl;
191  exit(EXIT_FAILURE);
192  }
193  }
194 
195  unsigned int result = std::accumulate(threadFutures.begin(), threadFutures.end(), 0U, [](unsigned int v, std::future<unsigned int>& f) {
196  return v + f.get();
197  });
198 
201 
202  return result;
203 }
This is the base class which will use other classes to do static code analysis for C and C++ code to ...
Definition: cppcheck.h:60
static void printTimerResults(SHOWTIME_MODES mode)
Definition: cppcheck.cpp:1850
Settings & settings()
Get reference to current settings.
Definition: cppcheck.cpp:1487
std::function< int(std::string, std::vector< std::string >, std::string, std::string &)> ExecuteCmdFn
Definition: cppcheck.h:62
unsigned int check(const std::string &path)
This starts the actual checking.
Definition: cppcheck.cpp:542
void analyseClangTidy(const FileSettings &fileSettings)
Analyze all files using clang-tidy.
Definition: cppcheck.cpp:1656
This is an interface, which the class responsible of error logging should implement.
Definition: errorlogger.h:214
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()
Definition: errorlogger.h:48
This class will take a list of filenames and settings and check then all files using threads.
Definition: executor.h:43
bool hasToLog(const ErrorMessage &msg)
Check if message is being suppressed and unique.
Definition: executor.cpp:41
const std::list< FileSettings > & mFileSettings
Definition: executor.h:72
const std::list< FileWithDetails > & mFiles
Definition: executor.h:71
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.
Definition: executor.cpp:61
ErrorLogger & mErrorLogger
Definition: executor.h:75
const Settings & mSettings
Definition: executor.h:73
This is just a container for general settings so that we don't need to pass individual values to func...
Definition: settings.h:95
bool quiet
Is –quiet given?
Definition: settings.h:282
bool clangTidy
Use clang-tidy.
Definition: settings.h:156
unsigned int jobs
How many processes/threads should do checking at the same time.
Definition: settings.h:231
SHOWTIME_MODES showtime
show timing information (–showtime=file|summary|top5)
Definition: settings.h:363
class for handling suppressions
Definition: suppressions.h:42
void reportStatus(std::size_t fileindex, std::size_t filecount, std::size_t sizedone, std::size_t sizetotal)
ErrorLogger & mErrorLogger
void reportOut(const std::string &outmsg, Color c) override
Information about progress is directed here.
std::mutex mReportSync
void reportErr(const ErrorMessage &msg) override
Information about found errors and warnings is directed here.
SyncLogForwarder(ThreadExecutor &threadExecutor, ErrorLogger &errorLogger)
ThreadExecutor & mThreadExecutor
std::mutex mFileSync
std::size_t mProcessedSize
std::size_t mTotalFileSize
unsigned int check(ErrorLogger &errorLogger, const std::string *file, const FileSettings *fs) const
ThreadData(ThreadExecutor &threadExecutor, ErrorLogger &errorLogger, const Settings &settings, const std::list< FileWithDetails > &files, const std::list< FileSettings > &fileSettings, CppCheck::ExecuteCmdFn executeCommand)
bool next(const std::string *&file, const FileSettings *&fs, std::size_t &fileSize)
std::size_t mProcessedFiles
SyncLogForwarder logForwarder
std::size_t mTotalFiles
const std::list< FileWithDetails > & mFiles
const std::list< FileSettings > & mFileSettings
CppCheck::ExecuteCmdFn mExecuteCommand
std::list< FileSettings >::const_iterator mItNextFileSettings
const Settings & mSettings
void status(std::size_t fileSize)
std::list< FileWithDetails >::const_iterator mItNextFile
This class will take a list of filenames and settings and check then all files using threads.
unsigned int check() override
CppCheck::ExecuteCmdFn mExecuteCommand
ThreadExecutor(const std::list< FileWithDetails > &files, const std::list< FileSettings > &fileSettings, const Settings &settings, SuppressionList &suppressions, ErrorLogger &errorLogger, CppCheck::ExecuteCmdFn executeCommand)
Color
Definition: color.h:27
File settings.
Definition: filesettings.h:57
static unsigned int STDCALL threadProc(ThreadData *data)