Multicore cpu support for Linux (currently disabled and compiling produces warnings)

"no errors" output removed.
This commit is contained in:
Reijo Tomperi 2009-02-19 22:21:18 +00:00
parent efeaac736d
commit 4fc774deda
12 changed files with 419 additions and 20 deletions

View File

@ -20,6 +20,7 @@ OBJECTS = src/checkbufferoverrun.o \
src/main.o \
src/preprocessor.o \
src/settings.o \
src/threadexecutor.o \
src/token.o \
src/tokenize.o
@ -62,6 +63,7 @@ TESTOBJ = test/testbufferoverrun.o \
src/filelister.o \
src/preprocessor.o \
src/settings.o \
src/threadexecutor.o \
src/token.o \
src/tokenize.o
@ -127,7 +129,7 @@ src/checkvalidate.o: src/checkvalidate.cpp src/checkvalidate.h src/errorlogger.h
src/cppcheck.o: src/cppcheck.cpp src/cppcheck.h src/settings.h src/errorlogger.h src/checkfunctionusage.h src/tokenize.h src/token.h src/preprocessor.h src/checkmemoryleak.h src/checkbufferoverrun.h src/checkdangerousfunctions.h src/checkclass.h src/checkheaders.h src/checkother.h src/checkstl.h src/filelister.h
g++ $(CXXFLAGS) -c -o src/cppcheck.o src/cppcheck.cpp
src/cppcheckexecutor.o: src/cppcheckexecutor.cpp src/cppcheckexecutor.h src/errorlogger.h src/settings.h src/cppcheck.h src/checkfunctionusage.h src/tokenize.h src/token.h
src/cppcheckexecutor.o: src/cppcheckexecutor.cpp src/cppcheckexecutor.h src/errorlogger.h src/settings.h src/cppcheck.h src/checkfunctionusage.h src/tokenize.h src/token.h src/threadexecutor.h
g++ $(CXXFLAGS) -c -o src/cppcheckexecutor.o src/cppcheckexecutor.cpp
src/errorlogger.o: src/errorlogger.cpp src/errorlogger.h src/settings.h src/tokenize.h src/token.h
@ -145,6 +147,9 @@ src/preprocessor.o: src/preprocessor.cpp src/preprocessor.h src/tokenize.h src/s
src/settings.o: src/settings.cpp src/settings.h
g++ $(CXXFLAGS) -c -o src/settings.o src/settings.cpp
src/threadexecutor.o: src/threadexecutor.cpp src/threadexecutor.h src/settings.h src/errorlogger.h src/cppcheck.h src/checkfunctionusage.h src/tokenize.h src/token.h
g++ $(CXXFLAGS) -c -o src/threadexecutor.o src/threadexecutor.cpp
src/token.o: src/token.cpp src/token.h
g++ $(CXXFLAGS) -c -o src/token.o src/token.cpp

View File

@ -59,6 +59,8 @@
<Unit filename="src/preprocessor.h" />
<Unit filename="src/settings.cpp" />
<Unit filename="src/settings.h" />
<Unit filename="src/threadexecutor.cpp" />
<Unit filename="src/threadexecutor.h" />
<Unit filename="src/token.cpp" />
<Unit filename="src/token.h" />
<Unit filename="src/tokenize.cpp" />

View File

@ -262,16 +262,7 @@ unsigned int CppCheck::check()
++checkCount;
}
if (_settings._errorsOnly == false && _errout.str().empty())
{
std::ostringstream oss;
oss << "No errors found ("
<< (c + 1) << "/" << _filenames.size()
<< " files checked " <<
static_cast<int>(static_cast<double>((c + 1)) / _filenames.size()*100)
<< "% done)";
_errorLogger->reportOut(oss.str());
}
_errorLogger->reportStatus(c + 1, _filenames.size());
}
// This generates false positives - especially for libraries
@ -458,3 +449,13 @@ void CppCheck::reportOut(const std::string & /*outmsg*/)
// This is currently never called. It is here just to comply with
// the interface.
}
const std::vector<std::string> &CppCheck::filenames() const
{
return _filenames;
}
void CppCheck::reportStatus(unsigned int /*index*/, unsigned int /*max*/)
{
}

View File

@ -100,6 +100,10 @@ public:
*/
std::string parseFromArgs(int argc, const char* const argv[]);
const std::vector<std::string> &filenames() const;
virtual void reportStatus(unsigned int index, unsigned int max);
private:
void checkFile(const std::string &code, const char FileName[]);

