Do logging on a background thread

Makes logging actually thread-safe and slightly improves performance.
This commit is contained in:
Thomas Goyne 2013-01-25 15:50:08 -08:00
parent 2e99223977
commit 5092ab20c9
3 changed files with 35 additions and 10 deletions

View file

@ -22,6 +22,7 @@
#include "libaegisub/cajun/elements.h"
#include "libaegisub/cajun/writer.h"
#include "libaegisub/dispatch.h"
#include "libaegisub/io.h"
#include "libaegisub/util.h"
@ -31,6 +32,7 @@
#include <boost/range/algorithm.hpp>
#include <cstring>
#include <functional>
#include <mutex>
namespace agi {
namespace log {
@ -42,30 +44,45 @@ LogSink *log;
/// Keep this ordered the same as Severity
const char *Severity_ID = "EAWID";
LogSink::LogSink()
: messages(250)
, queue(dispatch::Create())
{ }
LogSink::~LogSink() {
// The destructor for emitters may try to log messages, so disable all the
// emitters before destructing any
std::vector<Emitter*> emitters_temp;
swap(emitters_temp, emitters);
queue->Sync([&]{ swap(emitters_temp, emitters); });
util::delete_clear(emitters_temp);
}
void LogSink::Log(SinkMessage const& sm) {
messages.push_back(sm);
boost::for_each(emitters, [=](Emitter *em) { em->log(&messages.back()); });
queue->Async([=]{
messages.push_back(sm);
boost::for_each(emitters, [=](Emitter *em) { em->log(&messages.back()); });
});
}
void LogSink::Subscribe(Emitter *em) {
LOG_D("agi/log/emitter/subscribe") << "Subscribe: " << this;
emitters.push_back(em);
queue->Sync([=] { emitters.push_back(em); });
}
void LogSink::Unsubscribe(Emitter *em) {
emitters.erase(remove(emitters.begin(), emitters.end(), em), emitters.end());
delete em;
queue->Sync([=] {
emitters.erase(remove(emitters.begin(), emitters.end(), em), emitters.end());
delete em;
});
LOG_D("agi/log/emitter/unsubscribe") << "Un-Subscribe: " << this;
}
decltype(LogSink::messages) LogSink::GetMessages() const {
decltype(LogSink::messages) ret;
queue->Sync([&] { ret = messages; });
return ret;
}
Message::Message(const char *section, Severity severity, const char *file, const char *func, int line)
: msg(nullptr, 1024)
{

View file

@ -47,6 +47,8 @@
#define LOG_D_IF(cond, section) if (cond) LOG_SINK(section, agi::log::Debug)
namespace agi {
namespace dispatch { class Queue; }
namespace log {
class LogSink;
@ -82,12 +84,13 @@ class Emitter;
/// Log sink, single destination for all messages
class LogSink {
boost::circular_buffer<SinkMessage> messages;
std::unique_ptr<dispatch::Queue> queue;
/// List of pointers to emitters
std::vector<Emitter*> emitters;
public:
LogSink() : messages(250) { }
LogSink();
~LogSink();
/// Insert a message into the sink.
@ -105,7 +108,7 @@ public:
/// @brief @get the complete (current) log.
/// @return Const pointer to internal sink.
decltype(messages) const& GetSink() const { return messages; }
decltype(messages) GetMessages() const;
};
/// An emitter to produce human readable output for a log sink.

View file

@ -39,6 +39,7 @@
#include "compat.h"
#include "include/aegisub/context.h"
#include <libaegisub/dispatch.h>
#include <libaegisub/log.h>
#include <algorithm>
@ -57,7 +58,7 @@ public:
EmitLog(wxTextCtrl *t)
: text_ctrl(t)
{
for (auto sm : agi::log::log->GetSink())
for (auto sm : agi::log::log->GetMessages())
log(&sm);
}
@ -86,7 +87,11 @@ public:
sm->line,
to_wx(sm->message));
#endif
text_ctrl->AppendText(log);
if (wxIsMainThread())
text_ctrl->AppendText(log);
else
agi::dispatch::Main().Async([=]{ text_ctrl->AppendText(log); });
}
};