Do logging on a background thread
Makes logging actually thread-safe and slightly improves performance.
This commit is contained in:
parent
2e99223977
commit
5092ab20c9
3 changed files with 35 additions and 10 deletions
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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); });
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue