Fixed #648 (Threads in Windows)

This commit is contained in:
Gerhard Zlabinger 2012-12-12 19:09:37 +01:00 committed by Daniel Marjamäki
parent 624f2c7aca
commit 6442938fe9
2 changed files with 199 additions and 3 deletions

View File

@ -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*/)

View File

@ -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.