View File

@ -19,17 +19,18 @@
#include "cppcheckexecutor.h"
#include "cppcheck.h"
#include "threadexecutor.h"
#include <fstream>
#include <iostream>
CppCheckExecutor::CppCheckExecutor()
{
_useXML = false;
}
CppCheckExecutor::~CppCheckExecutor()
{
//dtor
}
unsigned int CppCheckExecutor::check(int argc, const char* const argv[])
@ -38,15 +39,29 @@ unsigned int CppCheckExecutor::check(int argc, const char* const argv[])
std::string result = cppCheck.parseFromArgs(argc, argv);
if (result.length() == 0)
{
if (cppCheck.settings()._xml)
_settings = cppCheck.settings();
if (_settings._xml)
{
_useXML = true;
reportErr("<?xml version=\"1.0\"?>");
reportErr("<results>");
}
unsigned int returnValue = cppCheck.check();
if (_useXML)
unsigned int returnValue = 0;
if (1)
{
// Single process
returnValue = cppCheck.check();
}
else
{
// Multiple processes
const std::vector<std::string> &filenames = cppCheck.filenames();
Settings settings = cppCheck.settings();
ThreadExecutor executor(filenames, settings, *this);
returnValue = executor.check();
}
if (_settings._xml)
{
reportErr("</results>");
}
@ -70,9 +85,22 @@ void CppCheckExecutor::reportOut(const std::string &outmsg)
std::cout << outmsg << std::endl;
}
void CppCheckExecutor::reportStatus(unsigned int index, unsigned int max)
{
if (max > 1 && !_settings._errorsOnly)
{
std::ostringstream oss;
oss << index << "/" << max
<< " files checked " <<
static_cast<int>(static_cast<double>(index) / max*100)
<< "% done";
std::cout << oss.str() << std::endl;
}
}
void CppCheckExecutor::reportErr(const ErrorLogger::ErrorMessage &msg)
{
if (_useXML)
if (_settings._xml)
{
reportErr(msg.toXML());
}

View File

@ -21,6 +21,7 @@
#define CPPCHECKEXECUTOR_H
#include "errorlogger.h"
#include "settings.h"
/**
* This class works as an example of how CppCheck can be used in external
@ -67,6 +68,8 @@ public:
/** xml output of errors */
virtual void reportErr(const ErrorLogger::ErrorMessage &msg);
virtual void reportStatus(unsigned int index, unsigned int max);
private:
/**
@ -75,7 +78,7 @@ private:
*/
void reportErr(const std::string &errmsg);
bool _useXML;
Settings _settings;
};
#endif // CPPCHECKEXECUTOR_H

View File

