You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
431 lines
8.1 KiB
431 lines
8.1 KiB
// Module: Log4CPLUS
|
|
// File: threads.cxx
|
|
// Created: 6/2001
|
|
// Author: Tad E. Smith
|
|
//
|
|
//
|
|
// Copyright 2001-2013 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.
|
|
|
|
#include <log4cplus/config.hxx>
|
|
|
|
#include <exception>
|
|
#include <ostream>
|
|
#include <cerrno>
|
|
|
|
#ifdef LOG4CPLUS_HAVE_SYS_TYPES_H
|
|
#include <sys/types.h>
|
|
#endif
|
|
|
|
#ifdef LOG4CPLUS_HAVE_SYS_SYSCALL_H
|
|
#include <sys/syscall.h>
|
|
#endif
|
|
|
|
#ifdef LOG4CPLUS_HAVE_ERRNO_H
|
|
#include <errno.h>
|
|
#endif
|
|
|
|
#ifdef LOG4CPLUS_HAVE_UNISTD_H
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
#if defined(LOG4CPLUS_USE_PTHREADS)
|
|
# include <pthread.h>
|
|
# include <sched.h>
|
|
# include <signal.h>
|
|
#elif defined (LOG4CPLUS_USE_WIN32_THREADS)
|
|
# include <process.h>
|
|
#endif
|
|
#include <log4cplus/config/windowsh-inc.h>
|
|
#include <log4cplus/thread/syncprims-pub-impl.h>
|
|
#include <log4cplus/tstring.h>
|
|
#include <log4cplus/internal/cygwin-win32.h>
|
|
#include <log4cplus/streams.h>
|
|
|
|
#ifndef LOG4CPLUS_SINGLE_THREADED
|
|
|
|
#include <log4cplus/thread/threads.h>
|
|
#include <log4cplus/thread/impl/threads-impl.h>
|
|
#include <log4cplus/thread/impl/tls.h>
|
|
#include <log4cplus/ndc.h>
|
|
#include <log4cplus/helpers/loglog.h>
|
|
#include <log4cplus/helpers/stringhelper.h>
|
|
#include <log4cplus/helpers/timehelper.h>
|
|
#include <log4cplus/internal/internal.h>
|
|
|
|
#endif // LOG4CPLUS_SINGLE_THREADED
|
|
|
|
|
|
namespace log4cplus { namespace thread {
|
|
|
|
LOG4CPLUS_EXPORT
|
|
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
|
|
}
|
|
|
|
|
|
LOG4CPLUS_EXPORT
|
|
void
|
|
yield()
|
|
{
|
|
#if defined(LOG4CPLUS_USE_PTHREADS)
|
|
sched_yield();
|
|
#elif defined(_WIN32)
|
|
if (! SwitchToThread ())
|
|
Sleep (0);
|
|
#endif
|
|
}
|
|
|
|
|
|
LOG4CPLUS_EXPORT
|
|
log4cplus::tstring const &
|
|
getCurrentThreadName()
|
|
{
|
|
#if ! defined (LOG4CPLUS_SINGLE_THREADED)
|
|
log4cplus::tstring & name = log4cplus::internal::get_thread_name_str ();
|
|
if (name.empty ())
|
|
{
|
|
log4cplus::tostringstream tmp;
|
|
tmp << impl::getCurrentThreadId ();
|
|
tmp.str ().swap (name);
|
|
}
|
|
#else
|
|
static log4cplus::tstring const name (LOG4CPLUS_TEXT ("single"));
|
|
#endif
|
|
|
|
return name;
|
|
}
|
|
|
|
|
|
namespace
|
|
{
|
|
|
|
|
|
static
|
|
bool
|
|
get_current_thread_name_alt (log4cplus::tostream * s)
|
|
{
|
|
log4cplus::tostream & os = *s;
|
|
|
|
#if defined (LOG4CPLUS_USE_PTHREADS) && defined (__linux__) \
|
|
&& defined (LOG4CPLUS_HAVE_GETTID)
|
|
pid_t tid = syscall (SYS_gettid);
|
|
os << tid;
|
|
|
|
#elif defined (__CYGWIN__)
|
|
unsigned long tid = cygwin::get_current_win32_thread_id ();
|
|
os << tid;
|
|
|
|
#else
|
|
os << getCurrentThreadName ();
|
|
|
|
#endif
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
LOG4CPLUS_EXPORT
|
|
log4cplus::tstring const &
|
|
getCurrentThreadName2()
|
|
{
|
|
#if ! defined (LOG4CPLUS_SINGLE_THREADED)
|
|
log4cplus::tstring & name = log4cplus::internal::get_thread_name2_str ();
|
|
if (name.empty ())
|
|
{
|
|
log4cplus::tostringstream tmp;
|
|
get_current_thread_name_alt (&tmp);
|
|
tmp.str ().swap (name);
|
|
}
|
|
|
|
#else
|
|
static log4cplus::tstring const name (getCurrentThreadName ());
|
|
|
|
#endif
|
|
|
|
return name;
|
|
}
|
|
|
|
|
|
} } // namespace log4cplus { namespace thread {
|
|
|
|
|
|
#ifndef LOG4CPLUS_SINGLE_THREADED
|
|
|
|
namespace
|
|
{
|
|
|
|
# ifdef LOG4CPLUS_USE_PTHREADS
|
|
extern "C" void* threadStartFunc(void * param)
|
|
# elif defined(LOG4CPLUS_USE_WIN32_THREADS)
|
|
static unsigned WINAPI threadStartFunc(void * param)
|
|
# endif
|
|
{
|
|
return log4cplus::thread::impl::ThreadStart::threadStartFuncWorker (param);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
|
|
namespace log4cplus { namespace thread { namespace impl {
|
|
|
|
|
|
#if defined(LOG4CPLUS_USE_PTHREADS)
|
|
void*
|
|
ThreadStart::threadStartFuncWorker(void * arg)
|
|
#elif defined(LOG4CPLUS_USE_WIN32_THREADS)
|
|
unsigned
|
|
ThreadStart::threadStartFuncWorker(void * arg)
|
|
#endif
|
|
{
|
|
blockAllSignals ();
|
|
helpers::LogLog * loglog = helpers::LogLog::getLogLog();
|
|
if (! arg)
|
|
loglog->error(LOG4CPLUS_TEXT("threadStartFunc()- arg is NULL"));
|
|
else
|
|
{
|
|
Thread * ptr = static_cast<Thread *>(arg);
|
|
ThreadPtr thread(ptr);
|
|
|
|
// Decrease reference count increased by Thread::start().
|
|
ptr->removeReference ();
|
|
|
|
try
|
|
{
|
|
thread->run();
|
|
}
|
|
catch(std::exception const & 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::MutexGuard guard (thread->access_mutex);
|
|
thread->flags &= ~Thread::fRUNNING;
|
|
}
|
|
|
|
threadCleanup ();
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
Thread::Thread()
|
|
: flags (0)
|
|
#if defined(LOG4CPLUS_USE_WIN32_THREADS)
|
|
, handle (INVALID_HANDLE_VALUE)
|
|
, thread_id (0)
|
|
#else
|
|
, handle ()
|
|
#endif
|
|
{
|
|
}
|
|
|
|
|
|
Thread::~Thread()
|
|
{
|
|
#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
|
|
}
|
|
|
|
|
|
void
|
|
Thread::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;
|
|
log4cplus::helpers::LogLog::getLogLog ()->error (
|
|
LOG4CPLUS_TEXT ("Thread creation was not successful"), true);
|
|
}
|
|
#elif defined(LOG4CPLUS_USE_WIN32_THREADS)
|
|
HANDLE h = InterlockedExchangePointer (&handle, INVALID_HANDLE_VALUE);
|
|
if (h != INVALID_HANDLE_VALUE)
|
|
::CloseHandle (h);
|
|
|
|
h = reinterpret_cast<HANDLE>(
|
|
::_beginthreadex (0, 0, threadStartFunc, this, 0, &thread_id));
|
|
if (! h)
|
|
{
|
|
removeReference ();
|
|
flags &= ~fRUNNING;
|
|
log4cplus::helpers::LogLog::getLogLog ()->error (
|
|
LOG4CPLUS_TEXT ("Thread creation was not successful"), true);
|
|
}
|
|
h = InterlockedExchangePointer (&handle, h);
|
|
assert (h == INVALID_HANDLE_VALUE);
|
|
#endif
|
|
}
|
|
|
|
|
|
bool
|
|
Thread::isRunning() const
|
|
{
|
|
thread::MutexGuard guard (access_mutex);
|
|
return (flags & fRUNNING) != 0;
|
|
}
|
|
|
|
|
|
os_id_type
|
|
Thread::getThreadId () const
|
|
{
|
|
#if defined(LOG4CPLUS_USE_PTHREADS)
|
|
return handle;
|
|
#elif defined(LOG4CPLUS_USE_WIN32_THREADS)
|
|
return thread_id;
|
|
#endif
|
|
}
|
|
|
|
|
|
os_handle_type
|
|
Thread::getThreadHandle () const
|
|
{
|
|
return handle;
|
|
}
|
|
|
|
|
|
void
|
|
Thread::join ()
|
|
{
|
|
#if defined(LOG4CPLUS_USE_PTHREADS)
|
|
pthread_join (handle, 0);
|
|
#elif defined(LOG4CPLUS_USE_WIN32_THREADS)
|
|
::WaitForSingleObject (handle, INFINITE);
|
|
#endif
|
|
flags |= fJOINED;
|
|
}
|
|
|
|
|
|
} // namespace impl {
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
ThreadImplBase::~ThreadImplBase ()
|
|
{ }
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
|
|
namespace
|
|
{
|
|
|
|
|
|
class ThreadImpl
|
|
: public impl::Thread
|
|
{
|
|
public:
|
|
ThreadImpl ()
|
|
: abs_thread (0)
|
|
{ }
|
|
|
|
virtual ~ThreadImpl ()
|
|
{ }
|
|
|
|
virtual
|
|
void
|
|
run ()
|
|
{
|
|
abs_thread->run ();
|
|
}
|
|
|
|
void
|
|
set_abs_thread (AbstractThread * at)
|
|
{
|
|
abs_thread = at;
|
|
}
|
|
|
|
protected:
|
|
AbstractThread * abs_thread;
|
|
};
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
//
|
|
//
|
|
//
|
|
|
|
AbstractThread::AbstractThread ()
|
|
: thread (new ThreadImpl)
|
|
{
|
|
static_cast<ThreadImpl *>(thread.get ())->set_abs_thread (this);
|
|
}
|
|
|
|
|
|
bool
|
|
AbstractThread::isRunning() const
|
|
{
|
|
return static_cast<ThreadImpl *>(thread.get ())->isRunning ();
|
|
}
|
|
|
|
|
|
void
|
|
AbstractThread::start()
|
|
{
|
|
static_cast<ThreadImpl *>(thread.get ())->start ();
|
|
}
|
|
|
|
|
|
void
|
|
AbstractThread::join () const
|
|
{
|
|
static_cast<ThreadImpl *>(thread.get ())->join ();
|
|
}
|
|
|
|
|
|
AbstractThread::~AbstractThread()
|
|
{ }
|
|
|
|
|
|
} } // namespace log4cplus { namespace thread {
|
|
|
|
|
|
#endif // LOG4CPLUS_SINGLE_THREADED
|