1
0
mirror of https://github.com/stefanocasazza/ULib.git synced 2025-09-28 19:05:55 +08:00

thread fix

This commit is contained in:
stefanocasazza 2015-08-27 16:26:09 +02:00
parent 7a1b166569
commit 61ad7266fc
20 changed files with 820 additions and 551 deletions

92
configure vendored
View File

@ -20582,6 +20582,98 @@ fi
fi
if test ! -z "$tlib" ; then
as_ac_Lib=`$as_echo "ac_cv_lib_$tlib''_pthread_suspend" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_suspend in -l$tlib" >&5
$as_echo_n "checking for pthread_suspend in -l$tlib... " >&6; }
if eval \${$as_ac_Lib+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
LIBS="-l$tlib $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char pthread_suspend ();
int
main ()
{
return pthread_suspend ();
;
return 0;
}
_ACEOF
if ac_fn_cxx_try_link "$LINENO"; then :
eval "$as_ac_Lib=yes"
else
eval "$as_ac_Lib=no"
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
$as_echo "#define HAVE_PTHREAD_SUSPEND 1" >>confdefs.h
fi
as_ac_Lib=`$as_echo "ac_cv_lib_$tlib''_pthread_cancel" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_cancel in -l$tlib" >&5
$as_echo_n "checking for pthread_cancel in -l$tlib... " >&6; }
if eval \${$as_ac_Lib+:} false; then :
$as_echo_n "(cached) " >&6
else
ac_check_lib_save_LIBS=$LIBS
LIBS="-l$tlib $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
#ifdef __cplusplus
extern "C"
#endif
char pthread_cancel ();
int
main ()
{
return pthread_cancel ();
;
return 0;
}
_ACEOF
if ac_fn_cxx_try_link "$LINENO"; then :
eval "$as_ac_Lib=yes"
else
eval "$as_ac_Lib=no"
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
eval ac_res=\$$as_ac_Lib
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
$as_echo "$ac_res" >&6; }
if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
$as_echo "#define HAVE_PTHREAD_CANCEL 1" >>confdefs.h
fi
as_ac_Lib=`$as_echo "ac_cv_lib_$tlib''_pthread_condattr_setclock" | $as_tr_sh`
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_condattr_setclock in -l$tlib" >&5
$as_echo_n "checking for pthread_condattr_setclock in -l$tlib... " >&6; }

View File

@ -676,6 +676,12 @@ if test "$threading" = "none" ; then
])
fi
if test ! -z "$tlib" ; then
AC_CHECK_LIB($tlib,pthread_suspend,[
AC_DEFINE(HAVE_PTHREAD_SUSPEND, [1], [pthread suspend])
])
AC_CHECK_LIB($tlib,pthread_cancel,[
AC_DEFINE(HAVE_PTHREAD_CANCEL, [1], [pthread cancel])
])
AC_CHECK_LIB($tlib,pthread_condattr_setclock,[
AC_DEFINE(HAVE_PTHREAD_CONDATTR_SETCLOCK, [1], [pthread clocking])
])

View File

