// Module: Log4CPLUS // File: threads.cxx // Created: 6/2001 // Author: Tad E. Smith // // // Copyright 2001-2010 Tad E. Smith // // Licensed 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. #ifndef LOG4CPLUS_SINGLE_THREADED #include #include #include #include #include #ifdef LOG4CPLUS_HAVE_ERRNO_H #include #endif #if defined(LOG4CPLUS_USE_PTHREADS) # include # include #elif defined (LOG4CPLUS_USE_WIN32_THREADS) && ! defined (_WIN32_WCE) # include #endif #include #include #include #include #include #include #include namespace log4cplus { namespace thread { struct ThreadStart { # ifdef LOG4CPLUS_USE_PTHREADS static void* threadStartFuncWorker(void *); # elif defined(LOG4CPLUS_USE_WIN32_THREADS) && defined (_WIN32_WCE) static DWORD threadStartFuncWorker(void *); # elif defined(LOG4CPLUS_USE_WIN32_THREADS) static unsigned threadStartFuncWorker(void *); # endif }; } } // namespace log4cplus { namespace thread { namespace { # ifdef LOG4CPLUS_USE_PTHREADS extern "C" void * threadStartFunc(void * param) # elif defined(LOG4CPLUS_USE_WIN32_THREADS) && defined (_WIN32_WCE) static DWORD WINAPI threadStartFunc(void * param) # elif defined(LOG4CPLUS_USE_WIN32_THREADS) static unsigned WINAPI threadStartFunc(void * param) # endif { return log4cplus::thread::ThreadStart::threadStartFuncWorker (param); } } // namespace namespace log4cplus { namespace thread { /////////////////////////////////////////////////////////////////////////////// // public methods /////////////////////////////////////////////////////////////////////////////// LOG4CPLUS_MUTEX_PTR_DECLARE createNewMutex() { #if defined(LOG4CPLUS_USE_PTHREADS) // The mutexes that we provide need to be recursive. This is // because of double locking, first lock gets acquired in // ConfigurationWatchDogThread::run() through the HierarchyLocker // instance there. The second lock on appender_list_mutex is // attempted in // helpers::AppenderAttachableImpl::removeAllAppenders(). This // results into deadlock on (at least) Linux. log4cplus::thread::PthreadMutexAttr mattr; mattr.set_type (log4cplus::thread::Mutex::RECURSIVE); std::auto_ptr m (new pthread_mutex_t); int ret = pthread_mutex_init (m.get (), &mattr.attr); if (ret != 0) throw std::runtime_error ("createNewMutex(): pthread_mutex_init () has failed."); #elif defined(LOG4CPLUS_USE_WIN32_THREADS) std::auto_ptr< ::CRITICAL_SECTION> m (new ::CRITICAL_SECTION); ::InitializeCriticalSection(m.get ()); #endif return m.release (); } void deleteMutex(LOG4CPLUS_MUTEX_PTR_DECLARE m) { #if defined(LOG4CPLUS_USE_PTHREADS) ::pthread_mutex_destroy(m); #elif defined(LOG4CPLUS_USE_WIN32_THREADS) ::DeleteCriticalSection(m); #endif delete m; } #if defined(LOG4CPLUS_USE_PTHREADS) pthread_key_t* createPthreadKey(void (*cleanupfunc)(void *)) { ::pthread_key_t* key = new ::pthread_key_t; ::pthread_key_create(key, cleanupfunc); return key; } #endif #ifndef LOG4CPLUS_SINGLE_THREADED void blockAllSignals() { #if defined (LOG4CPLUS_USE_PTHREADS) // Block all signals. sigset_t signal_set; sigfillset (&signal_set); pthread_sigmask (SIG_BLOCK, &signal_set, 0); #endif } #endif // LOG4CPLUS_SINGLE_THREADED void yield() { #if defined(LOG4CPLUS_USE_PTHREADS) sched_yield(); #elif defined(LOG4CPLUS_USE_WIN32_THREADS) ::Sleep(0); #endif } tstring getCurrentThreadName() { tostringstream tmp; tmp << LOG4CPLUS_GET_CURRENT_THREAD; return tmp.str (); } #if defined(LOG4CPLUS_USE_PTHREADS) void* ThreadStart::threadStartFuncWorker(void * arg) #elif defined(LOG4CPLUS_USE_WIN32_THREADS) && defined (_WIN32_WCE) DWORD ThreadStart::threadStartFuncWorker(void * arg) #elif defined(LOG4CPLUS_USE_WIN32_THREADS) unsigned ThreadStart::threadStartFuncWorker(void * arg) #endif { blockAllSignals (); helpers::SharedObjectPtr loglog = helpers::LogLog::getLogLog(); if (! arg) loglog->error(LOG4CPLUS_TEXT("threadStartFunc()- arg is NULL")); else { AbstractThread * ptr = static_cast(arg); AbstractThreadPtr thread(ptr); // Decrease reference count increased by AbstractThread::start(). ptr->removeReference (); try { thread->run(); } catch(std::exception& e) { tstring err = LOG4CPLUS_TEXT("threadStartFunc()- run() terminated with an exception: "); err += LOG4CPLUS_C_STR_TO_TSTRING(e.what()); loglog->warn(err); } catch(...) { loglog->warn(LOG4CPLUS_TEXT("threadStartFunc()- run() terminated with an exception.")); } thread->flags &= ~AbstractThread::fRUNNING; getNDC().remove(); } return 0; } /////////////////////////////////////////////////////////////////////////////// // AbstractThread ctor and dtor /////////////////////////////////////////////////////////////////////////////// AbstractThread::AbstractThread() : flags (0) #if defined(LOG4CPLUS_USE_WIN32_THREADS) , handle (INVALID_HANDLE_VALUE) #endif { } AbstractThread::~AbstractThread() { #if defined(LOG4CPLUS_USE_PTHREADS) if ((flags & fJOINED) == 0) pthread_detach (handle); #elif defined(LOG4CPLUS_USE_WIN32_THREADS) if (handle != INVALID_HANDLE_VALUE) ::CloseHandle (handle); #endif } /////////////////////////////////////////////////////////////////////////////// // AbstractThread public methods /////////////////////////////////////////////////////////////////////////////// void AbstractThread::start() { flags |= fRUNNING; // Increase reference count here. It will be lowered by the running // thread itself. addReference (); #if defined(LOG4CPLUS_USE_PTHREADS) if (pthread_create(&handle, NULL, threadStartFunc, this) ) { removeReference (); flags &= ~fRUNNING; throw std::runtime_error("Thread creation was not successful"); } #elif defined(LOG4CPLUS_USE_WIN32_THREADS) HANDLE h = InterlockedExchangePointer (&handle, INVALID_HANDLE_VALUE); if (h != INVALID_HANDLE_VALUE) ::CloseHandle (h); #if defined (_WIN32_WCE) h = ::CreateThread (0, 0, threadStartFunc, this, 0, &thread_id); #else h = reinterpret_cast( ::_beginthreadex (0, 0, threadStartFunc, this, 0, &thread_id)); #endif if (! h) { removeReference (); flags &= ~fRUNNING; throw std::runtime_error("Thread creation was not successful"); } h = InterlockedExchangePointer (&handle, h); assert (h == INVALID_HANDLE_VALUE); #endif } LOG4CPLUS_THREAD_KEY_TYPE AbstractThread::getThreadId () const { #if defined(LOG4CPLUS_USE_PTHREADS) return handle; #elif defined(LOG4CPLUS_USE_WIN32_THREADS) return thread_id; #endif } LOG4CPLUS_THREAD_HANDLE_TYPE AbstractThread::getThreadHandle () const { return handle; } void AbstractThread::join () { #if defined(LOG4CPLUS_USE_PTHREADS) pthread_join (handle, 0); #elif defined(LOG4CPLUS_USE_WIN32_THREADS) ::WaitForSingleObject (handle, INFINITE); #endif flags |= fJOINED; } } } // namespace log4cplus { namespace thread { #endif // LOG4CPLUS_SINGLE_THREADED