forked from mia/Aegisub
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/elements.h"
|
||||||
#include "libaegisub/cajun/writer.h"
|
#include "libaegisub/cajun/writer.h"
|
||||||
|
#include "libaegisub/dispatch.h"
|
||||||
#include "libaegisub/io.h"
|
#include "libaegisub/io.h"
|
||||||
#include "libaegisub/util.h"
|
#include "libaegisub/util.h"
|
||||||
|
|
||||||
|
@ -31,6 +32,7 @@
|
||||||
#include <boost/range/algorithm.hpp>
|
#include <boost/range/algorithm.hpp>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
namespace agi {
|
namespace agi {
|
||||||
namespace log {
|
namespace log {
|
||||||
|
@ -42,30 +44,45 @@ LogSink *log;
|
||||||
/// Keep this ordered the same as Severity
|
/// Keep this ordered the same as Severity
|
||||||
const char *Severity_ID = "EAWID";
|
const char *Severity_ID = "EAWID";
|
||||||
|
|
||||||
|
LogSink::LogSink()
|
||||||
|
: messages(250)
|
||||||
|
, queue(dispatch::Create())
|
||||||
|
{ }
|
||||||
|
|
||||||
LogSink::~LogSink() {
|
LogSink::~LogSink() {
|
||||||
// The destructor for emitters may try to log messages, so disable all the
|
// The destructor for emitters may try to log messages, so disable all the
|
||||||
// emitters before destructing any
|
// emitters before destructing any
|
||||||
std::vector<Emitter*> emitters_temp;
|
std::vector<Emitter*> emitters_temp;
|
||||||
swap(emitters_temp, emitters);
|
queue->Sync([&]{ swap(emitters_temp, emitters); });
|
||||||
util::delete_clear(emitters_temp);
|
util::delete_clear(emitters_temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogSink::Log(SinkMessage const& sm) {
|
void LogSink::Log(SinkMessage const& sm) {
|
||||||
messages.push_back(sm);
|
queue->Async([=]{
|
||||||
boost::for_each(emitters, [=](Emitter *em) { em->log(&messages.back()); });
|
messages.push_back(sm);
|
||||||
|
boost::for_each(emitters, [=](Emitter *em) { em->log(&messages.back()); });
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogSink::Subscribe(Emitter *em) {
|
void LogSink::Subscribe(Emitter *em) {
|
||||||
LOG_D("agi/log/emitter/subscribe") << "Subscribe: " << this;
|
LOG_D("agi/log/emitter/subscribe") << "Subscribe: " << this;
|
||||||
emitters.push_back(em);
|
queue->Sync([=] { emitters.push_back(em); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogSink::Unsubscribe(Emitter *em) {
|
void LogSink::Unsubscribe(Emitter *em) {
|
||||||
emitters.erase(remove(emitters.begin(), emitters.end(), em), emitters.end());
|
queue->Sync([=] {
|
||||||
delete em;
|
emitters.erase(remove(emitters.begin(), emitters.end(), em), emitters.end());
|
||||||
|
delete em;
|
||||||
|
});
|
||||||
LOG_D("agi/log/emitter/unsubscribe") << "Un-Subscribe: " << this;
|
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)
|
Message::Message(const char *section, Severity severity, const char *file, const char *func, int line)
|
||||||
: msg(nullptr, 1024)
|
: msg(nullptr, 1024)
|
||||||
{
|
{
|
||||||
|
|
|
@ -47,6 +47,8 @@
|
||||||
#define LOG_D_IF(cond, section) if (cond) LOG_SINK(section, agi::log::Debug)
|
#define LOG_D_IF(cond, section) if (cond) LOG_SINK(section, agi::log::Debug)
|
||||||
|
|
||||||
namespace agi {
|
namespace agi {
|
||||||
|
namespace dispatch { class Queue; }
|
||||||
|
|
||||||
namespace log {
|
namespace log {
|
||||||
class LogSink;
|
class LogSink;
|
||||||
|
|
||||||
|
@ -82,12 +84,13 @@ class Emitter;
|
||||||
/// Log sink, single destination for all messages
|
/// Log sink, single destination for all messages
|
||||||
class LogSink {
|
class LogSink {
|
||||||
boost::circular_buffer<SinkMessage> messages;
|
boost::circular_buffer<SinkMessage> messages;
|
||||||
|
std::unique_ptr<dispatch::Queue> queue;
|
||||||
|
|
||||||
/// List of pointers to emitters
|
/// List of pointers to emitters
|
||||||
std::vector<Emitter*> emitters;
|
std::vector<Emitter*> emitters;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
LogSink() : messages(250) { }
|
LogSink();
|
||||||
~LogSink();
|
~LogSink();
|
||||||
|
|
||||||
/// Insert a message into the sink.
|
/// Insert a message into the sink.
|
||||||
|
@ -105,7 +108,7 @@ public:
|
||||||
|
|
||||||
/// @brief @get the complete (current) log.
|
/// @brief @get the complete (current) log.
|
||||||
/// @return Const pointer to internal sink.
|
/// @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.
|
/// An emitter to produce human readable output for a log sink.
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include "compat.h"
|
#include "compat.h"
|
||||||
#include "include/aegisub/context.h"
|
#include "include/aegisub/context.h"
|
||||||
|
|
||||||
|
#include <libaegisub/dispatch.h>
|
||||||
#include <libaegisub/log.h>
|
#include <libaegisub/log.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
@ -57,7 +58,7 @@ public:
|
||||||
EmitLog(wxTextCtrl *t)
|
EmitLog(wxTextCtrl *t)
|
||||||
: text_ctrl(t)
|
: text_ctrl(t)
|
||||||
{
|
{
|
||||||
for (auto sm : agi::log::log->GetSink())
|
for (auto sm : agi::log::log->GetMessages())
|
||||||
log(&sm);
|
log(&sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +87,11 @@ public:
|
||||||
sm->line,
|
sm->line,
|
||||||
to_wx(sm->message));
|
to_wx(sm->message));
|
||||||
#endif
|
#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