Author: tschoening Date: Mon Feb 10 13:17:41 2014 New Revision: 1566613 URL: http://svn.apache.org/r1566613 Log: LOGCXX-305: Property/DOMConfigurator::configureAndWatch can continue to run after APR termination
Added: incubator/log4cxx/trunk/src/test/cpp/helpers/filewatchdogtest.cpp Modified: incubator/log4cxx/trunk/src/changes/changes.xml incubator/log4cxx/trunk/src/main/cpp/aprinitializer.cpp incubator/log4cxx/trunk/src/main/cpp/domconfigurator.cpp incubator/log4cxx/trunk/src/main/cpp/filewatchdog.cpp incubator/log4cxx/trunk/src/main/cpp/mutex.cpp incubator/log4cxx/trunk/src/main/cpp/propertyconfigurator.cpp incubator/log4cxx/trunk/src/main/cpp/threadspecificdata.cpp incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/aprinitializer.h Modified: incubator/log4cxx/trunk/src/changes/changes.xml URL: http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/changes/changes.xml?rev=1566613&r1=1566612&r2=1566613&view=diff ============================================================================== --- incubator/log4cxx/trunk/src/changes/changes.xml (original) +++ incubator/log4cxx/trunk/src/changes/changes.xml Mon Feb 10 13:17:41 2014 @@ -53,6 +53,7 @@ <action issue="LOGCXX-300" type="fix">ODBCAppender connection settings broken (or just have changed).</action> <action issue="LOGCXX-303" type="fix">DOMConfigurator does not set ErrorHandler.</action> <action issue="LOGCXX-304" type="fix">BasicConfigurator::configure results in writer not set warning.</action> + <action issue="LOGCXX-305" type="fix">Property/DOMConfigurator::configureAndWatch can continue to run after APR termination</action> <action issue="LOGCXX-317" type="fix">Log4cxx triggers locking inversion which can result in a deadlock.</action> <action issue="LOGCXX-331" type="fix">DailyRollingFileAppender should roll if program doesn't run at rolling time</action> <action issue="LOGCXX-336" type="fix">Test compilation fails: Overloading ambiguity</action> Modified: incubator/log4cxx/trunk/src/main/cpp/aprinitializer.cpp URL: http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/cpp/aprinitializer.cpp?rev=1566613&r1=1566612&r2=1566613&view=diff ============================================================================== --- incubator/log4cxx/trunk/src/main/cpp/aprinitializer.cpp (original) +++ incubator/log4cxx/trunk/src/main/cpp/aprinitializer.cpp Mon Feb 10 13:17:41 2014 @@ -21,9 +21,12 @@ #include <log4cxx/helpers/aprinitializer.h> #include <apr_pools.h> #include <apr_atomic.h> -#include <apr_time.h> #include <assert.h> #include <log4cxx/helpers/threadspecificdata.h> +#include <apr_thread_mutex.h> +#include <apr_thread_proc.h> +#include <log4cxx/helpers/synchronized.h> +#include <log4cxx/helpers/filewatchdog.h> using namespace log4cxx::helpers; using namespace log4cxx; @@ -37,7 +40,7 @@ namespace { } } -APRInitializer::APRInitializer() { +APRInitializer::APRInitializer() : p(0), mutex(0), startTime(0), tlsKey(0) { apr_initialize(); apr_pool_create(&p, NULL); apr_atomic_init(p); @@ -45,10 +48,22 @@ APRInitializer::APRInitializer() { #if APR_HAS_THREADS apr_status_t stat = apr_threadkey_private_create(&tlsKey, tlsDestruct, p); assert(stat == APR_SUCCESS); + stat = apr_thread_mutex_create(&mutex, APR_THREAD_MUTEX_NESTED, p); + assert(stat == APR_SUCCESS); #endif } APRInitializer::~APRInitializer() { + { +#if APR_HAS_THREADS + synchronized sync(mutex); +#endif + for(std::vector<FileWatchdog*>::iterator iter = watchdogs.begin(); + iter != watchdogs.end(); + iter++) { + delete *iter; + } + } apr_terminate(); isDestructed = true; } @@ -71,3 +86,11 @@ apr_threadkey_t* APRInitializer::getTlsK return getInstance().tlsKey; } +void APRInitializer::registerCleanup(FileWatchdog* watchdog) { + APRInitializer& instance(getInstance()); +#if APR_HAS_THREADS + synchronized sync(instance.mutex); +#endif + instance.watchdogs.push_back(watchdog); +} + Modified: incubator/log4cxx/trunk/src/main/cpp/domconfigurator.cpp URL: http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/cpp/domconfigurator.cpp?rev=1566613&r1=1566612&r2=1566613&view=diff ============================================================================== --- incubator/log4cxx/trunk/src/main/cpp/domconfigurator.cpp (original) +++ incubator/log4cxx/trunk/src/main/cpp/domconfigurator.cpp Mon Feb 10 13:17:41 2014 @@ -45,6 +45,9 @@ #include <log4cxx/helpers/charsetdecoder.h> #include <log4cxx/net/smtpappender.h> +#define LOG4CXX 1 +#include <log4cxx/helpers/aprinitializer.h> + using namespace log4cxx; using namespace log4cxx::xml; using namespace log4cxx::helpers; @@ -812,6 +815,7 @@ void DOMConfigurator::configureAndWatch( File file(filename); #if APR_HAS_THREADS XMLWatchdog * xdog = new XMLWatchdog(file); + APRInitializer::registerCleanup(xdog); xdog->setDelay(delay); xdog->start(); #else @@ -825,6 +829,7 @@ void DOMConfigurator::configureAndWatch( File file(filename); #if APR_HAS_THREADS XMLWatchdog * xdog = new XMLWatchdog(file); + APRInitializer::registerCleanup(xdog); xdog->setDelay(delay); xdog->start(); #else Modified: incubator/log4cxx/trunk/src/main/cpp/filewatchdog.cpp URL: http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/cpp/filewatchdog.cpp?rev=1566613&r1=1566612&r2=1566613&view=diff ============================================================================== --- incubator/log4cxx/trunk/src/main/cpp/filewatchdog.cpp (original) +++ incubator/log4cxx/trunk/src/main/cpp/filewatchdog.cpp Mon Feb 10 13:17:41 2014 @@ -22,7 +22,7 @@ #include <apr_thread_proc.h> #include <apr_atomic.h> #include <log4cxx/helpers/transcoder.h> - +#include <log4cxx/helpers/exception.h> using namespace log4cxx; using namespace log4cxx::helpers; @@ -39,7 +39,11 @@ warnedAlready(false), interrupted(0), th FileWatchdog::~FileWatchdog() { apr_atomic_set32(&interrupted, 0xFFFF); - thread.join(); + try { + thread.interrupt(); + thread.join(); + } catch(Exception &e) { + } } void FileWatchdog::checkAndConfigure() @@ -73,10 +77,10 @@ void* APR_THREAD_FUNC FileWatchdog::run( unsigned int interrupted = apr_atomic_read32(&pThis->interrupted); while(!interrupted) { - apr_sleep(APR_INT64_C(1000) * pThis->delay); - interrupted = apr_atomic_read32(&pThis->interrupted); - if (!interrupted) { + try { + Thread::sleep(pThis->delay); pThis->checkAndConfigure(); + } catch(InterruptedException& ex) { interrupted = apr_atomic_read32(&pThis->interrupted); } } Modified: incubator/log4cxx/trunk/src/main/cpp/mutex.cpp URL: http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/cpp/mutex.cpp?rev=1566613&r1=1566612&r2=1566613&view=diff ============================================================================== --- incubator/log4cxx/trunk/src/main/cpp/mutex.cpp (original) +++ incubator/log4cxx/trunk/src/main/cpp/mutex.cpp Mon Feb 10 13:17:41 2014 @@ -19,6 +19,7 @@ #include <log4cxx/helpers/mutex.h> #include <log4cxx/helpers/exception.h> #include <apr_thread_mutex.h> +#include <log4cxx/helpers/pool.h> #include <assert.h> #if !defined(LOG4CXX) #define LOG4CXX 1 Modified: incubator/log4cxx/trunk/src/main/cpp/propertyconfigurator.cpp URL: http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/cpp/propertyconfigurator.cpp?rev=1566613&r1=1566612&r2=1566613&view=diff ============================================================================== --- incubator/log4cxx/trunk/src/main/cpp/propertyconfigurator.cpp (original) +++ incubator/log4cxx/trunk/src/main/cpp/propertyconfigurator.cpp Mon Feb 10 13:17:41 2014 @@ -39,6 +39,9 @@ #include <log4cxx/helpers/transcoder.h> #include <log4cxx/helpers/fileinputstream.h> +#define LOG4CXX 1 +#include <log4cxx/helpers/aprinitializer.h> + using namespace log4cxx; using namespace log4cxx::spi; @@ -135,6 +138,7 @@ void PropertyConfigurator::configureAndW const File& configFilename, long delay) { PropertyWatchdog * pdog = new PropertyWatchdog(configFilename); + APRInitializer::registerCleanup(pdog); pdog->setDelay(delay); pdog->start(); } Modified: incubator/log4cxx/trunk/src/main/cpp/threadspecificdata.cpp URL: http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/cpp/threadspecificdata.cpp?rev=1566613&r1=1566612&r2=1566613&view=diff ============================================================================== --- incubator/log4cxx/trunk/src/main/cpp/threadspecificdata.cpp (original) +++ incubator/log4cxx/trunk/src/main/cpp/threadspecificdata.cpp Mon Feb 10 13:17:41 2014 @@ -18,6 +18,7 @@ #include <log4cxx/logstring.h> #include <log4cxx/helpers/threadspecificdata.h> #include <log4cxx/helpers/exception.h> +#include <apr_thread_proc.h> #if !defined(LOG4CXX) #define LOG4CXX 1 #endif Modified: incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/aprinitializer.h URL: http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/aprinitializer.h?rev=1566613&r1=1566612&r2=1566613&view=diff ============================================================================== --- incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/aprinitializer.h (original) +++ incubator/log4cxx/trunk/src/main/include/log4cxx/helpers/aprinitializer.h Mon Feb 10 13:17:41 2014 @@ -22,28 +22,44 @@ #error "aprinitializer.h should only be included by log4cxx implementation" #endif -#include <log4cxx/helpers/pool.h> -#include <apr_pools.h> -#include <apr_thread_proc.h> +#include <vector> + +extern "C" { +typedef struct apr_thread_mutex_t apr_thread_mutex_t; +typedef struct apr_threadkey_t apr_threadkey_t; +} + +#include <apr_time.h> namespace log4cxx { namespace helpers { + class FileWatchdog; + class APRInitializer { public: - static log4cxx_time_t initialize(); + static apr_time_t initialize(); static apr_pool_t* getRootPool(); static apr_threadkey_t* getTlsKey(); static bool isDestructed; + + /** + * Register a FileWatchdog for deletion prior to + * APR termination. FileWatchdog must be + * allocated on heap and not deleted elsewhere. + */ + static void registerCleanup(FileWatchdog* watchdog); private: APRInitializer(); APRInitializer(const APRInitializer&); APRInitializer& operator=(const APRInitializer&); apr_pool_t* p; - log4cxx_time_t startTime; + apr_thread_mutex_t* mutex; + std::vector<FileWatchdog*> watchdogs; + apr_time_t startTime; apr_threadkey_t* tlsKey; static APRInitializer& getInstance(); Added: incubator/log4cxx/trunk/src/test/cpp/helpers/filewatchdogtest.cpp URL: http://svn.apache.org/viewvc/incubator/log4cxx/trunk/src/test/cpp/helpers/filewatchdogtest.cpp?rev=1566613&view=auto ============================================================================== --- incubator/log4cxx/trunk/src/test/cpp/helpers/filewatchdogtest.cpp (added) +++ incubator/log4cxx/trunk/src/test/cpp/helpers/filewatchdogtest.cpp Mon Feb 10 13:17:41 2014 @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <log4cxx/helpers/pool.h> +#include <log4cxx/helpers/filewatchdog.h> +#include "../logunit.h" +#include "apr_time.h" + +using namespace log4cxx; +using namespace log4cxx::helpers; + + +/** + * + * FileWatchdog tests. + */ +LOGUNIT_CLASS(FileWatchdogTest) { + LOGUNIT_TEST_SUITE(FileWatchdogTest); + LOGUNIT_TEST(testShutdownDelay); + LOGUNIT_TEST_SUITE_END(); + +private: + class MockWatchdog : public FileWatchdog { + public: + MockWatchdog(const File& file) : FileWatchdog(file) { + } + + void doOnChange() { + } + }; + +public: + + /** + * Tests that FileWatchdog will respond to a shutdown request more rapidly + * than waiting out its delay. + */ + void testShutdownDelay() { + apr_time_t start = apr_time_now(); + { + MockWatchdog dog(File(LOG4CXX_STR("input/patternlayout1.properties"))); + dog.start(); + // wait 50 ms for thread to get rolling + apr_sleep(50000); + } + apr_time_t delta = apr_time_now() - start; + LOGUNIT_ASSERT(delta < 30000000); + } + +}; + +LOGUNIT_TEST_SUITE_REGISTRATION(FileWatchdogTest); +