@ -123,27 +123,29 @@
extern "C" {
#endif
typedef int (*iPF) (void);
typedef int (*iPFpv) (void*);
typedef int (*iPFpvpv) ( void*, void*);
typedef int (*qcompare)(const void*,const void*);
typedef bool (*bPFi) (int);
typedef bool (*bPF) (void);
typedef bool (*bPFpv) (void*);
typedef bool (*bPFpvpv) (void*,void*);
typedef bool (*bPFpc) (const char*);
typedef bool (*bPFpcu) (const char*, uint32_t);
typedef bool (*bPFpcpc) (const char*,const char*);
typedef bool (*bPFpcpv) (const char*,const void*);
typedef void (*vPF) (void);
typedef void (*vPFi) (int);
typedef void (*vPFpv) (void*);
typedef void (*vPFpc) (const char*);
typedef void (*vPFpvpc) (void*,char*);
typedef void (*vPFpvpv) (void*,void*);
typedef void (*vPFpvu) (void*,uint32_t);
typedef void* (*pvPF) (void);
typedef void* (*pvPFpvpb)(void*,bool*);
typedef int (*iPF) (void);
typedef int (*iPFpv) (void*);
typedef unsigned (*uPFpv) (void*);
typedef int (*iPFpvpv) ( void*, void*);
typedef int (*qcompare)(const void*,const void*);
typedef bool (*bPFi) (int);
typedef bool (*bPF) (void);
typedef bool (*bPFpv) (void*);
typedef bool (*bPFpvpv) (void*,void*);
typedef bool (*bPFpc) (const char*);
typedef bool (*bPFpcu) (const char*, uint32_t);
typedef bool (*bPFpcpc) (const char*,const char*);
typedef bool (*bPFpcpv) (const char*,const void*);
typedef void (*vPF) (void);
typedef void (*vPFi) (int);
typedef void (*vPFpv) (void*);
typedef void (*vPFpc) (const char*);
typedef void (*vPFpvpc) (void*,char*);
typedef void (*vPFpvpv) (void*,void*);
typedef void (*vPFpvu) (void*,uint32_t);
typedef void* (*pvPF) (void);
typedef void* (*pvPFpv) (void*);
typedef void* (*pvPFpvpb)(void*,bool*);
typedef struct U_DATA {
unsigned char* dptr;

View File

@ -308,6 +308,9 @@
/* pthread inherit scheduling attribute */
#undef HAVE_PTHREAD_ATTR_SETINHRITSCHED
/* pthread cancel */
#undef HAVE_PTHREAD_CANCEL
/* pthread clocking */
#undef HAVE_PTHREAD_CONDATTR_SETCLOCK
@ -323,6 +326,9 @@
/* pthread scheduling */
#undef HAVE_PTHREAD_SETSCHEDPRIO
/* pthread suspend */
#undef HAVE_PTHREAD_SUSPEND
/* pthread yield */
#undef HAVE_PTHREAD_YIELD

View File

@ -56,7 +56,7 @@ public:
static const char* prefix;
static struct iovec iov_vec[5];
static log_date* ptr_shared_date;
#ifdef ENABLE_THREAD
#if defined(ENABLE_THREAD) && !defined(_MSWINDOWS_)
static pthread_rwlock_t* prwlock;
#endif

View File

@ -285,7 +285,7 @@ public:
# endif
# endif
// ------------------------------------------------------------------------------
# ifdef ENABLE_THREAD
# if defined(ENABLE_THREAD) && !defined(_MSWINDOWS_)
pthread_rwlock_t rwlock;
struct timeval now_shared; // => u_now
ULog::log_date log_date_shared;

View File

@ -124,6 +124,7 @@ protected:
#ifdef U_EPOLLET_POSTPONE_STRATEGY
static bool bepollet;
static unsigned bepollet_threshold;
#endif
#ifdef USE_LIBEVENT

View File

@ -14,14 +14,15 @@
#ifndef ULIB_THREAD_H
#define ULIB_THREAD_H
#include <ulib/internal/common.h>
#define U_SIGSTOP (SIGRTMIN+5)
#define U_SIGCONT (SIGRTMIN+6)
#include <ulib/timeval.h>
#ifdef _MSWINDOWS_
#undef signal
#undef sleep
# undef sleep
# undef signal
# define PTHREAD_CREATE_DETACHED 1
#else
# define U_SIGSTOP (SIGRTMIN+5)
# define U_SIGCONT (SIGRTMIN+6)
#endif
class UNotifier;
@ -35,49 +36,55 @@ public:
U_MEMORY_ALLOCATOR
U_MEMORY_DEALLOCATOR
enum Cancel {
cancelInitial, /* used internally, do not use */
cancelDeferred, /* exit thread on cancellation pointsuch as yield */
cancelImmediate, /* exit befor cancellation */
cancelDisabled /* ignore cancellation */
};
// COSTRUTTORI
UThread(bool suspendEnable = false, bool joinEnable = true);
virtual ~UThread();
UThread(int _detachstate);
virtual ~UThread()
{
U_TRACE_UNREGISTER_OBJECT(0, UThread)
if (tid) close();
}
// SERVICES
static pid_t getTID();
static void sleep(time_t timeoutMS);
#ifdef _MSWINDOWS_
static DWORD getTID();
#else
static pthread_t getTID();
#endif
// Inter Process Communication
static void lock(pthread_mutex_t* mutex)
static void lock(pthread_mutex_t* pmutex)
{
U_TRACE(1, "UThread::lock(%p)", mutex)
U_TRACE(1, "UThread::lock(%p)", pmutex)
(void) U_SYSCALL(pthread_mutex_lock, "%p", mutex);
# ifndef _MSWINDOWS_
(void) U_SYSCALL(pthread_mutex_lock, "%p", pmutex);
# endif
}
static void unlock(pthread_mutex_t* mutex)
static void unlock(pthread_mutex_t* pmutex)
{
U_TRACE(1, "UThread::unlock(%p)", mutex)
U_TRACE(1, "UThread::unlock(%p)", pmutex)
(void) U_SYSCALL(pthread_mutex_unlock, "%p", mutex);
# ifndef _MSWINDOWS_
(void) U_SYSCALL(pthread_mutex_unlock, "%p", pmutex);
# endif
}
static bool initRwLock(pthread_rwlock_t* rwlock)
#ifndef _MSWINDOWS_
static bool initRwLock(pthread_rwlock_t* prwlock)
{
U_TRACE(1, "UThread::initRwLock(%p)", rwlock)
U_TRACE(1, "UThread::initRwLock(%p)", prwlock)
pthread_rwlockattr_t rwlockattr;
if (U_SYSCALL(pthread_rwlockattr_init, "%p", &rwlockattr) != 0 ||
U_SYSCALL(pthread_rwlockattr_setpshared, "%p,%d", &rwlockattr, PTHREAD_PROCESS_SHARED) != 0 ||
U_SYSCALL(pthread_rwlock_init, "%p,%p", rwlock, &rwlockattr) != 0)
U_SYSCALL(pthread_rwlock_init, "%p,%p", prwlock, &rwlockattr) != 0)
{
U_RETURN(false);
}
@ -87,40 +94,61 @@ public:
static bool initIPC(pthread_mutex_t* mutex, pthread_cond_t* cond);
static void doIPC(pthread_mutex_t* mutex, pthread_cond_t* cond, vPF function, bool wait);
#endif
/**
* All threads execute by deriving the run method of UThread.
* This method is called after initial to begin normal operation of the
* When a new thread is created, it does not begin immediate execution. This is because the derived class virtual tables are not properly loaded
* at the time the C++ object is created within the constructor itself, at least in some compiler/system combinations. It can be started directly
* after the constructor completes by calling the start() method
*
* @return false if execution fails
*/
bool start(uint32_t timeoutMS = 0);
/**
* All threads execute by deriving the run method of UThread. This method is called after initial to begin normal operation of the
* thread. If the method terminates, then the thread will also terminate
*/
virtual void run()
{
U_TRACE(0, "UThread::run()")
}
}
/**
* When a new thread is created, it does not begin immediate execution.
* This is because the derived class virtual tables are not properly loaded
* at the time the C++ object is created within the constructor itself, at
* least in some compiler/system combinations. It can be started directly
* after the constructor completes by calling the start() method
* Check if this thread is detached
*
* @return false if execution fails
* @return true if the thread is detached
*/
void stop();
bool start(uint32_t timeoutMS = 0);
bool isDetached()
{
U_TRACE(0, "UThread::isDetached()")
/**
* Start a new thread as "detached". This is an alternative
* start() method that resolves some issues with later glibc
* implementations which incorrectly implement self-detach
*
* @return false if execution fails
*/
U_INTERNAL_DUMP("detachstate = %d", detachstate)
bool detach();
if (detachstate == PTHREAD_CREATE_DETACHED) U_RETURN(true);
U_RETURN(false);
}
void sleep(time_t timeoutMS);
static void nanosleep(time_t timeoutMS)
{
U_TRACE(0, "UThread::nanosleep(%ld)", timeoutMS)
UThread* th = getThread();
if (th)
{
th->sleep(timeoutMS);
return;
}
UTimeVal(timeoutMS / 1000L, (timeoutMS % 1000L) * 1000L).nanosleep();
}
/**
* Yields the current thread's CPU time slice to allow another thread to begin immediate execution
@ -129,34 +157,46 @@ public:
void yield();
/**
* Suspends execution of the selected thread. Pthreads do not normally
* support suspendable threads, so the behavior is simulated with signals
* Suspends execution of the selected thread. Pthreads do not normally support suspendable threads, so the behavior is simulated with signals.
* You can't kill or stop just one thread from another process. You can send a signal to a particular thread, but the stop/abort action that
* is taken by the signal affects the whole process. In the earlier implementation of Linux threads, it was possible to stop a single thread
* with SIGSTOP, but this behaviour has now been fixed to conform to the Posix standard (so it stops all threads in the process)
*/
void suspend();
void resume()
{
U_TRACE(0, "UThread::resume()")
/**
* Resumes execution of the selected thread
*/
# ifndef _MSWINDOWS_
resume(tid);
# ifndef HAVE_PTHREAD_SUSPEND
yield(); // give the signal a time to kick in
# endif
# endif
}
void suspend()
{
U_TRACE(0, "UThread::suspend()")
void resume();
/**
* Check if this thread is detached
*
* @return true if the thread is detached
*/
bool isDetached() const;
/**
* Each time a thread receives a signal, it stores the signal number locally
*/
void signal(int signo);
# ifndef _MSWINDOWS_
suspend(tid);
# ifndef HAVE_PTHREAD_SUSPEND
yield(); // give the signal a time to kick in
# endif
# endif
}
// Cancellation
enum Cancel {
cancelInitial, /* used internally, do not use */
cancelDeferred, /* exit thread on cancellation pointsuch as yield */
cancelImmediate, /* exit befor cancellation */
cancelDisabled, /* ignore cancellation */
cancelManual
};
void setCancel(int mode);
/**
@ -176,44 +216,163 @@ public:
void exitCancel(int cancel);
// A special global function, getThread(), is provided to identify the thread object that represents the current
// execution context you are running under. This is sometimes needed to deliver signals to the correct thread
static UThread* getThread() __pure
{
U_TRACE(1, "UThread::getThread()")
U_INTERNAL_DUMP("first = %p", first)
# ifdef _MSWINDOWS_
DWORD _tid = GetCurrentThreadId();
# else
pthread_t _tid = (pthread_t) U_SYSCALL_NO_PARAM(pthread_self);
# endif
for (UThread* obj = first; obj; obj = obj->next)
{
# ifdef _MSWINDOWS_
if (_tid == obj->tid) U_RETURN_POINTER(obj, UThread);
# else
if (pthread_equal(_tid, obj->tid)) U_RETURN_POINTER(obj, UThread);
# endif
}
U_RETURN_POINTER(0, UThread);
}
static bool isCurrentThread(pthread_t _tid)
{
U_TRACE(1, "UThread::isCurrentThread(%p)", _tid)
U_INTERNAL_ASSERT_POINTER(_tid)
# ifdef _MSWINDOWS_
if (GetCurrentThreadId() == _tid) U_RETURN(true);
# else
if (pthread_equal((pthread_t)U_SYSCALL_NO_PARAM(pthread_self), _tid)) U_RETURN(true);
# endif
U_RETURN(false);
}
#if defined(U_STDCPP_ENABLE) && defined(DEBUG)
const char* dump(bool reset) const;
#endif
protected:
UThread* next;
int detachstate, cancel;
#ifdef _MSWINDOWS_
DWORD tid;
HANDLE cancellation;
#else
pthread_t tid;
pthread_attr_t attr;
int suspendCount;
static pthread_mutex_t mlock;
#endif
static UThread* first;
static pthread_cond_t cond;
static pthread_mutex_t _lock;
void close(); // close current thread, free all
void close();
#ifdef _MSWINDOWS_
static void lock() {}
static void unlock() {}
static void resume(pthread_t _tid) {}
static void suspend(pthread_t _tid) {}
static unsigned __stdcall execHandler(void* th);
#else
void sigInstall(int signo);
void manageSignal(int signo);
static void lock() { lock(&_lock); }
static void unlock() { unlock(&_lock); }
static void lock() { lock(&mlock); }
static void unlock() { unlock(&mlock); }
static void sigHandler(int signo);
static void execHandler(UThread* th);
static void threadCleanup(UThread* th)
static void sigHandler(int signo)
{
U_TRACE(0, "UThread::sigHandler(%d)", signo)
UThread* th = getThread();
if (th) th->manageSignal(signo);
}
static bool isDetached(pthread_attr_t* pattr)
{
U_TRACE(1, "UThread::isDetached(%p)", pattr)
int state;
(void) U_SYSCALL(pthread_attr_getdetachstate, "%p,%p", pattr, &state);
if (state == PTHREAD_CREATE_DETACHED) U_RETURN(true);
U_RETURN(false);
}
static void stop(pthread_t _tid, pthread_attr_t* pattr)
{
U_TRACE(1, "UThread::stop(%p,%p)", _tid, pattr)
# ifdef HAVE_PTHREAD_CANCEL
(void) U_SYSCALL(pthread_cancel, "%p", _tid);
# endif
if (isDetached(pattr) == false) (void) U_SYSCALL(pthread_join, "%p,%p", _tid, 0);
# ifdef HAVE_PTHREAD_YIELD
else (void) U_SYSCALL_NO_PARAM(pthread_yield);
# endif
}
static void suspend(pthread_t _tid)
{
U_TRACE(1, "UThread::suspend(%p)", _tid)
U_ASSERT_EQUALS(isCurrentThread(_tid), false)
# ifdef HAVE_PTHREAD_SUSPEND
(void) U_SYSCALL(pthread_suspend, "%p", _tid);
# else
(void) U_SYSCALL(pthread_kill, "%p,%d", _tid, U_SIGSTOP);
# endif
}
static void resume(pthread_t _tid)
{
U_TRACE(1, "UThread::resume(%p)", _tid)
U_ASSERT_EQUALS(isCurrentThread(_tid), false)
# ifdef HAVE_PTHREAD_SUSPEND
(void) U_SYSCALL(pthread_resume, "%p", _tid);
# else
(void) U_SYSCALL(pthread_kill, "%p,%d", _tid, U_SIGCONT);
# endif
}
static void threadCleanup(void* th)
{
U_TRACE(0, "UThread::threadCleanup(%p)", th)
th->close();
U_INTERNAL_ASSERT_POINTER(th)
U_INTERNAL_DUMP("th->tid = %p", ((UThread*)th)->tid)
if (((UThread*)th)->tid) ((UThread*)th)->close();
}
// A special global function, getThread(), is provided to identify the thread object that represents the current
// execution context you are running under. This is sometimes needed to deliver signals to the correct thread
static UThread* getThread() __pure;
#endif
private:
class UThreadImpl* priv; // private data
friend class UNotifier;
friend class UThreadImpl;
#ifdef U_COMPILER_DELETE_MEMBERS
UThread(const UThread&) = delete;
@ -224,4 +383,14 @@ private:
#endif
};
class U_EXPORT UThreadPool {
public:
// Check for memory error
U_MEMORY_TEST
// Allocator e Deallocator
U_MEMORY_ALLOCATOR
U_MEMORY_DEALLOCATOR
};
#endif

View File

@ -43,7 +43,7 @@ const char* ULog::prefix;
struct iovec ULog::iov_vec[5];
ULog::log_date ULog::date;
ULog::log_date* ULog::ptr_shared_date;
#ifdef ENABLE_THREAD
#if defined(ENABLE_THREAD) && !defined(_MSWINDOWS_)
pthread_rwlock_t* ULog::prwlock;
#endif
@ -281,7 +281,7 @@ void ULog::updateDate1()
* 012345678901234567890123456789
*/
#ifdef ENABLE_THREAD
#if defined(ENABLE_THREAD) && !defined(_MSWINDOWS_)
if (u_pthread_time)
{
(void) U_SYSCALL(pthread_rwlock_rdlock, "%p", prwlock);
@ -353,7 +353,7 @@ void ULog::updateDate2()
* 012345678901234567890123456789
*/
#ifdef ENABLE_THREAD
#if defined(ENABLE_THREAD) && !defined(_MSWINDOWS_)
if (u_pthread_time)
{
(void) U_SYSCALL(pthread_rwlock_rdlock, "%p", prwlock);
@ -426,7 +426,7 @@ void ULog::updateDate3()
* 0123456789012345678901234567890123456789
*/
#ifdef ENABLE_THREAD
#if defined(ENABLE_THREAD) && !defined(_MSWINDOWS_)
if (u_pthread_time)
{
(void) U_SYSCALL(pthread_rwlock_rdlock, "%p", prwlock);

View File

@ -166,13 +166,13 @@ UString* UServer_Base::allow_IP_prv;
UVector<UIPAllow*>* UServer_Base::vallow_IP_prv;
#endif
#ifdef ENABLE_THREAD
#if defined(ENABLE_THREAD) && !defined(_MSWINDOWS_)
# include <ulib/thread.h>
class UTimeThread U_DECL_FINAL : public UThread {
public:
UTimeThread() : UThread(true, false) {}
UTimeThread() : UThread(PTHREAD_CREATE_DETACHED) {}
virtual void run()
{
@ -234,7 +234,7 @@ public:
class UClientThread U_DECL_FINAL : public UThread {
public:
UClientThread() : UThread(true, false) {}
UClientThread() : UThread(PTHREAD_CREATE_DETACHED) {}
virtual void run()
{
@ -251,7 +251,7 @@ public:
class UOCSPStapling U_DECL_FINAL : public UThread {
public:
UOCSPStapling() : UThread(true, false) {}
UOCSPStapling() : UThread(PTHREAD_CREATE_DETACHED) {}
virtual void run()
{
@ -352,7 +352,7 @@ UServer_Base::~UServer_Base()
U_INTERNAL_ASSERT_POINTER(socket)
U_INTERNAL_ASSERT_POINTER(vplugin)
#ifdef ENABLE_THREAD
#if defined(ENABLE_THREAD) && !defined(_MSWINDOWS_)
if (u_pthread_time)
{
((UTimeThread*)u_pthread_time)->suspend();
@ -1540,7 +1540,7 @@ void UServer_Base::init()
U_INTERNAL_ASSERT_POINTER(ptr_shared_data)
U_INTERNAL_ASSERT_DIFFERS(ptr_shared_data, MAP_FAILED)
#ifdef ENABLE_THREAD
#if defined(ENABLE_THREAD) && !defined(_MSWINDOWS_)
bool bpthread_time = (preforked_num_kids >= 4); // intuitive heuristic...
#else
bool bpthread_time = false;
@ -1553,7 +1553,7 @@ void UServer_Base::init()
#endif
ULog::initDate();
#ifdef ENABLE_THREAD
#if defined(ENABLE_THREAD) && !defined(_MSWINDOWS_)
if (bpthread_time)
{
U_INTERNAL_ASSERT_POINTER(ptr_shared_data)
@ -1588,7 +1588,7 @@ void UServer_Base::init()
flag_loop = true; // NB: UTimeThread loop depend on this setting...
#ifdef ENABLE_THREAD
#if defined(ENABLE_THREAD) && !defined(_MSWINDOWS_)
if (bpthread_time)
{
U_INTERNAL_ASSERT_EQUALS(ULog::prwlock, 0)
@ -1678,7 +1678,7 @@ void UServer_Base::init()
pthis->preallocate();
#if defined(USE_LIBSSL) && defined(ENABLE_THREAD) && !defined(OPENSSL_NO_OCSP) && defined(SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB)
#if defined(USE_LIBSSL) && defined(ENABLE_THREAD) && !defined(OPENSSL_NO_OCSP) && defined(SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB) && !defined(_MSWINDOWS_)
if (bssl)
{
if (USSLSocket::setDataForStapling() == false)
@ -1834,7 +1834,7 @@ RETSIGTYPE UServer_Base::handlerForSigHUP(int signo)
(void) U_SYSCALL(gettimeofday, "%p,%p", u_now, 0);
#ifdef ENABLE_THREAD
#if defined(ENABLE_THREAD) && !defined(_MSWINDOWS_)
# if defined(USE_LIBSSL) && !defined(OPENSSL_NO_OCSP) && defined(SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB)
if (pthread_ocsp) pthread_ocsp->suspend();
# endif
@ -1855,7 +1855,7 @@ RETSIGTYPE UServer_Base::handlerForSigHUP(int signo)
UInterrupt::insert(SIGTERM, (sighandler_t)UServer_Base::handlerForSigTERM); // async signal
#endif
#ifdef ENABLE_THREAD
#if defined(ENABLE_THREAD) && !defined(_MSWINDOWS_)
# if defined(USE_LIBSSL) && !defined(OPENSSL_NO_OCSP) && defined(SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB)
if (pthread_ocsp) pthread_ocsp->resume();
# endif
@ -1881,7 +1881,7 @@ RETSIGTYPE UServer_Base::handlerForSigTERM(int signo)
if (proc->parent())
{
# ifdef ENABLE_THREAD
# if defined(ENABLE_THREAD) && !defined(_MSWINDOWS_)
if (u_pthread_time) ((UTimeThread*)u_pthread_time)->suspend();
# endif
@ -1912,10 +1912,11 @@ RETSIGTYPE UServer_Base::handlerForSigTERM(int signo)
"SIGTERM (Interrupt): "
"address space usage: %.2f MBytes - "
"rss usage: %.2f MBytes\n"
"max_nfd_ready = %u max_depth = %u again:read = (%u/%u - %u%%) wakeup_for_nothing = %u\n",
"max_nfd_ready = %u max_depth = %u again:read = (%u/%u - %u%%) wakeup_for_nothing = %u bepollet_threshold = %u\n",
(double)vsz / (1024.0 * 1024.0),
(double)rss / (1024.0 * 1024.0), UNotifier::max_nfd_ready,
(max_depth > UNotifier::min_connection ? max_depth - UNotifier::min_connection : 0), nread_again, nread, (nread_again*100)/nread, wakeup_for_nothing);
(max_depth > UNotifier::min_connection ? max_depth - UNotifier::min_connection : 0),
nread_again, nread, (nread_again*100)/nread, wakeup_for_nothing, UNotifier::bepollet_threshold);
ostrstream os(buffer + len, sizeof(buffer) - len);

View File

@ -85,6 +85,7 @@ fd_set UNotifier::fd_set_write;
#endif
#ifdef U_EPOLLET_POSTPONE_STRATEGY
bool UNotifier::bepollet;
unsigned UNotifier::bepollet_threshold = 10;
#endif
int UNotifier::nfd_ready; // the number of file descriptors ready for the requested I/O
int UNotifier::max_nfd_ready;
@ -668,9 +669,9 @@ void UNotifier::waitForEvent(UEventTime* timeout)
# ifdef U_EPOLLET_POSTPONE_STRATEGY
bool bloop1 = false;
bepollet = (nfd_ready >= 10);
bepollet = ((unsigned)nfd_ready >= bepollet_threshold);
U_INTERNAL_DUMP("bepollet = %b nfd_ready = %d", bepollet, nfd_ready)
U_INTERNAL_DUMP("bepollet = %b nfd_ready = %d bepollet_threshold = %u", bepollet, nfd_ready, bepollet_threshold)
# endif
loop: U_INTERNAL_ASSERT_POINTER(pevents->data.ptr)
@ -736,41 +737,51 @@ loop: U_INTERNAL_ASSERT_POINTER(pevents->data.ptr)
}
# ifdef U_EPOLLET_POSTPONE_STRATEGY
while (bloop1)
if (bepollet)
{
U_INTERNAL_ASSERT(bepollet)
i = 0;
bloop1 = false;
pevents = events;
loop2: if (pevents->events)
if (bloop1 == false)
{
handler_event = (UEventFd*)pevents->data.ptr;
bepollet_threshold += bepollet_threshold / 2;
U_INTERNAL_DUMP("i = %d handler_event->fd = %d ", i, handler_event->fd)
U_INTERNAL_ASSERT_DIFFERS(handler_event->fd, -1)
if (handler_event->handlerRead() == U_NOTIFIER_DELETE)
{
handlerDelete(handler_event);
handler_event->fd = -1;
pevents->events = 0;
}
else
{
if (U_ClientImage_state != U_PLUGIN_HANDLER_AGAIN) bloop1 = true;
else pevents->events = 0;
}
U_INTERNAL_DUMP("bepollet_threshold = %u", bepollet_threshold)
}
if (++i < nfd_ready)
else
{
++pevents;
do {
i = 0;
bloop1 = false;
pevents = events;
goto loop2;
loop2: if (pevents->events)
{
handler_event = (UEventFd*)pevents->data.ptr;
U_INTERNAL_DUMP("i = %d handler_event->fd = %d ", i, handler_event->fd)
U_INTERNAL_ASSERT_DIFFERS(handler_event->fd, -1)
if (handler_event->handlerRead() == U_NOTIFIER_DELETE)
{
handlerDelete(handler_event);
handler_event->fd = -1;
pevents->events = 0;
}
else
{
if (U_ClientImage_state != U_PLUGIN_HANDLER_AGAIN) bloop1 = true;
else pevents->events = 0;
}
}
if (++i < nfd_ready)
{
++pevents;
goto loop2;
}
}
while (bloop1);
}
}
# endif

View File

@ -1520,13 +1520,13 @@ bool USSLSocket::doStapling()
p = (unsigned char*) staple.data;
# ifdef ENABLE_THREAD
# if defined(ENABLE_THREAD) && !defined(_MSWINDOWS_)
UServer_Base::lock_ocsp_staple->lock();
# endif
staple.len = i2d_OCSP_RESPONSE(resp, &p);
# ifdef ENABLE_THREAD
# if defined(ENABLE_THREAD) && !defined(_MSWINDOWS_)
UServer_Base::lock_ocsp_staple->unlock();
# endif
@ -1560,7 +1560,7 @@ void USSLSocket::certificate_status_callback(SSL* _ssl, void* data)
U_INTERNAL_ASSERT_MINOR(staple.len, U_OCSP_MAX_RESPONSE_SIZE)
# ifdef ENABLE_THREAD
# if defined(ENABLE_THREAD) && !defined(_MSWINDOWS_)
UServer_Base::lock_ocsp_staple->lock();
# endif
@ -1570,7 +1570,7 @@ void USSLSocket::certificate_status_callback(SSL* _ssl, void* data)
U_MEMCPY(p, staple.data, staple.len);
# ifdef ENABLE_THREAD
# if defined(ENABLE_THREAD) && !defined(_MSWINDOWS_)
UServer_Base::lock_ocsp_staple->unlock();
# endif

View File

@ -19,189 +19,176 @@
# include <sys/syscall.h>
#endif
typedef void* (*exec_t) (void*);
typedef void (*cleanup_t)(void*);
#ifndef HAVE_PTHREAD_CANCEL
# ifdef SIGCANCEL
# define U_SIG_THREAD_CANCEL SIGCANCEL
# else
# define U_SIG_THREAD_CANCEL SIGQUIT
# endif
#endif
#ifndef HAVE_NANOSLEEP
extern "C" { int nanosleep (const struct timespec* requested_time,
struct timespec* remaining); }
#endif
UThread* UThread::first;
pthread_cond_t UThread::cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t UThread::_lock = PTHREAD_MUTEX_INITIALIZER;
UThread* UThread::first;
class UThreadImpl {
public:
// Check for memory error
U_MEMORY_TEST
// Allocator e Deallocator
U_MEMORY_ALLOCATOR
U_MEMORY_DEALLOCATOR
UThreadImpl(bool suspendEnable, bool joinEnable)
{
U_TRACE(0, "UThreadImpl::UThreadImpl(%b,%b)", suspendEnable, joinEnable)
_tid = 0;
_signal = 0;
_cancel = 0;
_suspendCount = 0;
_suspendEnable = suspendEnable;
(void) U_SYSCALL(pthread_attr_init, "%p", &_attr);
(void) U_SYSCALL(pthread_attr_setdetachstate, "%p,%d", &_attr, (joinEnable ? PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED));
}
~UThreadImpl()
{
// U_TRACE(0, "UThreadImpl::~UThreadImpl()") // problem with sanitize address
// (void) U_SYSCALL(pthread_attr_destroy, "%p", &_attr);
(void) pthread_attr_destroy( &_attr);
}
#ifdef DEBUG
const char* dump(bool reset) const;
#ifndef _MSWINDOWS_
pthread_mutex_t UThread::mlock = PTHREAD_MUTEX_INITIALIZER;
#endif
private:
pthread_t _tid;
pthread_attr_t _attr;
int _cancel, _signal, _suspendCount;
bool _suspendEnable;
UThread::UThread(int _detachstate)
{
U_TRACE_REGISTER_OBJECT(0, UThread, "%d", _detachstate)
// derived class copy constructor creates new instance, so base copy constructor of ThreadImpl should do nothing...
next = 0;
tid = 0;
detachstate = _detachstate;
cancel = 0;
#ifdef U_COMPILER_DELETE_MEMBERS
UThreadImpl(const UThreadImpl&) = delete;
UThreadImpl& operator=(const UThreadImpl&) = delete;
#ifdef _MSWINDOWS_
HANDLE process = GetCurrentProcess();
DuplicateHandle(process, GetCurrentThread(), process, (LPHANDLE)&tid, 0, FALSE, DUPLICATE_SAME_ACCESS);
cancellation = CreateEvent(NULL, TRUE, FALSE, NULL);
#else
UThreadImpl(const UThreadImpl&) {}
UThreadImpl& operator=(const UThreadImpl&) { return *this; }
#endif
suspendCount = 0;
friend class UThread;
};
UThread::UThread(bool suspendEnable, bool joinEnable)
{
U_TRACE_REGISTER_OBJECT(0, UThread, "%b,%b", suspendEnable, joinEnable)
priv = U_NEW(UThreadImpl(suspendEnable, joinEnable));
next = first;
first = this;
U_INTERNAL_DUMP("first = %p next = %p", first, next)
}
UThread::~UThread()
{
U_TRACE_UNREGISTER_OBJECT(0, UThread)
if (priv) stop();
U_INTERNAL_DUMP("first = %p next = %p", first, next)
}
pid_t UThread::getTID()
{
U_TRACE(0, "UThread::getTID()")
pid_t _tid = syscall(SYS_gettid);
U_RETURN(_tid);
}
__pure UThread* UThread::getThread()
{
U_TRACE(1, "UThread::getThread()")
U_INTERNAL_DUMP("first = %p", first)
pthread_t _tid = (pthread_t) U_SYSCALL_NO_PARAM(pthread_self);
for (UThread* obj = first; obj; obj = obj->next)
{
if (pthread_equal(_tid, obj->priv->_tid)) U_RETURN_POINTER(obj, UThread);
}
U_RETURN_POINTER(0, UThread);
}
void UThread::stop()
{
U_TRACE(1, "UThread::stop()")
bool bdetached = isDetached();
(void) U_SYSCALL(pthread_cancel, "%p", priv->_tid);
if (bdetached == false) (void) U_SYSCALL(pthread_join, "%p,%p", priv->_tid, 0);
#ifdef HAVE_PTHREAD_YIELD
else (void) U_SYSCALL_NO_PARAM(pthread_yield);
(void) U_SYSCALL(pthread_attr_init, "%p", &attr);
(void) U_SYSCALL(pthread_attr_setdetachstate, "%p,%d", &attr, _detachstate);
#endif
}
void UThread::close()
{
U_TRACE(1, "UThread::close()")
U_TRACE(0, "UThread::close()")
if (priv)
#ifdef _MSWINDOWS_
DWORD _tid = tid;
#else
pthread_t _tid = tid;
#endif
tid = 0;
U_INTERNAL_DUMP("tid = %p first = %p next = %p", _tid, first, next)
U_INTERNAL_ASSERT_POINTER(first)
UThread* obj;
UThread** ptr = &first;
while ((obj = *ptr))
{
UThread* obj;
UThread** ptr = &first;
U_INTERNAL_ASSERT_POINTER(obj)
while ((obj = *ptr))
# ifdef _MSWINDOWS_
if (tid == obj->tid)
# else
if (pthread_equal(tid, obj->tid))
# endif
{
U_INTERNAL_ASSERT_POINTER(obj)
U_INTERNAL_ASSERT_EQUALS(this, obj)
U_INTERNAL_ASSERT_EQUALS(next, obj->next)
if (pthread_equal(priv->_tid, obj->priv->_tid))
{
*ptr = obj->next;
obj->next = 0;
*ptr = next;
next = 0;
break;
}
ptr = &(*ptr)->next;
break;
}
delete priv;
priv = 0;
ptr = &(*ptr)->next;
}
if (_tid)
{
# ifdef _MSWINDOWS_ // wait for real w32 thread to cleanup
switch (cancel)
{
case cancelImmediate: TerminateThread((HANDLE)_tid, 0); break;
default: SetEvent(cancellation);
}
(void) ::WaitForSingleObject((HANDLE)_tid, INFINITE);
(void) U_SYSCALL(CloseHandle, "%p", cancellation);
(void) U_SYSCALL(CloseHandle, "%p", (HANDLE)_tid);
ExitThread(0);
# else
# ifdef HAVE_PTHREAD_CANCEL
(void) U_SYSCALL(pthread_cancel, "%p", _tid);
# endif
if (detachstate == PTHREAD_CREATE_JOINABLE) (void) U_SYSCALL(pthread_join, "%p,%p", _tid, 0);
# ifdef HAVE_PTHREAD_YIELD
else
{
(void) U_SYSCALL_NO_PARAM(pthread_yield);
}
# endif
# endif
}
#ifndef _MSWINDOWS_
(void) pthread_attr_destroy(&attr);
#endif
}
#ifdef _MSWINDOWS_
DWORD UThread::getTID()
{
U_TRACE(0, "UThread::getTID()")
DWORD _tid = GetCurrentThreadId();
U_RETURN(_tid);
}
#else
pthread_t UThread::getTID()
{
U_TRACE(0, "UThread::getTID()")
pthread_t _tid = syscall(SYS_gettid);
U_RETURN(_tid);
}
#endif
void UThread::yield()
{
U_TRACE(1, "UThread::yield()")
// Yields the current thread's CPU time slice to allow another thread to begin immediate execution
U_INTERNAL_DUMP("_cancel = %d", priv->_cancel)
U_INTERNAL_DUMP("cancel = %d", cancel)
#ifndef CCXX_SIG_THREAD_CANCEL
#ifdef HAVE_PTHREAD_CANCEL
U_SYSCALL_VOID_NO_PARAM(pthread_testcancel);
#else
sigset_t cancel, old;
bool bcancel = (priv->_cancel != cancelDisabled && priv->_cancel != cancelInitial);
#elif !defined(_MSWINDOWS_)
sigset_t old = 0;
if (bcancel)
if (cancel != cancelInitial &&
cancel != cancelDisabled)
{
sigset_t scancel;
# ifdef sigemptyset
sigemptyset(&cancel);
sigemptyset(&scancel);
# else
(void) U_SYSCALL(sigemptyset, "%p", &cancel);
(void) U_SYSCALL(sigemptyset, "%p", &scancel);
# endif
# ifdef sigaddset
sigaddset(&cancel, CCXX_SIG_THREAD_CANCEL);
sigaddset(&scancel, U_SIG_THREAD_CANCEL);
# else
(void) U_SYSCALL(sigaddset, "%p,%d", &cancel, CCXX_SIG_THREAD_CANCEL);
(void) U_SYSCALL(sigaddset, "%p,%d", &scancel, U_SIG_THREAD_CANCEL);
# endif
(void) U_SYSCALL(pthread_sigmask, "%d,%p,%p", SIG_UNBLOCK, &cancel, &old);
(void) U_SYSCALL(pthread_sigmask, "%d,%p,%p", SIG_UNBLOCK, &scancel, &old);
}
#endif
@ -209,32 +196,12 @@ void UThread::yield()
(void) U_SYSCALL_NO_PARAM(pthread_yield);
#endif
#ifdef CCXX_SIG_THREAD_CANCEL
if (bcancel) (void) U_SYSCALL(pthread_sigmask, "%d,%p,%p", SIG_SETMASK, &old, 0);
#if !defined(HAVE_PTHREAD_CANCEL) && !defined(_MSWINDOWS_)
if (old) (void) U_SYSCALL(pthread_sigmask, "%d,%p,%p", SIG_SETMASK, &old, 0);
#endif
}
bool UThread::isDetached() const
{
U_TRACE(1, "UThread::isDetached()")
U_INTERNAL_DUMP("priv = %p", priv)
U_INTERNAL_ASSERT_POINTER(priv)
U_INTERNAL_DUMP("_tid = %p", priv->_tid)
U_INTERNAL_ASSERT_POINTER(priv->_tid)
int state;
(void) U_SYSCALL(pthread_attr_getdetachstate, "%p,%p", &(priv->_attr), &state);
if (state == PTHREAD_CREATE_DETACHED) U_RETURN(true);
U_RETURN(false);
}
#ifndef _MSWINDOWS_
void UThread::sigInstall(int signo)
{
U_TRACE(1, "UThread::sigInstall(%d)", signo)
@ -242,7 +209,7 @@ void UThread::sigInstall(int signo)
struct sigaction sa;
#ifdef sigemptyset
sigemptyset(&sa.sa_mask);
sigemptyset(&sa.sa_mask);
#else
(void) U_SYSCALL(sigemptyset, "%p", &sa.sa_mask);
#endif
@ -261,96 +228,72 @@ void UThread::sigInstall(int signo)
(void) U_SYSCALL(sigaction, "%d,%p,%p", signo, &sa, 0);
}
void UThread::sigHandler(int signo)
void UThread::manageSignal(int signo)
{
U_TRACE(1, "UThread::sigHandler(%d)", signo)
U_TRACE(1, "UThread::manageSignal(%d)", signo)
(void) U_SYSCALL(pthread_mutex_lock, "%p", &_lock);
// Mutexes are used to ensure the exclusive access, where as condition variables are used to synchronize threads based on the events.
// We need Mutexes to ensure that condition variables dont end up in an infinite wait. One thing to remember is Mutex operation of lock
// and unlock are guaranteed to be atomic, but the condition variables need not be. i.e The thread can get scheduled out while the condition variable wait is half way
UThread* th = getThread();
static pthread_cond_t mcond = PTHREAD_COND_INITIALIZER;
U_INTERNAL_DUMP("_signal = %d _suspendCount = %d", th->priv->_signal, th->priv->_suspendCount)
U_INTERNAL_DUMP("suspendCount = %d", suspendCount)
th->priv->_signal = signo;
(void) U_SYSCALL(pthread_mutex_lock, "%p", &mlock);
if (signo == U_SIGSTOP &&
th->priv->_suspendCount++ == 0)
suspendCount++ == 0)
{
U_INTERNAL_DUMP("SUSPEND: start(%2D)")
(void) U_SYSCALL(pthread_cond_wait, "%p,%p", &cond, &_lock);
// NB: A thread can wake up from pthread_cond_wait() at any name, not necessarily only when it is signalled.
// This means that you need to pair pthread_cond_wait() with some shared state that encodes the condition that the thread is really waiting for
do {
(void) U_SYSCALL(pthread_cond_wait, "%p,%p", &mcond, &mlock); // NB: pthread_cond_wait() requires that the mutex be locked already when you call it
}
while (suspendCount == 1);
U_INTERNAL_DUMP("SUSPEND: end(%2D)")
}
else if (signo == U_SIGCONT &&
th->priv->_suspendCount > 0 &&
th->priv->_suspendCount-- == 1)
else if (signo == U_SIGCONT &&
suspendCount > 0 &&
suspendCount-- == 1)
{
(void) U_SYSCALL(pthread_cond_signal, "%p", &cond);
(void) U_SYSCALL(pthread_cond_signal, "%p", &mcond);
}
(void) U_SYSCALL(pthread_mutex_unlock, "%p", &_lock);
(void) U_SYSCALL(pthread_mutex_unlock, "%p", &mlock);
}
#endif
void UThread::signal(int signo)
#ifdef _MSWINDOWS_
unsigned __stdcall UThread::execHandler(void* th)
{
U_TRACE(1, "UThread::signal(%d)", signo)
U_TRACE(0, "UThread::::execHandler(%p)", th)
// set the _signal variable to the given value. Can only be done if called from the process that the
// thread is associated with. If called from a different process, the given signal is sent to the process
U_INTERNAL_DUMP("th->tid = %p", ((UThread*)th)->tid)
pthread_t _tid = (pthread_t) U_SYSCALL_NO_PARAM(pthread_self);
((UThread*)th)->setCancel(cancelDeferred);
if (pthread_equal(_tid, priv->_tid)) sigHandler(signo);
else
{
(void) U_SYSCALL(pthread_kill, "%p,%d", priv->_tid, signo);
((UThread*)th)->run();
yield(); // give the signal a time to kick in
}
((UThread*)th)->close();
U_RETURN(0);
}
/**
* You can't kill or stop just one thread from another process. You can send a signal to a particular thread,
* but the stop/abort action that is taken by the signal affects the whole process. In the earlier implementation
* of Linux threads, it was possible to stop a single thread with SIGSTOP, but this behaviour has now been fixed
* to conform to the Posix standard (so it stops all threads in the process)
*/
void UThread::suspend()
{
U_TRACE(1, "UThread::suspend()")
U_INTERNAL_DUMP("priv = %p", priv)
U_INTERNAL_ASSERT_POINTER(priv)
U_INTERNAL_DUMP("_tid = %p", priv->_tid)
U_INTERNAL_ASSERT_POINTER(priv->_tid)
if (priv->_suspendEnable) signal(U_SIGSTOP);
}
void UThread::resume()
{
U_TRACE(1, "UThread::resume()")
U_INTERNAL_ASSERT_POINTER(priv->_tid)
if (priv->_suspendEnable) signal(U_SIGCONT);
}
#else
void UThread::execHandler(UThread* th)
{
U_TRACE(1, "UThread::execHandler(%p)", th)
th->priv->_tid = (pthread_t) U_SYSCALL_NO_PARAM(pthread_self);
U_INTERNAL_DUMP("_tid = %p", th->priv->_tid)
sigset_t mask;
th->tid = (pthread_t) U_SYSCALL_NO_PARAM(pthread_self);
U_INTERNAL_DUMP("th->tid = %p", th->tid)
#ifdef sigemptyset
sigemptyset(&mask);
#else
@ -373,36 +316,28 @@ void UThread::execHandler(UThread* th)
(void) U_SYSCALL(pthread_sigmask, "%d,%p,%p", SIG_BLOCK, &mask, 0);
if (th->priv->_suspendEnable)
{
# ifndef HAVE_PTHREAD_SUSPEND
// You can't kill or stop just one thread from another process. You can send a signal to a particular thread,
// but the stop/abort action that is taken by the signal affects the whole process. In the earlier implementation
// of Linux threads, it was possible to stop a single thread with SIGSTOP, but this behaviour has now been fixed
// to conform to the Posix standard (so it stops all threads in the process)
#ifndef HAVE_PTHREAD_SUSPEND
# ifdef sigemptyset
sigemptyset(&mask);
# else
(void) U_SYSCALL(sigemptyset, "%p", &mask);
# endif
# ifdef sigemptyset
sigemptyset(&mask);
# else
(void) U_SYSCALL(sigemptyset, "%p", &mask);
# endif
# ifdef sigaddset
sigaddset(&mask, U_SIGSTOP);
sigaddset(&mask, U_SIGCONT);
# else
(void) U_SYSCALL(sigaddset, "%p,%d", &mask, U_SIGSTOP);
(void) U_SYSCALL(sigaddset, "%p,%d", &mask, U_SIGCONT);
# endif
# ifdef sigaddset
sigaddset(&mask, U_SIGSTOP);
sigaddset(&mask, U_SIGCONT);
# else
(void) U_SYSCALL(sigaddset, "%p,%d", &mask, U_SIGSTOP);
(void) U_SYSCALL(sigaddset, "%p,%d", &mask, U_SIGCONT);
# endif
(void) U_SYSCALL(pthread_sigmask, "%d,%p,%p", SIG_UNBLOCK, &mask, 0);
(void) U_SYSCALL(pthread_sigmask, "%d,%p,%p", SIG_UNBLOCK, &mask, 0);
th->sigInstall(U_SIGSTOP);
th->sigInstall(U_SIGCONT);
#endif
th->sigInstall(U_SIGSTOP);
th->sigInstall(U_SIGCONT);
# endif
}
pthread_cleanup_push((cleanup_t)UThread::threadCleanup, th);
pthread_cleanup_push(threadCleanup, th);
th->setCancel(cancelDeferred);
@ -410,24 +345,50 @@ void UThread::execHandler(UThread* th)
pthread_cleanup_pop(0);
th->close();
U_INTERNAL_DUMP("th->tid = %p", th->tid)
if (th->tid) th->close();
}
#endif
bool UThread::start(uint32_t timeoutMS)
{
U_TRACE(1, "UThread::start(%u)", timeoutMS)
U_INTERNAL_ASSERT_EQUALS(priv->_tid, 0)
U_INTERNAL_ASSERT_EQUALS(tid, 0)
#ifdef DEBUG
#if defined(DEBUG) && !defined(_MSWINDOWS_)
if (u_plock == 0)
{
static pthread_mutex_t plock = PTHREAD_MUTEX_INITIALIZER;
u_plock = &plock;
u_plock = &plock;
}
#endif
if (U_SYSCALL(pthread_create, "%p,%p,%p,%p", &(priv->_tid), &(priv->_attr), (exec_t)execHandler, this) == 0)
next = first;
first = this;
U_INTERNAL_DUMP("first = %p next = %p", first, next)
#ifdef _MSWINDOWS_
(void) _beginthreadex(NULL, 0, execHandler, this, CREATE_SUSPENDED, (unsigned*)&tid);
if (tid == 0)
{
CloseHandle(cancellation);
cancellation = 0;
U_RETURN(false);
}
setCancel(cancelInitial);
SetThreadPriority((HANDLE)tid, THREAD_PRIORITY_NORMAL);
ResumeThread((HANDLE)tid);
#else
if (U_SYSCALL(pthread_create, "%p,%p,%p,%p", &tid, &attr, (pvPFpv)execHandler, this) == 0)
{
if (timeoutMS)
{
@ -442,26 +403,11 @@ bool UThread::start(uint32_t timeoutMS)
U_RETURN(true);
}
#endif
U_RETURN(false);
}
bool UThread::detach()
{
U_TRACE(1, "UThread::detach()")
if (priv->_tid)
{
if (U_SYSCALL(pthread_detach, "%p", priv->_tid)) U_RETURN(false);
}
else
{
if (U_SYSCALL(pthread_attr_setdetachstate, "%p,%d", &(priv->_attr), PTHREAD_CREATE_DETACHED)) U_RETURN(false);
}
U_RETURN(true);
}
void UThread::setCancel(int mode)
{
U_TRACE(1, "UThread::setCancel(%d)", mode)
@ -473,51 +419,61 @@ void UThread::setCancel(int mode)
case cancelImmediate:
case cancelDeferred:
{
# ifdef HAVE_PTHREAD_CANCEL
(void) U_SYSCALL(pthread_setcancelstate, "%d,%p", PTHREAD_CANCEL_ENABLE, &old);
(void) U_SYSCALL(pthread_setcanceltype, "%d,%p", (mode == cancelDeferred ? PTHREAD_CANCEL_DEFERRED
: PTHREAD_CANCEL_ASYNCHRONOUS), &old);
# endif
}
break;
case cancelInitial:
case cancelDisabled:
# ifdef HAVE_PTHREAD_CANCEL
(void) U_SYSCALL(pthread_setcancelstate, "%d,%p", PTHREAD_CANCEL_DISABLE, &old);
# endif
break;
}
priv->_cancel = mode;
cancel = mode;
U_INTERNAL_DUMP("_cancel = %d", priv->_cancel)
U_INTERNAL_DUMP("cancel = %d", cancel)
}
int UThread::enterCancel()
{
U_TRACE(1, "UThread::enterCancel()")
U_INTERNAL_DUMP("_cancel = %d", priv->_cancel)
U_INTERNAL_DUMP("cancel = %d", cancel)
int old = priv->_cancel;
int old = cancel;
if (old != cancelDisabled &&
old != cancelImmediate)
{
setCancel(cancelImmediate);
if (old != cancelDisabled &&
old != cancelImmediate)
{
setCancel(cancelImmediate);
U_SYSCALL_VOID_NO_PARAM(pthread_testcancel);
}
# ifdef HAVE_PTHREAD_CANCEL
U_SYSCALL_VOID_NO_PARAM(pthread_testcancel);
# elif defined(_MSWINDOWS_)
yield();
# endif
}
U_RETURN(old);
U_RETURN(old);
}
void UThread::exitCancel(int old)
{
U_TRACE(1, "UThread::exitCancel(%d)", old)
U_INTERNAL_DUMP("_cancel = %d", priv->_cancel)
U_INTERNAL_DUMP("cancel = %d", cancel)
if (old != priv->_cancel)
if (old != cancel)
{
# ifdef HAVE_PTHREAD_CANCEL
U_SYSCALL_VOID_NO_PARAM(pthread_testcancel);
# endif
setCancel(old);
}
@ -525,20 +481,37 @@ void UThread::exitCancel(int old)
void UThread::sleep(time_t timeoutMS)
{
U_TRACE(1+256, "UThread::sleep(%ld)", timeoutMS)
U_TRACE(1, "UThread::sleep(%ld)", timeoutMS)
#ifdef CCXX_SIG_THREAD_CANCEL
UThread* th = getThread();
int old = th->enterCancel();
#endif
struct timespec ts = { timeoutMS / 1000L, (timeoutMS % 1000L) * 1000000L };
struct timespec ts = { timeoutMS / 1000L, (timeoutMS % 1000L) * 1000000L };
U_INTERNAL_ASSERT(ts.tv_sec >= 0L)
U_INTERNAL_ASSERT_RANGE(0L, ts.tv_nsec, 999999999L)
#ifdef HAVE_PTHREAD_DELAY
pthread_delay(&ts);
#ifdef HAVE_PTHREAD_CANCEL
int old = enterCancel();
#endif
#ifdef _MSWINDOWS_
switch (cancel)
{
case cancelInitial:
case cancelDisabled: SleepEx(timeoutMS, FALSE); break;
default:
{
if (WaitForSingleObject(cancellation, timeoutMS) == WAIT_OBJECT_0)
{
if (cancel != cancelManual) close();
}
}
}
#endif
#ifdef HAVE_PTHREAD_DELAY
(void) pthread_delay(&ts);
#elif defined(HAVE_PTHREAD_DELAY_NP)
(void) pthread_delay_np(&ts);
#else
U_INTERNAL_DUMP("Call nanosleep(%2D)")
@ -547,37 +520,38 @@ void UThread::sleep(time_t timeoutMS)
U_INTERNAL_DUMP("Return nanosleep(%2D)")
#endif
#ifdef CCXX_SIG_THREAD_CANCEL
th->exitCancel(old);
#ifdef HAVE_PTHREAD_CANCEL
exitCancel(old);
#endif
}
// Inter Process Communication
bool UThread::initIPC(pthread_mutex_t* mutex, pthread_cond_t* cond)
#ifndef _MSWINDOWS_
bool UThread::initIPC(pthread_mutex_t* pmutex, pthread_cond_t* pcond)
{
U_TRACE(0, "UThread::initIPC(%p,%p)", mutex, cond)
U_TRACE(0, "UThread::initIPC(%p,%p)", pmutex, pcond)
if (mutex) /* initialize mutex */
if (pmutex) /* initialize mutex */
{
pthread_mutexattr_t mutexattr;
if (U_SYSCALL(pthread_mutexattr_init, "%p", &mutexattr) != 0 ||
U_SYSCALL(pthread_mutexattr_setrobust, "%p,%d", &mutexattr, PTHREAD_MUTEX_ROBUST) != 0 ||
U_SYSCALL(pthread_mutexattr_setpshared, "%p,%d", &mutexattr, PTHREAD_PROCESS_SHARED) != 0 ||
U_SYSCALL(pthread_mutex_init, "%p,%p", mutex, &mutexattr) != 0)
U_SYSCALL(pthread_mutex_init, "%p,%p", pmutex, &mutexattr) != 0)
{
U_RETURN(false);
}
}
if (cond) /* initialize condition variable */
if (pcond) /* initialize condition variable */
{
pthread_condattr_t condattr;
if (U_SYSCALL(pthread_condattr_init, "%p", &condattr) != 0 ||
U_SYSCALL(pthread_condattr_setpshared, "%p,%d", &condattr, PTHREAD_PROCESS_SHARED) != 0 ||
U_SYSCALL(pthread_cond_init, "%p,%p", cond, &condattr) != 0)
U_SYSCALL(pthread_cond_init, "%p,%p", pcond, &condattr) != 0)
{
U_RETURN(false);
}
@ -586,43 +560,29 @@ bool UThread::initIPC(pthread_mutex_t* mutex, pthread_cond_t* cond)
U_RETURN(true);
}
void UThread::doIPC(pthread_mutex_t* mutex, pthread_cond_t* cond, vPF function, bool wait)
void UThread::doIPC(pthread_mutex_t* pmutex, pthread_cond_t* pcond, vPF function, bool wait)
{
U_TRACE(0, "UThread::doIPC(%p,%p,%p,%b)", mutex, cond, function, wait)
U_TRACE(0, "UThread::doIPC(%p,%p,%p,%b)", pmutex, pcond, function, wait)
lock(mutex);
lock(pmutex);
if (wait) (void) U_SYSCALL(pthread_cond_wait, "%p,%p", cond, mutex); // block until we are signalled from other...
if (wait) (void) U_SYSCALL(pthread_cond_wait, "%p,%p", pcond, pmutex); // block until we are signalled from other...
function(); // ...than call function
unlock(mutex);
unlock(pmutex);
if (wait == false) (void) U_SYSCALL(pthread_cond_signal, "%p", cond); // signal to waiting thread...
if (wait == false) (void) U_SYSCALL(pthread_cond_signal, "%p", pcond); // signal to waiting thread...
}
#endif
#if defined(U_STDCPP_ENABLE) && defined(DEBUG)
const char* UThreadImpl::dump(bool reset) const
{
*UObjectIO::os << "_tid " << _tid << '\n'
<< "_cancel " << _cancel << '\n'
<< "_signal " << _signal << '\n'
<< "_suspendCount " << _suspendCount << '\n'
<< "_suspendEnable " << _suspendEnable;
if (reset)
{
UObjectIO::output();
return UObjectIO::buffer_output;
}
return 0;
}
const char* UThread::dump(bool reset) const
{
*UObjectIO::os << "next (UThread " << (void*)next << ")\n"
*UObjectIO::os << "tid " << tid << '\n'
<< "cancel " << cancel << '\n'
<< "detachstate " << detachstate << '\n'
<< "next (UThread " << (void*)next << ")\n"
<< "first (UThread " << (void*)first << ')';
if (reset)

View File

@ -22,9 +22,10 @@ export ORM_DRIVER ORM_OPTION UMEMPOOL
# ----------------------------------------------------------------------------------------------------------------------------------------------------------
# PLAINTEXT
# ----------------------------------------------------------------------------------------------------------------------------------------------------------
UMEMPOOL="52,0,0,39,8205,8205,-11,-20,22"
#UMEMPOOL="982,0,0,36,9846,-24,-23,1727,1151"
#sed -i "s|TCP_LINGER_SET .*|TCP_LINGER_SET 0|g" benchmark/FrameworkBenchmarks/fbenchmark.cfg
#sed -i "s|LISTEN_BACKLOG .*|LISTEN_BACKLOG 16384|g" benchmark/FrameworkBenchmarks/fbenchmark.cfg
sed -i "s|TCP_LINGER_SET .*|TCP_LINGER_SET 0|g" benchmark/FrameworkBenchmarks/fbenchmark.cfg
sed -i "s|LISTEN_BACKLOG .*|LISTEN_BACKLOG 16384|g" benchmark/FrameworkBenchmarks/fbenchmark.cfg
#sed -i "s|CLIENT_THRESHOLD .*|CLIENT_THRESHOLD 4000|g" benchmark/FrameworkBenchmarks/fbenchmark.cfg
#sed -i "s|CLIENT_FOR_PARALLELIZATION .*|CLIENT_FOR_PARALLELIZATION 8000|g" benchmark/FrameworkBenchmarks/fbenchmark.cfg
# ----------------------------------------------------------------------------------------------------------------------------------------------------------
@ -149,9 +150,9 @@ export ORM_DRIVER ORM_OPTION UMEMPOOL
# Transfer/sec: 5.96MB
# ----------------------------------------------------------------------------------------------------------------------------------------------------------
#export REDIS_HOST=localhost
UMEMPOOL="146,0,0,90,150,-22,-12,-20,0"
sed -i "s|TCP_LINGER_SET .*|TCP_LINGER_SET -2|g" benchmark/FrameworkBenchmarks/fbenchmark.cfg
sed -i "s|LISTEN_BACKLOG .*|LISTEN_BACKLOG 256|g" benchmark/FrameworkBenchmarks/fbenchmark.cfg
#UMEMPOOL="146,0,0,90,150,-22,-12,-20,0"
#sed -i "s|TCP_LINGER_SET .*|TCP_LINGER_SET -2|g" benchmark/FrameworkBenchmarks/fbenchmark.cfg
#sed -i "s|LISTEN_BACKLOG .*|LISTEN_BACKLOG 256|g" benchmark/FrameworkBenchmarks/fbenchmark.cfg
#sed -i "s|CLIENT_THRESHOLD .*|CLIENT_THRESHOLD 80|g" benchmark/FrameworkBenchmarks/fbenchmark.cfg
#sed -i "s|CLIENT_FOR_PARALLELIZATION .*|CLIENT_FOR_PARALLELIZATION 100|g" benchmark/FrameworkBenchmarks/fbenchmark.cfg
# ----------------------------------------------------------------------------------------------------------------------------------------------------------

View File

@ -1,6 +1,6 @@
#ULib Benchmarking Test
This is the [ULib][http://stefanocasazza.github.io/ULib/] portion of a [benchmarking test suite](https://github.com/TechEmpower/FrameworkBenchmarks) comparing a variety of web development platforms.
This is the [ULib](http://stefanocasazza.github.io/ULib/) portion of a [benchmarking test suite](https://github.com/TechEmpower/FrameworkBenchmarks) comparing a variety of web development platforms.
### JSON Encoding Test
@ -8,23 +8,23 @@ This is the [ULib][http://stefanocasazza.github.io/ULib/] portion of a [benchmar
### Data-Store/Database Mapping Test
* [Database test source](SQL)(src/db.usp)
* [Database test source](REDIS)(src/rdb.usp)
* [Database test source (SQL)](src/db.usp)
* [Database test source (REDIS)](src/rdb.usp)
### Variable Query Test
* [Variable Query test source](SQL)(src/query.usp)
* [Variable Query test source](REDIS)(src/rquery.usp)
* [Variable Query test source (SQL)](src/query.usp)
* [Variable Query test source (REDIS)](src/rquery.usp)
### Fortune Query Test
* [Fortune Query test source](SQL)(src/fortune.usp)
* [Fortune Query test source](REDIS)(src/rfortune.usp)
* [Fortune Query test source (SQL)](src/fortune.usp)
* [Fortune Query test source (REDIS)](src/rfortune.usp)
### Variable Query (update) Test
* [Variable Query (update) test source](SQL)(src/update.usp)
* [Variable Query (update) test source](REDIS)(src/rupdate.usp)
* [Variable Query (update) test source (SQL)](src/update.usp)
* [Variable Query (update) test source (REDIS)](src/rupdate.usp)
### Plaintext Test

View File

@ -104,6 +104,7 @@
"db_url": "/rdb",
"query_url": "/rquery?queries=",
"fortune_url": "/rfortune",
"update_url": "/rupdate?queries=",
"port": 8080,
"approach": "Realistic",
"classification": "Platform",

View File

@ -2,8 +2,8 @@ userver {
PORT 8080
PREFORK_CHILD 4
TCP_LINGER_SET -2
LISTEN_BACKLOG 256
TCP_LINGER_SET 0
LISTEN_BACKLOG 16384
DOCUMENT_ROOT benchmark/FrameworkBenchmarks/ULib/www
PID_FILE benchmark/FrameworkBenchmarks/ULib/userver_tcp.pid

View File

@ -39,10 +39,9 @@ Testing resuspend
starting father thread
starting child thread
child start
child end
father end
starting thread
created auto object on stack
ending thread
Now program should finish... :)

View File

@ -4,42 +4,47 @@
#include <iostream>
#undef OK
#define OK {printf("ok\n");}
#undef ERROR
#define ERROR {printf("ko\n");return 1;}
#define TEST_CHANGE(b) {if(!TestChange(b))return 1;}
static bool status;
static volatile int n;
static int time_to_sleep = 5;
static bool WaitNValue(int value)
{
U_TRACE(5, "::WaitNValue(%d)", value)
U_TRACE(5+256, "::WaitNValue(%d)", value)
U_INTERNAL_DUMP("n = %d", n)
for (int i = 0; ; ++i)
for (int i = 0; i < 100; ++i)
{
if (n == value) break;
if (n == value) U_RETURN(true);
if (i >= 100) U_RETURN(false);
UThread::sleep(10);
UThread::nanosleep(10);
}
U_RETURN(true);
U_RETURN(false);
}
static bool WaitChangeNValue(int value)
{
U_TRACE(5, "::WaitChangeNValue(%d)", value)
U_TRACE(5+256, "::WaitChangeNValue(%d)", value)
U_INTERNAL_DUMP("n = %d", n)
for (int i = 0; ; ++i)
for (int i = 0; i < 100; ++i)
{
if (n != value) break;
if (n != value) U_RETURN(true);
if (i >= 100) U_RETURN(false);
UThread::sleep(10);
UThread::nanosleep(10);
}
U_RETURN(true);
U_RETURN(false);
}
static bool TestChange(bool shouldChange)
@ -68,25 +73,28 @@ static bool TestChange(bool shouldChange)
class ThreadTest : public UThread {
public:
ThreadTest() : UThread(true) {}
ThreadTest() : UThread(PTHREAD_CREATE_JOINABLE) {}
virtual void run()
{
U_TRACE(5, "ThreadTest::run()")
U_TRACE(5+256, "ThreadTest::run()")
n = 1;
// wait for main thread
if (!WaitNValue(2)) return;
// increment infinitely
while (true)
if (WaitNValue(2)) // wait for main thread
{
yield();
# ifdef DEBUG
status = UTrace::suspend();
# endif
n = n+1;
while (true)
{
yield();
++n; // increment infinitely
sleep(time_to_sleep);
}
}
}
@ -95,25 +103,22 @@ public:
#endif
};
#undef OK
#define OK {printf("ok\n");}
#undef ERROR
#define ERROR {printf("ko\n");return 1;}
#define TEST_CHANGE(b) {if(!TestChange(b))return 1;}
class Child : public UThread {
public:
Child() {}
Child() : UThread(PTHREAD_CREATE_JOINABLE) {}
virtual void run()
{
U_TRACE(5, "Child::run()")
U_INTERNAL_DUMP("CHILD START")
cout << "child start" << endl;
UThread::sleep(1500);
sleep(50);
U_INTERNAL_DUMP("CHILD END")
cout << "child end" << endl;
}
@ -122,21 +127,27 @@ public:
class Father : public UThread {
public:
Father() {}
Father() : UThread(PTHREAD_CREATE_JOINABLE) {}
virtual void run()
{
U_TRACE(5, "Father::run()")
U_INTERNAL_DUMP("STARTING CHILD THREAD")
cout << "starting child thread" << endl;
UThread* th = new Child;
Child* ch = U_NEW(Child);
th->start();
ch->start();
UThread::sleep(1000);
ch->sleep(100);
delete th;
U_INTERNAL_DUMP("DELETING CHILD THREAD = %p", ch)
delete ch;
U_INTERNAL_DUMP("FATHER END")
cout << "father end" << endl;
}
@ -144,15 +155,15 @@ public:
class myObject {
public:
myObject() { cout << "created auto object on stack" << endl; }
~myObject() { cout << "destroyed auto object on cancel" << endl; }
myObject() {}
~myObject() {}
};
class myThread : public UThread {
public:
myThread() : UThread() {}
~myThread() { cout << "ending thread" << endl; }
myThread() : UThread(PTHREAD_CREATE_JOINABLE) {}
~myThread() {}
void run()
{
@ -162,7 +173,7 @@ public:
setCancel(cancelImmediate);
UThread::sleep(2000);
sleep(100);
}
};
@ -173,6 +184,7 @@ int U_EXPORT main(int argc, char* argv[])
U_TRACE(5,"main(%d)",argc)
// This is a little regression test
UThread* th;
ThreadTest test;
// test only thread, without sincronization
@ -231,15 +243,23 @@ int U_EXPORT main(int argc, char* argv[])
TEST_CHANGE(false);
test.resume();
time_to_sleep = 5000;
#ifdef DEBUG
UTrace::resume(status);
#endif
// Test child thread destroying before father
cout << "\nstarting father thread" << endl;
Father* th = new Father;
th = U_NEW(Father);
th->start();
UThread::sleep(2000);
UThread::nanosleep(200);
U_INTERNAL_DUMP("FATHER DELETE = %p", th)
delete th;
@ -247,13 +267,13 @@ int U_EXPORT main(int argc, char* argv[])
cout << "\nstarting thread" << endl;
myThread* th1 = new myThread;
th = U_NEW(myThread);
th1->start();
th->start();
UThread::sleep(1000); // 1 second
UThread::nanosleep(100); // 150 millisecond
delete th1; // delete to join
delete th; // delete to join
printf("\nNow program should finish... :)\n");

View File

@ -7,7 +7,7 @@
start_msg thread
#UTRACE="0 5M 0"
#UOBJDUMP="-1 100k 10"
#UOBJDUMP="0 100k 10"
#USIMERR="error.sim"
#VALGRIND='valgrind --leak-check=full'
export UTRACE UOBJDUMP USIMERR