Fixed #648 (Threads in Windows)
This commit is contained in:
parent
624f2c7aca
commit
6442938fe9
|
@ -26,13 +26,19 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef THREADING_MODEL_WIN
|
||||||
|
#include <process.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
#include <errno.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
ThreadExecutor::ThreadExecutor(const std::map<std::string, std::size_t> &files, Settings &settings, ErrorLogger &errorLogger)
|
ThreadExecutor::ThreadExecutor(const std::map<std::string, std::size_t> &files, Settings &settings, ErrorLogger &errorLogger)
|
||||||
: _files(files), _settings(settings), _errorLogger(errorLogger), _fileCount(0)
|
: _files(files), _settings(settings), _errorLogger(errorLogger), _fileCount(0)
|
||||||
|
@ -52,7 +58,7 @@ ThreadExecutor::~ThreadExecutor()
|
||||||
////// This code is for platforms that support fork() only ////////////////////
|
////// This code is for platforms that support fork() only ////////////////////
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#ifdef THREADING_MODEL_FORK
|
#if defined(THREADING_MODEL_FORK)
|
||||||
|
|
||||||
void ThreadExecutor::addFileContent(const std::string &path, const std::string &content)
|
void ThreadExecutor::addFileContent(const std::string &path, const std::string &content)
|
||||||
{
|
{
|
||||||
|
@ -298,6 +304,166 @@ void ThreadExecutor::reportInfo(const ErrorLogger::ErrorMessage &msg)
|
||||||
writeToPipe(REPORT_INFO, msg.serialize());
|
writeToPipe(REPORT_INFO, msg.serialize());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#elif defined(THREADING_MODEL_WIN)
|
||||||
|
|
||||||
|
void ThreadExecutor::addFileContent(const std::string &path, const std::string &content)
|
||||||
|
{
|
||||||
|
_fileContents[path] = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int ThreadExecutor::check()
|
||||||
|
{
|
||||||
|
HANDLE *threadHandles = new HANDLE[_settings._jobs];
|
||||||
|
|
||||||
|
_itNextFile = _files.begin();
|
||||||
|
|
||||||
|
InitializeCriticalSection(&_fileSync);
|
||||||
|
InitializeCriticalSection(&_errorSync);
|
||||||
|
InitializeCriticalSection(&_reportSync);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < _settings._jobs; ++i) {
|
||||||
|
threadHandles[i] = (HANDLE)_beginthreadex(NULL, 0, threadProc, this, 0, NULL);
|
||||||
|
if (!threadHandles[i]) {
|
||||||
|
std::cerr << "#### .\nThreadExecutor::check error, errno :" << errno << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD waitResult = WaitForMultipleObjects(_settings._jobs, threadHandles, TRUE, INFINITE);
|
||||||
|
if (waitResult != WAIT_OBJECT_0) {
|
||||||
|
if (waitResult == WAIT_FAILED) {
|
||||||
|
std::cerr << "#### .\nThreadExecutor::check wait failed, result: " << waitResult << " error: " << GetLastError() << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
} else {
|
||||||
|
std::cerr << "#### .\nThreadExecutor::check wait failed, result: " << waitResult << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int result = 0;
|
||||||
|
for (unsigned int i = 0; i < _settings._jobs; ++i) {
|
||||||
|
DWORD exitCode;
|
||||||
|
|
||||||
|
if (!GetExitCodeThread(threadHandles[i], &exitCode)) {
|
||||||
|
std::cerr << "#### .\nThreadExecutor::check get exit code failed, error:" << GetLastError() << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
result += exitCode;
|
||||||
|
|
||||||
|
if (!CloseHandle(threadHandles[i])) {
|
||||||
|
std::cerr << "#### .\nThreadExecutor::check close handle failed, error:" << GetLastError() << std::endl;
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DeleteCriticalSection(&_fileSync);
|
||||||
|
DeleteCriticalSection(&_errorSync);
|
||||||
|
DeleteCriticalSection(&_reportSync);
|
||||||
|
|
||||||
|
delete[] threadHandles;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int __stdcall ThreadExecutor::threadProc(void *args)
|
||||||
|
{
|
||||||
|
unsigned int result = 0;
|
||||||
|
|
||||||
|
ThreadExecutor *threadExecutor = static_cast<ThreadExecutor*>(args);
|
||||||
|
std::map<std::string, std::size_t>::const_iterator &it = threadExecutor->_itNextFile;
|
||||||
|
|
||||||
|
// guard static members of CppCheck against concurrent access
|
||||||
|
EnterCriticalSection(&threadExecutor->_fileSync);
|
||||||
|
|
||||||
|
CppCheck fileChecker(*threadExecutor, false);
|
||||||
|
fileChecker.settings() = threadExecutor->_settings;
|
||||||
|
|
||||||
|
LeaveCriticalSection(&threadExecutor->_fileSync);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
|
||||||
|
EnterCriticalSection(&threadExecutor->_fileSync);
|
||||||
|
|
||||||
|
if (it == threadExecutor->_files.end()) {
|
||||||
|
LeaveCriticalSection(&threadExecutor->_fileSync);
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
const std::string &file = (it++)->first;
|
||||||
|
|
||||||
|
LeaveCriticalSection(&threadExecutor->_fileSync);
|
||||||
|
|
||||||
|
if (!threadExecutor->_fileContents.empty() && threadExecutor->_fileContents.find(file) != threadExecutor->_fileContents.end()) {
|
||||||
|
// File content was given as a string
|
||||||
|
result += fileChecker.check(file, threadExecutor->_fileContents[file]);
|
||||||
|
} else {
|
||||||
|
// Read file from a file
|
||||||
|
result += fileChecker.check(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreadExecutor::reportOut(const std::string &outmsg)
|
||||||
|
{
|
||||||
|
EnterCriticalSection(&_reportSync);
|
||||||
|
|
||||||
|
_errorLogger.reportOut(outmsg);
|
||||||
|
|
||||||
|
LeaveCriticalSection(&_reportSync);
|
||||||
|
}
|
||||||
|
void ThreadExecutor::reportErr(const ErrorLogger::ErrorMessage &msg)
|
||||||
|
{
|
||||||
|
report(msg, REPORT_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreadExecutor::reportInfo(const ErrorLogger::ErrorMessage &msg)
|
||||||
|
{
|
||||||
|
report(msg, REPORT_INFO);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreadExecutor::report(const ErrorLogger::ErrorMessage &msg, MessageType msgType)
|
||||||
|
{
|
||||||
|
std::string file;
|
||||||
|
unsigned int line(0);
|
||||||
|
if (!msg._callStack.empty()) {
|
||||||
|
file = msg._callStack.back().getfile(false);
|
||||||
|
line = msg._callStack.back().line;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_settings.nomsg.isSuppressed(msg._id, file, line))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Alert only about unique errors
|
||||||
|
bool reportError = false;
|
||||||
|
std::string errmsg = msg.toString(_settings._verbose);
|
||||||
|
|
||||||
|
EnterCriticalSection(&_errorSync);
|
||||||
|
if (std::find(_errorList.begin(), _errorList.end(), errmsg) == _errorList.end()) {
|
||||||
|
_errorList.push_back(errmsg);
|
||||||
|
reportError = true;
|
||||||
|
}
|
||||||
|
LeaveCriticalSection(&_errorSync);
|
||||||
|
|
||||||
|
if (reportError) {
|
||||||
|
EnterCriticalSection(&_reportSync);
|
||||||
|
|
||||||
|
switch (msgType) {
|
||||||
|
case REPORT_ERROR:
|
||||||
|
_errorLogger.reportErr(msg);
|
||||||
|
break;
|
||||||
|
case REPORT_INFO:
|
||||||
|
_errorLogger.reportInfo(msg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
LeaveCriticalSection(&_reportSync);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
void ThreadExecutor::addFileContent(const std::string &/*path*/, const std::string &/*content*/)
|
void ThreadExecutor::addFileContent(const std::string &/*path*/, const std::string &/*content*/)
|
||||||
|
|
|
@ -26,6 +26,9 @@
|
||||||
|
|
||||||
#if (defined(__GNUC__) || defined(__sun)) && !defined(__MINGW32__)
|
#if (defined(__GNUC__) || defined(__sun)) && !defined(__MINGW32__)
|
||||||
#define THREADING_MODEL_FORK
|
#define THREADING_MODEL_FORK
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
#define THREADING_MODEL_WIN
|
||||||
|
#include <Windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class Settings;
|
class Settings;
|
||||||
|
@ -42,6 +45,7 @@ public:
|
||||||
ThreadExecutor(const std::map<std::string, std::size_t> &files, Settings &settings, ErrorLogger &_errorLogger);
|
ThreadExecutor(const std::map<std::string, std::size_t> &files, Settings &settings, ErrorLogger &_errorLogger);
|
||||||
virtual ~ThreadExecutor();
|
virtual ~ThreadExecutor();
|
||||||
unsigned int check();
|
unsigned int check();
|
||||||
|
|
||||||
virtual void reportOut(const std::string &outmsg);
|
virtual void reportOut(const std::string &outmsg);
|
||||||
virtual void reportErr(const ErrorLogger::ErrorMessage &msg);
|
virtual void reportErr(const ErrorLogger::ErrorMessage &msg);
|
||||||
virtual void reportInfo(const ErrorLogger::ErrorMessage &msg);
|
virtual void reportInfo(const ErrorLogger::ErrorMessage &msg);
|
||||||
|
@ -61,7 +65,7 @@ private:
|
||||||
ErrorLogger &_errorLogger;
|
ErrorLogger &_errorLogger;
|
||||||
unsigned int _fileCount;
|
unsigned int _fileCount;
|
||||||
|
|
||||||
#ifdef THREADING_MODEL_FORK
|
#if defined(THREADING_MODEL_FORK)
|
||||||
|
|
||||||
/** @brief Key is file name, and value is the content of the file */
|
/** @brief Key is file name, and value is the content of the file */
|
||||||
std::map<std::string, std::string> _fileContents;
|
std::map<std::string, std::string> _fileContents;
|
||||||
|
@ -83,6 +87,32 @@ private:
|
||||||
std::list<std::string> _errorList;
|
std::list<std::string> _errorList;
|
||||||
int _wpipe;
|
int _wpipe;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @return true if support for threads exist.
|
||||||
|
*/
|
||||||
|
static bool isEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(THREADING_MODEL_WIN)
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum MessageType {REPORT_ERROR, REPORT_INFO};
|
||||||
|
|
||||||
|
std::map<std::string, std::string> _fileContents;
|
||||||
|
std::map<std::string, std::size_t>::const_iterator _itNextFile;
|
||||||
|
CRITICAL_SECTION _fileSync;
|
||||||
|
|
||||||
|
std::list<std::string> _errorList;
|
||||||
|
CRITICAL_SECTION _errorSync;
|
||||||
|
|
||||||
|
CRITICAL_SECTION _reportSync;
|
||||||
|
|
||||||
|
void report(const ErrorLogger::ErrorMessage &msg, MessageType msgType);
|
||||||
|
|
||||||
|
static unsigned __stdcall threadProc(void*);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @return true if support for threads exist.
|
* @return true if support for threads exist.
|
||||||
|
|
Loading…
Reference in New Issue