Use mutexes in LogManager to make it threadsafe, as suggested by beistin's patch. Change some LogManager function names to be consistent with Dolphin's naming conventions.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@7433 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
Jordan Woyak 2011-04-01 07:43:02 +00:00
parent 7a9a47376f
commit 021193b22f
10 changed files with 132 additions and 137 deletions

View File

@ -43,8 +43,6 @@ public:
void Log(LogTypes::LOG_LEVELS, const char *Text);
void ClearScreen(bool Cursor = true);
const char *getName() const { return "Console"; }
private:
#ifdef _WIN32
HWND GetHwnd(void);

View File

@ -86,17 +86,20 @@ LogManager::LogManager()
m_fileLog = new FileLogListener(File::GetUserPath(F_MAINLOG_IDX).c_str());
m_consoleLog = new ConsoleListener();
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) {
m_Log[i]->setEnable(true);
m_Log[i]->addListener(m_fileLog);
m_Log[i]->addListener(m_consoleLog);
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
{
m_Log[i]->SetEnable(true);
m_Log[i]->AddListener(m_fileLog);
m_Log[i]->AddListener(m_consoleLog);
}
}
LogManager::~LogManager() {
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i) {
m_logManager->removeListener((LogTypes::LOG_TYPE)i, m_fileLog);
m_logManager->removeListener((LogTypes::LOG_TYPE)i, m_consoleLog);
LogManager::~LogManager()
{
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
{
m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_fileLog);
m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_consoleLog);
}
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
@ -107,14 +110,13 @@ LogManager::~LogManager() {
}
void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type,
const char *file, int line, const char *format,
va_list args) {
const char *file, int line, const char *format, va_list args)
{
char temp[MAX_MSGLEN];
char msg[MAX_MSGLEN * 2];
LogContainer *log = m_Log[type];
if (! log->isEnable() || level > log->getLevel() || ! log->hasListeners())
if (!log->IsEnabled() || level > log->GetLevel() || ! log->HasListeners())
return;
CharArrayFromFormatV(temp, MAX_MSGLEN, format, args);
@ -123,16 +125,9 @@ void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type,
sprintf(msg, "%s %s:%u %c[%s]: %s\n",
Common::Timer::GetTimeFormatted().c_str(),
file, line, level_to_char[(int)level],
log->getShortName(), temp);
log->GetShortName(), temp);
std::lock_guard<std::mutex> lk(logMutex);
log->trigger(level, msg);
}
void LogManager::removeListener(LogTypes::LOG_TYPE type, LogListener *listener)
{
std::lock_guard<std::mutex> lk(logMutex);
m_Log[type]->removeListener(listener);
log->Trigger(level, msg);
}
void LogManager::Init()
@ -147,31 +142,33 @@ void LogManager::Shutdown()
}
LogContainer::LogContainer(const char* shortName, const char* fullName, bool enable)
: m_enable(enable) {
: m_enable(enable)
{
strncpy(m_fullName, fullName, 128);
strncpy(m_shortName, shortName, 32);
m_level = LogTypes::LWARNING;
}
// LogContainer
void LogContainer::addListener(LogListener *listener) {
if (!isListener(listener))
listeners.push_back(listener);
void LogContainer::AddListener(LogListener *listener)
{
std::lock_guard<std::mutex> lk(m_listeners_lock);
m_listeners.insert(listener);
}
void LogContainer::removeListener(LogListener *listener) {
std::vector<LogListener *>::iterator i = std::find(listeners.begin(), listeners.end(), listener);
if (listeners.end() != i)
listeners.erase(i);
void LogContainer::RemoveListener(LogListener *listener)
{
std::lock_guard<std::mutex> lk(m_listeners_lock);
m_listeners.erase(listener);
}
bool LogContainer::isListener(LogListener *listener) const {
return listeners.end() != std::find(listeners.begin(), listeners.end(), listener);
}
void LogContainer::Trigger(LogTypes::LOG_LEVELS level, const char *msg)
{
std::lock_guard<std::mutex> lk(m_listeners_lock);
void LogContainer::trigger(LogTypes::LOG_LEVELS level, const char *msg) {
std::vector<LogListener *>::const_iterator i;
for (i = listeners.begin(); i != listeners.end(); ++i) {
std::set<LogListener*>::const_iterator i;
for (i = m_listeners.begin(); i != m_listeners.end(); ++i)
{
(*i)->Log(level, msg);
}
}
@ -179,13 +176,14 @@ void LogContainer::trigger(LogTypes::LOG_LEVELS level, const char *msg) {
FileLogListener::FileLogListener(const char *filename)
{
m_logfile.open(filename, std::ios::app);
setEnable(true);
SetEnable(true);
}
void FileLogListener::Log(LogTypes::LOG_LEVELS, const char *msg)
{
if (!m_enable || !isValid())
if (!IsEnabled() || !IsValid())
return;
std::lock_guard<std::mutex> lk(m_log_lock);
m_logfile << msg << std::flush;
}

View File

@ -23,80 +23,70 @@
#include "Thread.h"
#include "FileUtil.h"
#include <vector>
#include <set>
#include <string.h>
#define MAX_MESSAGES 8000
#define MAX_MSGLEN 1024
// pure virtual interface (well, except the destructor which we just leave empty).
class LogListener {
// pure virtual interface
class LogListener
{
public:
virtual ~LogListener() {}
virtual void Log(LogTypes::LOG_LEVELS, const char *msg) = 0;
virtual const char *getName() const = 0;
};
class FileLogListener : public LogListener {
class FileLogListener : public LogListener
{
public:
FileLogListener(const char *filename);
void Log(LogTypes::LOG_LEVELS, const char *msg);
bool isValid() {
return (m_logfile != NULL);
}
bool IsValid() { return (m_logfile != NULL); }
bool IsEnabled() const { return m_enable; }
void SetEnable(bool enable) { m_enable = enable; }
bool isEnable() {
return m_enable;
}
void setEnable(bool enable) {
m_enable = enable;
}
const char *getName() const { return "file"; }
const char* GetName() const { return "file"; }
private:
std::mutex m_log_lock;
std::ofstream m_logfile;
bool m_enable;
};
class LogContainer {
class LogContainer
{
public:
LogContainer(const char* shortName, const char* fullName, bool enable = false);
const char *getShortName() const { return m_shortName; }
const char *getFullName() const { return m_fullName; }
const char* GetShortName() const { return m_shortName; }
const char* GetFullName() const { return m_fullName; }
bool isListener(LogListener *listener) const;
void addListener(LogListener *listener);
void removeListener(LogListener *listener);
void AddListener(LogListener* listener);
void RemoveListener(LogListener* listener);
void trigger(LogTypes::LOG_LEVELS, const char *msg);
void Trigger(LogTypes::LOG_LEVELS, const char *msg);
bool isEnable() const { return m_enable; }
void setEnable(bool enable) {
m_enable = enable;
}
bool IsEnabled() const { return m_enable; }
void SetEnable(bool enable) { m_enable = enable; }
LogTypes::LOG_LEVELS getLevel() const {
return m_level;
}
LogTypes::LOG_LEVELS GetLevel() const { return m_level; }
void setLevel(LogTypes::LOG_LEVELS level) {
m_level = level;
}
bool hasListeners() const { return listeners.size() > 0; }
void SetLevel(LogTypes::LOG_LEVELS level) { m_level = level; }
bool HasListeners() const { return !m_listeners.empty(); }
private:
char m_fullName[128];
char m_shortName[32];
bool m_enable;
LogTypes::LOG_LEVELS m_level;
std::vector<LogListener *> listeners;
std::mutex m_listeners_lock;
std::set<LogListener*> m_listeners;
};
class ConsoleListener;
@ -105,7 +95,6 @@ class LogManager : NonCopyable
{
private:
LogContainer* m_Log[LogTypes::NUMBER_OF_LOGS];
std::mutex logMutex;
FileLogListener *m_fileLog;
ConsoleListener *m_consoleLog;
static LogManager *m_logManager; // Singleton. Ugh.
@ -119,49 +108,58 @@ public:
void Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type,
const char *file, int line, const char *fmt, va_list args);
void setLogLevel(LogTypes::LOG_TYPE type, LogTypes::LOG_LEVELS level) {
m_Log[type]->setLevel(level);
void SetLogLevel(LogTypes::LOG_TYPE type, LogTypes::LOG_LEVELS level)
{
m_Log[type]->SetLevel(level);
}
void setEnable(LogTypes::LOG_TYPE type, bool enable) {
m_Log[type]->setEnable(enable);
void SetEnable(LogTypes::LOG_TYPE type, bool enable)
{
m_Log[type]->SetEnable(enable);
}
bool isEnable(LogTypes::LOG_TYPE type) {
return m_Log[type]->isEnable();
bool IsEnabled(LogTypes::LOG_TYPE type) const
{
return m_Log[type]->IsEnabled();
}
const char *getShortName(LogTypes::LOG_TYPE type) const {
return m_Log[type]->getShortName();
const char* GetShortName(LogTypes::LOG_TYPE type) const
{
return m_Log[type]->GetShortName();
}
const char *getFullName(LogTypes::LOG_TYPE type) const {
return m_Log[type]->getFullName();
const char* GetFullName(LogTypes::LOG_TYPE type) const
{
return m_Log[type]->GetFullName();
}
bool isListener(LogTypes::LOG_TYPE type, LogListener *listener) const {
return m_Log[type]->isListener(listener);
void AddListener(LogTypes::LOG_TYPE type, LogListener *listener)
{
m_Log[type]->AddListener(listener);
}
void addListener(LogTypes::LOG_TYPE type, LogListener *listener) {
m_Log[type]->addListener(listener);
void RemoveListener(LogTypes::LOG_TYPE type, LogListener *listener)
{
m_Log[type]->RemoveListener(listener);
}
void removeListener(LogTypes::LOG_TYPE type, LogListener *listener);
FileLogListener *getFileListener() {
FileLogListener *GetFileListener() const
{
return m_fileLog;
}
ConsoleListener *getConsoleListener() {
ConsoleListener *GetConsoleListener() const
{
return m_consoleLog;
}
static LogManager* GetInstance() {
static LogManager* GetInstance()
{
return m_logManager;
}
static void SetInstance(LogManager *logManager) {
static void SetInstance(LogManager *logManager)
{
m_logManager = logManager;
}

View File

@ -68,7 +68,6 @@ public:
void Wait()
{
std::unique_lock<std::mutex> lk(m_mutex);
if (!is_set)
m_condvar.wait(lk, IsSet(this));
is_set = false;
}

View File

@ -209,7 +209,7 @@ u32 CWII_IPC_HLE_Device_di::ExecuteCommand(u32 _BufferIn, u32 _BufferInSize, u32
u64 DVDAddress = (u64)Memory::Read_U32(_BufferIn + 0x08) << 2;
// Don't do anything if the log is unselected
if (LogManager::GetInstance()->isEnable(LogTypes::FILEMON))
if (LogManager::GetInstance()->IsEnabled(LogTypes::FILEMON))
{
const char *pFilename = m_pFileSystem->GetFileName(DVDAddress);
if (pFilename != NULL)

View File

@ -93,9 +93,11 @@ void ReadGC(std::string FileName)
void CheckFile(std::string File, u64 Size)
{
// Don't do anything if the log is unselected
if (!LogManager::GetInstance()->isEnable(LogTypes::FILEMON)) return;
if (!LogManager::GetInstance()->IsEnabled(LogTypes::FILEMON))
return;
// Do nothing if we found the same file again
if (CurrentFile == File) return;
if (CurrentFile == File)
return;
if (Size > 0) Size = (Size / 1000);
std::string Str = StringFromFormat("%s kB %s", ThousandSeparate(Size, 7).c_str(), File.c_str());
@ -119,7 +121,7 @@ void FindFilename(u64 offset)
// Don't do anything if a game is not running
if (Core::GetState() != Core::CORE_RUN) return;
// Or if the log is unselected
if (!LogManager::GetInstance()->isEnable(LogTypes::FILEMON)) return;
if (!LogManager::GetInstance()->IsEnabled(LogTypes::FILEMON)) return;
if (!FileAccess) return;
if (!pFileSystem || ISOFile != SConfig::GetInstance().m_LastFilename)

View File

@ -344,7 +344,7 @@ CFrame::CFrame(wxFrame* parent,
if (ShowLogWindow) SConfig::GetInstance().m_InterfaceLogWindow = true;
// Give it a console early to show potential messages from this onward
ConsoleListener *Console = LogManager::GetInstance()->getConsoleListener();
ConsoleListener *Console = LogManager::GetInstance()->GetConsoleListener();
if (SConfig::GetInstance().m_InterfaceConsole) Console->Open();
// Start debugging mazimized

View File

@ -142,7 +142,7 @@ void CFrame::ToggleConsole(bool bShow)
// If the console doesn't exist, we create it
if (!GetConsoleWindow())
{
ConsoleListener *Console = LogManager::GetInstance()->getConsoleListener();
ConsoleListener *Console = LogManager::GetInstance()->GetConsoleListener();
Console->Open();
}
else
@ -747,7 +747,7 @@ void CFrame::ResizeConsole()
/*max out the width in the word wrap mode*/ 100;
int WindowHeight = InternalHeight + MenuBar;
// Resize buffer
ConsoleListener* Console = LogManager::GetInstance()->getConsoleListener();
ConsoleListener* Console = LogManager::GetInstance()->GetConsoleListener();
Console->PixelSpace(0,0, InternalWidth, InternalHeight, false);
// Move the window to hide the border
MoveWindow(GetConsoleWindow(), -Border-wxBorder, -MenuBar-wxBorder,

View File

@ -69,7 +69,7 @@ void LogConfigWindow::CreateGUIControls()
m_checks = new wxCheckListBox(this, wxID_ANY);
_connect_macro_(m_checks, LogConfigWindow::OnLogCheck, wxEVT_COMMAND_CHECKLISTBOX_TOGGLED, this);
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++)
m_checks->Append(wxString::FromAscii(m_LogManager->getFullName((LogTypes::LOG_TYPE)i)));
m_checks->Append(wxString::FromAscii(m_LogManager->GetFullName((LogTypes::LOG_TYPE)i)));
// Sizers
wxStaticBoxSizer* sbOutputs = new wxStaticBoxSizer(wxVERTICAL, this, _("Logger Outputs"));
@ -110,7 +110,7 @@ void LogConfigWindow::LoadSettings()
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
{
bool log_enabled;
ini.Get("Logs", m_LogManager->getShortName((LogTypes::LOG_TYPE)i), &log_enabled, true);
ini.Get("Logs", m_LogManager->GetShortName((LogTypes::LOG_TYPE)i), &log_enabled, true);
if (log_enabled) enableAll = false;
m_checks->Check(i, log_enabled);
}
@ -126,7 +126,7 @@ void LogConfigWindow::SaveSettings()
ini.Set("Options", "WriteToConsole", m_writeConsole);
ini.Set("Options", "WriteToWindow", m_writeWindow);
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
ini.Set("Logs", m_LogManager->getShortName((LogTypes::LOG_TYPE)i), m_checks->IsChecked(i));
ini.Set("Logs", m_LogManager->GetShortName((LogTypes::LOG_TYPE)i), m_checks->IsChecked(i));
ini.Save(File::GetUserPath(F_LOGGERCONFIG_IDX));
}
@ -134,7 +134,7 @@ void LogConfigWindow::OnVerbosityChange(wxCommandEvent& event)
{
int v = m_verbosity->GetSelection() + 1;
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; i++)
m_LogManager->setLogLevel((LogTypes::LOG_TYPE)i, (LogTypes::LOG_LEVELS)v);
m_LogManager->SetLogLevel((LogTypes::LOG_TYPE)i, (LogTypes::LOG_LEVELS)v);
event.Skip();
}
@ -146,9 +146,9 @@ void LogConfigWindow::OnWriteFileChecked(wxCommandEvent& event)
if (m_checks->IsChecked(i))
{
if (m_writeFile)
m_LogManager->addListener((LogTypes::LOG_TYPE)i, m_LogManager->getFileListener());
m_LogManager->AddListener((LogTypes::LOG_TYPE)i, m_LogManager->GetFileListener());
else
m_LogManager->removeListener((LogTypes::LOG_TYPE)i, m_LogManager->getFileListener());
m_LogManager->RemoveListener((LogTypes::LOG_TYPE)i, m_LogManager->GetFileListener());
}
}
}
@ -161,9 +161,9 @@ void LogConfigWindow::OnWriteConsoleChecked(wxCommandEvent& event)
if (m_checks->IsChecked(i))
{
if (m_writeConsole)
m_LogManager->addListener((LogTypes::LOG_TYPE)i, m_LogManager->getConsoleListener());
m_LogManager->AddListener((LogTypes::LOG_TYPE)i, m_LogManager->GetConsoleListener());
else
m_LogManager->removeListener((LogTypes::LOG_TYPE)i, m_LogManager->getConsoleListener());
m_LogManager->RemoveListener((LogTypes::LOG_TYPE)i, m_LogManager->GetConsoleListener());
}
}
}
@ -176,9 +176,9 @@ void LogConfigWindow::OnWriteWindowChecked(wxCommandEvent& event)
if (m_checks->IsChecked(i))
{
if (m_writeWindow)
m_LogManager->addListener((LogTypes::LOG_TYPE)i, (LogListener *)m_LogWindow);
m_LogManager->AddListener((LogTypes::LOG_TYPE)i, (LogListener *)m_LogWindow);
else
m_LogManager->removeListener((LogTypes::LOG_TYPE)i, (LogListener *)m_LogWindow);
m_LogManager->RemoveListener((LogTypes::LOG_TYPE)i, (LogListener *)m_LogWindow);
}
}
}
@ -197,22 +197,22 @@ void LogConfigWindow::ToggleLog(int _logType, bool enable)
m_checks->Check(_logType, enable);
m_LogManager->setEnable(logType, enable);
m_LogManager->SetEnable(logType, enable);
if (enable)
{
if (m_writeWindow)
m_LogManager->addListener(logType, (LogListener *)m_LogWindow);
m_LogManager->AddListener(logType, (LogListener *)m_LogWindow);
if (m_writeFile)
m_LogManager->addListener(logType, m_LogManager->getFileListener());
m_LogManager->AddListener(logType, m_LogManager->GetFileListener());
if (m_writeConsole)
m_LogManager->addListener(logType, m_LogManager->getConsoleListener());
m_LogManager->AddListener(logType, m_LogManager->GetConsoleListener());
}
else
{
m_LogManager->removeListener(logType, (LogListener *)m_LogWindow);
m_LogManager->removeListener(logType, m_LogManager->getFileListener());
m_LogManager->removeListener(logType, m_LogManager->getConsoleListener());
m_LogManager->RemoveListener(logType, (LogListener *)m_LogWindow);
m_LogManager->RemoveListener(logType, m_LogManager->GetFileListener());
m_LogManager->RemoveListener(logType, m_LogManager->GetConsoleListener());
}
}

View File

@ -87,23 +87,23 @@ void CLogWindow::CreateGUIControls()
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
{
bool enable;
ini.Get("Logs", m_LogManager->getShortName((LogTypes::LOG_TYPE)i), &enable, true);
ini.Get("Logs", m_LogManager->GetShortName((LogTypes::LOG_TYPE)i), &enable, true);
if (m_writeWindow && enable)
m_LogManager->addListener((LogTypes::LOG_TYPE)i, this);
m_LogManager->AddListener((LogTypes::LOG_TYPE)i, this);
else
m_LogManager->removeListener((LogTypes::LOG_TYPE)i, this);
m_LogManager->RemoveListener((LogTypes::LOG_TYPE)i, this);
if (m_writeFile && enable)
m_LogManager->addListener((LogTypes::LOG_TYPE)i, m_LogManager->getFileListener());
m_LogManager->AddListener((LogTypes::LOG_TYPE)i, m_LogManager->GetFileListener());
else
m_LogManager->removeListener((LogTypes::LOG_TYPE)i, m_LogManager->getFileListener());
m_LogManager->RemoveListener((LogTypes::LOG_TYPE)i, m_LogManager->GetFileListener());
if (m_writeConsole && enable)
m_LogManager->addListener((LogTypes::LOG_TYPE)i, m_LogManager->getConsoleListener());
m_LogManager->AddListener((LogTypes::LOG_TYPE)i, m_LogManager->GetConsoleListener());
else
m_LogManager->removeListener((LogTypes::LOG_TYPE)i, m_LogManager->getConsoleListener());
m_LogManager->setLogLevel((LogTypes::LOG_TYPE)i, (LogTypes::LOG_LEVELS)(verbosity));
m_LogManager->RemoveListener((LogTypes::LOG_TYPE)i, m_LogManager->GetConsoleListener());
m_LogManager->SetLogLevel((LogTypes::LOG_TYPE)i, (LogTypes::LOG_LEVELS)(verbosity));
}
// Font
@ -159,7 +159,7 @@ CLogWindow::~CLogWindow()
{
for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
{
m_LogManager->removeListener((LogTypes::LOG_TYPE)i, this);
m_LogManager->RemoveListener((LogTypes::LOG_TYPE)i, this);
}
m_LogTimer->Stop();
delete m_LogTimer;
@ -205,7 +205,7 @@ void CLogWindow::OnClear(wxCommandEvent& WXUNUSED (event))
msgQueue.pop();
}
m_LogManager->getConsoleListener()->ClearScreen();
m_LogManager->GetConsoleListener()->ClearScreen();
}
void CLogWindow::UnPopulateBottom()