summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorPatrick Ohly <patrick.ohly@intel.com>2013-04-09 21:32:35 +0200
committerPatrick Ohly <patrick.ohly@intel.com>2013-05-06 16:28:13 +0200
commit649837c2c2d3858116a0e422dd890d082f7f99ac (patch)
tree88061f3c8f84a21a26535c4e7d6c532b52f71ced /test
parent2f6f880910f36703b96995270dac5a6d2f8e6e56 (diff)
Logging: thread-safe
Logging must be thread-safe, because the glib log callback may be called from arbitrary threads. This becomes more important with EDS 3.8, because it shifts the execution of synchronous calls into threads. Thread-safe logging will also be required for running the Synthesis engine multithreaded, to overlap SyncML client communication with preparing the sources. To achieve this, the core Logging module protects its global data with a recursive mutex. A recursive mutes is used because logging calls themselves may be recursive, so ensuring single-lock semantic would be hard. Ref-counted boost pointers are used to track usage of Logger instances. This allows removal of an instance from the logging stack while it may still be in use. Destruction then will be delayed until the last user of the instance drops it. The instance itself must be prepared to handle this. The Logging mutex is available to users of the Logging module. Code which holds the logging mutex should not lock any other mutex, to avoid deadlocks. The new code is a bit fuzzy on that, because it calls other modules (glib, Synthesis engine) while holding the mutex. If that becomes a problem, then the mutex can be unlocked, at the risk of leading to reordered log messages in different channels (see ServerLogger). Making all loggers follow the new rules uses different approaches. Loggers like the one in the local transport child which use a parent logger and an additional ref-counted class like the D-Bus helper keep a weak reference to the helper and lock it before use. If it is gone already, the second logging part is skipped. This is the recommended approach. In cases where introducing ref-counting for the second class would have been too intrusive (Server and SessionHelper), a fake boost::shared_ptr without a destructor is used as an intermediate step towards the recommended approach. To avoid race conditions while the instance these fake pointers refer to destructs, an explicit "remove()" method is necessary which must hold the Logging mutex. Using the potentially removed pointer must do the same. Such fake ref-counted Loggers cannot be used as parent logger of other loggers, because then remove() would not be able to drop the last reference to the fake boost::shared_ptr. Loggers with fake boost::shared_ptr must keep a strong reference, because no-one else does. The goal is to turn this into weak references eventually. LogDir must protect concurrent access to m_report and the Synthesis engine. The LogRedirectLogger assumes that it is still the active logger while disabling itself. The remove() callback method will always be invoked before removing a logger from the stack.
Diffstat (limited to 'test')
-rw-r--r--test/client-test-main.cpp12
1 files changed, 3 insertions, 9 deletions
diff --git a/test/client-test-main.cpp b/test/client-test-main.cpp
index b68317c7..6685aa02 100644
--- a/test/client-test-main.cpp
+++ b/test/client-test-main.cpp
@@ -123,9 +123,7 @@ public:
}
~ClientListener() {
- if (&Logger::instance() == m_logger.get()) {
- Logger::popLogger();
- }
+ m_logger.reset();
}
void addAllowedFailures(string allowedFailures) {
@@ -138,9 +136,8 @@ public:
if (!getenv("SYNCEVOLUTION_DEBUG")) {
string logfile = m_currentTest + ".log";
simplifyFilename(logfile);
- m_logger.reset(new LogRedirect(true, logfile.c_str()));
+ m_logger.reset(new LogRedirect(LogRedirect::STDERR_AND_STDOUT, logfile.c_str()));
m_logger->setLevel(Logger::DEBUG);
- Logger::pushLogger(m_logger.get());
}
SE_LOG_DEBUG(NULL, "*** starting %s ***", m_currentTest.c_str());
m_failures.reset();
@@ -192,9 +189,6 @@ public:
if (!failure.empty()) {
SE_LOG_ERROR(NULL, "%s", failure.c_str());
}
- if (&Logger::instance() == m_logger.get()) {
- Logger::popLogger();
- }
m_logger.reset();
string logfile = m_currentTest + ".log";
@@ -245,7 +239,7 @@ private:
bool m_failed, m_testFailed;
string m_currentTest;
int m_alarmSeconds;
- auto_ptr<Logger> m_logger;
+ PushLogger<Logger> m_logger;
CppUnit::TestResultCollector m_failures;
static void alarmTriggered(int signal) {