@ -23,6 +23,11 @@
#include <sstream>
ErrorLogger::ErrorMessage::ErrorMessage()
{
}
#include <iostream>
ErrorLogger::ErrorMessage::ErrorMessage(const std::list<FileLocation> &callStack, const std::string &severity, const std::string &msg, const std::string &id)
{
_callStack = callStack;
@ -31,6 +36,78 @@ ErrorLogger::ErrorMessage::ErrorMessage(const std::list<FileLocation> &callStack
_id = id;
}
std::string ErrorLogger::ErrorMessage::serialize() const
{
std::ostringstream oss;
oss << _id.length() << " " << _id;
oss << _severity.length() << " " << _severity;
oss << _msg.length() << " " << _msg;
oss << _callStack.size() << " ";
for (std::list<ErrorLogger::ErrorMessage::FileLocation>::const_iterator tok = _callStack.begin(); tok != _callStack.end(); ++tok)
{
std::ostringstream smallStream;
smallStream << (*tok).line << ":" << (*tok).file;
oss << smallStream.str().length() << " " << smallStream.str();
}
return oss.str();
}
bool ErrorLogger::ErrorMessage::deserialize(const std::string &data)
{
_callStack.clear();
std::istringstream iss(data);
std::vector<std::string> results;
while (iss.good())
{
unsigned int len = 0;
if (!(iss >> len))
return false;
iss.get();
std::string temp;
for (unsigned int i = 0; i < len && iss.good(); ++i)
temp.append(1, iss.get());
results.push_back(temp);
if (results.size() == 3)
break;
}
_id = results[0];
_severity = results[1];
_msg = results[2];
unsigned int stackSize = 0;
if (!(iss >> stackSize))
return false;
while (iss.good())
{
unsigned int len = 0;
if (!(iss >> len))
return false;
iss.get();
std::string temp;
for (unsigned int i = 0; i < len && iss.good(); ++i)
temp.append(1, iss.get());
ErrorLogger::ErrorMessage::FileLocation loc;
loc.file = temp.substr(temp.find(':') + 1);
temp = temp.substr(0, temp.find(':'));
std::istringstream fiss(temp);
fiss >> loc.line;
_callStack.push_back(loc);
if (_callStack.size() >= stackSize)
break;
}
return true;
}
std::string ErrorLogger::ErrorMessage::toXML() const
{
std::ostringstream xml;

View File

@ -52,8 +52,11 @@ public:
};
ErrorMessage(const std::list<FileLocation> &callStack, const std::string &severity, const std::string &msg, const std::string &id);
ErrorMessage();
std::string toXML() const;
std::string toText() const;
std::string serialize() const;
bool deserialize( const std::string &data );
private:
std::list<FileLocation> _callStack;
std::string _severity;
@ -81,6 +84,14 @@ public:
*/
virtual void reportErr(const ErrorLogger::ErrorMessage &msg) = 0;
/**
* Information about how many files have been checked
*
* @param index This many files have been checked.
* @param max This many files there are in total.
*/
virtual void reportStatus(unsigned int index, unsigned int max) = 0;
void arrayIndexOutOfBounds(const Tokenizer *tokenizer, const std::list<const Token *> &Location)
{
_writemsg(tokenizer, Location, "all", "Array index out of bounds", "arrayIndexOutOfBounds");

191
src/threadexecutor.cpp Normal file
View File

@ -0,0 +1,191 @@
/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2009 Daniel Marjamäki, Reijo Tomperi, Nicolas Le Cam,
* Leandro Penz, Kimmo Varis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#include "threadexecutor.h"
#include "cppcheck.h"
#if 0
/**
This implementation is currently for Linux only and disabled with #if 0 until
proper way is invented.
*/
#include <sys/wait.h>
#include <iostream>
#include <unistd.h>
#include <fcntl.h>
ThreadExecutor::ThreadExecutor(const std::vector<std::string> &filenames, const Settings &settings, ErrorLogger &errorLogger)
: _filenames(filenames), _settings(settings), _errorLogger(errorLogger), _fileCount(0)
{
}
ThreadExecutor::~ThreadExecutor()
{
//dtor
}
bool ThreadExecutor::handleRead(unsigned int &result)
{
char type = 0;
if (read(_pipe[0], &type, 1) <= 0)
{
return false;
}
if (type != '1' && type != '2' && type != '3')
{
std::cerr << "#### ThreadExecutor::handleRead error, type was:" << type << std::endl;
exit(0);
}
unsigned int len = 0;
read(_pipe[0], &len, sizeof(len));
char *buf = new char[len];
read(_pipe[0], buf, len);
if (type == '1')
{
_errorLogger.reportOut(buf);
}
else if (type == '2')
{
ErrorLogger::ErrorMessage msg;
msg.deserialize(buf);
_errorLogger.reportErr(msg);
}
else if (type == '3')
{
_fileCount++;
std::istringstream iss(buf);
unsigned int fileResult = 0;
iss >> fileResult;
result += fileResult;
_errorLogger.reportStatus(_fileCount, _filenames.size());
}
delete [] buf;
return true;
}
unsigned int ThreadExecutor::check()
{
_fileCount = 0;
unsigned int result = 0;
if (pipe(_pipe) == -1)
{
perror("pipe");
exit(1);
}
int flags = 0;
if ((flags = fcntl(_pipe[0], F_GETFL, 0)) < 0)
{
perror("fcntl");
exit(1);
}
if (fcntl(_pipe[0], F_SETFL, flags | O_NONBLOCK) < 0)
{
perror("fcntl");
exit(1);
}
unsigned int childCount = 0;
for (unsigned int i = 0; i < _filenames.size(); i++)
{
// Keep only wanted amount of child processes running at a time.
if (childCount >= 2)
{
while (handleRead(result))
{
}
int stat = 0;
waitpid(0, &stat, 0);
--childCount;
}
pid_t pid = fork();
if (pid < 0)
{
// Error
std::cerr << "Failed to create child process" << std::endl;
exit(EXIT_FAILURE);
}
else if (pid == 0)
{
CppCheck fileChecker(*this);
fileChecker.settings(_settings);
fileChecker.addFile(_filenames[i]);
unsigned int result = fileChecker.check();
std::ostringstream oss;
oss << result;
writeToPipe('3', oss.str());
exit(0);
}
++childCount;
}
while (childCount > 0)
{
int stat = 0;
waitpid(0, &stat, 0);
--childCount;
}
while (handleRead(result))
{
}
return result;
}
void ThreadExecutor::writeToPipe(char type, const std::string &data)
{
unsigned int len = data.length() + 1;
char *out = new char[ len + 1 + sizeof(len)];
out[0] = type;
memcpy(&(out[1]), &len, sizeof(len));
memcpy(&(out[1+sizeof(len)]), data.c_str(), len);
write(_pipe[1], out, len + 1 + sizeof(len));
}
void ThreadExecutor::reportOut(const std::string &outmsg)
{
writeToPipe('1', outmsg);
}
void ThreadExecutor::reportErr(const ErrorLogger::ErrorMessage &msg)
{
writeToPipe('2', msg.serialize());
}
void ThreadExecutor::reportStatus(unsigned int /*index*/, unsigned int /*max*/)
{
// Not used
}
#else
#endif

66
src/threadexecutor.h Normal file
View File

@ -0,0 +1,66 @@
/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2009 Daniel Marjamäki, Reijo Tomperi, Nicolas Le Cam,
* Leandro Penz, Kimmo Varis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/
*/
#ifndef THREADEXECUTOR_H
#define THREADEXECUTOR_H
#include <vector>
#include <string>
#include "settings.h"
#include "errorlogger.h"
/**
* This class will take a list of filenames and settings and check then
* all files using threads.
*/
class ThreadExecutor : public ErrorLogger
{
#if 0
public:
ThreadExecutor(const std::vector<std::string> &filenames, const Settings &settings, ErrorLogger &_errorLogger);
virtual ~ThreadExecutor();
unsigned int check();
virtual void reportOut(const std::string &outmsg);
virtual void reportErr(const ErrorLogger::ErrorMessage &msg);
virtual void reportStatus(unsigned int index, unsigned int max);
protected:
private:
bool handleRead(unsigned int &result);
void writeToPipe(char type, const std::string &data);
const std::vector<std::string> &_filenames;
const Settings &_settings;
ErrorLogger &_errorLogger;
int _pipe[2];
unsigned int _fileCount;
#else
public:
ThreadExecutor(const std::vector<std::string> &filenames, const Settings &settings, ErrorLogger &_errorLogger) {};
virtual ~ThreadExecutor() {};
unsigned int check()
{
return 0;
}
virtual void reportOut(const std::string &outmsg) {}
virtual void reportErr(const ErrorLogger::ErrorMessage &msg) {}
virtual void reportStatus(unsigned int index, unsigned int max) {}
#endif
};
#endif // THREADEXECUTOR_H

View File

@ -44,7 +44,7 @@ protected:
public:
virtual void reportOut(const std::string &outmsg);
virtual void reportErr(const ErrorLogger::ErrorMessage &msg);
virtual void reportStatus(unsigned int /*index*/, unsigned int /*max*/) {}
void run(const std::string &str);
TestFixture(const std::string &_name);

View File

@ -177,8 +177,11 @@ int main()
fout << " };\n";
fout << "\n";
fout << " ErrorMessage(const std::list<FileLocation> &callStack, const std::string &severity, const std::string &msg, const std::string &id);\n";
fout << " ErrorMessage();\n";
fout << " std::string toXML() const;\n";
fout << " std::string toText() const;\n";
fout << " std::string serialize() const;\n";
fout << " bool deserialize( const std::string &data );\n";
fout << " private:\n";
fout << " std::list<FileLocation> _callStack;\n";
fout << " std::string _severity;\n";
@ -206,6 +209,14 @@ int main()
fout << " */\n";
fout << " virtual void reportErr(const ErrorLogger::ErrorMessage &msg) = 0;\n";
fout << "\n";
fout << " /**\n";
fout << " * Information about how many files have been checked\n";
fout << " *\n";
fout << " * @param index This many files have been checked.\n";
fout << " * @param max This many files there are in total.\n";
fout << " */\n";
fout << " virtual void reportStatus(unsigned int index, unsigned int max) = 0;\n";
fout << "\n";
for (std::list<Message>::const_iterator it = err.begin(); it != err.end(); ++it)
it->generateCode(fout);