diff options
author | Patrick Ohly <patrick.ohly@intel.com> | 2013-04-09 21:32:35 +0200 |
---|---|---|
committer | Patrick Ohly <patrick.ohly@intel.com> | 2013-05-06 16:28:13 +0200 |
commit | 649837c2c2d3858116a0e422dd890d082f7f99ac (patch) | |
tree | 88061f3c8f84a21a26535c4e7d6c532b52f71ced /test | |
parent | 2f6f880910f36703b96995270dac5a6d2f8e6e56 (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.cpp | 12 |
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) { |