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 fi
if test ! -z "$tlib" ; then 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_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 "$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; } $as_echo_n "checking for pthread_condattr_setclock in -l$tlib... " >&6; }

View File

@ -676,6 +676,12 @@ if test "$threading" = "none" ; then
]) ])
fi fi
if test ! -z "$tlib" ; then 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_CHECK_LIB($tlib,pthread_condattr_setclock,[
AC_DEFINE(HAVE_PTHREAD_CONDATTR_SETCLOCK, [1], [pthread clocking]) AC_DEFINE(HAVE_PTHREAD_CONDATTR_SETCLOCK, [1], [pthread clocking])
]) ])

View File

@ -125,6 +125,7 @@ extern "C" {
typedef int (*iPF) (void); typedef int (*iPF) (void);
typedef int (*iPFpv) (void*); typedef int (*iPFpv) (void*);
typedef unsigned (*uPFpv) (void*);
typedef int (*iPFpvpv) ( void*, void*); typedef int (*iPFpvpv) ( void*, void*);
typedef int (*qcompare)(const void*,const void*); typedef int (*qcompare)(const void*,const void*);
typedef bool (*bPFi) (int); typedef bool (*bPFi) (int);
@ -143,6 +144,7 @@ typedef void (*vPFpvpc) (void*,char*);
typedef void (*vPFpvpv) (void*,void*); typedef void (*vPFpvpv) (void*,void*);
typedef void (*vPFpvu) (void*,uint32_t); typedef void (*vPFpvu) (void*,uint32_t);
typedef void* (*pvPF) (void); typedef void* (*pvPF) (void);
typedef void* (*pvPFpv) (void*);
typedef void* (*pvPFpvpb)(void*,bool*); typedef void* (*pvPFpvpb)(void*,bool*);
typedef struct U_DATA { typedef struct U_DATA {

View File

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

View File

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

View File

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

View File

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

View File

@ -14,14 +14,15 @@
#ifndef ULIB_THREAD_H #ifndef ULIB_THREAD_H
#define ULIB_THREAD_H #define ULIB_THREAD_H
#include <ulib/internal/common.h> #include <ulib/timeval.h>
#define U_SIGSTOP (SIGRTMIN+5)
#define U_SIGCONT (SIGRTMIN+6)
#ifdef _MSWINDOWS_ #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 #endif
class UNotifier; class UNotifier;
@ -35,49 +36,55 @@ public:
U_MEMORY_ALLOCATOR U_MEMORY_ALLOCATOR
U_MEMORY_DEALLOCATOR 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 // COSTRUTTORI
UThread(bool suspendEnable = false, bool joinEnable = true); UThread(int _detachstate);
virtual ~UThread();
virtual ~UThread()
{
U_TRACE_UNREGISTER_OBJECT(0, UThread)
if (tid) close();
}
// SERVICES // SERVICES
static pid_t getTID(); #ifdef _MSWINDOWS_
static DWORD getTID();
static void sleep(time_t timeoutMS); #else
static pthread_t getTID();
#endif
// Inter Process Communication // 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; pthread_rwlockattr_t rwlockattr;
if (U_SYSCALL(pthread_rwlockattr_init, "%p", &rwlockattr) != 0 || if (U_SYSCALL(pthread_rwlockattr_init, "%p", &rwlockattr) != 0 ||
U_SYSCALL(pthread_rwlockattr_setpshared, "%p,%d", &rwlockattr, PTHREAD_PROCESS_SHARED) != 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); U_RETURN(false);
} }
@ -87,10 +94,20 @@ public:
static bool initIPC(pthread_mutex_t* mutex, pthread_cond_t* cond); 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); 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. * When a new thread is created, it does not begin immediate execution. This is because the derived class virtual tables are not properly loaded
* This method is called after initial to begin normal operation of the * 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 * thread. If the method terminates, then the thread will also terminate
*/ */
@ -100,27 +117,38 @@ public:
} }
/** /**
* When a new thread is created, it does not begin immediate execution. * Check if this thread is detached
* 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 * @return true if the thread is detached
*/ */
void stop(); bool isDetached()
bool start(uint32_t timeoutMS = 0); {
U_TRACE(0, "UThread::isDetached()")
/** U_INTERNAL_DUMP("detachstate = %d", detachstate)
* 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
*/
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 * Yields the current thread's CPU time slice to allow another thread to begin immediate execution
@ -129,34 +157,46 @@ public:
void yield(); void yield();
/** /**
* Suspends execution of the selected thread. Pthreads do not normally * Suspends execution of the selected thread. Pthreads do not normally support suspendable threads, so the behavior is simulated with signals.
* 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()")
/** # ifndef _MSWINDOWS_
* Resumes execution of the selected thread resume(tid);
*/ # ifndef HAVE_PTHREAD_SUSPEND
yield(); // give the signal a time to kick in
# endif
# endif
}
void resume(); void suspend()
{
U_TRACE(0, "UThread::suspend()")
/** # ifndef _MSWINDOWS_
* Check if this thread is detached suspend(tid);
* # ifndef HAVE_PTHREAD_SUSPEND
* @return true if the thread is detached yield(); // give the signal a time to kick in
*/ # endif
# endif
bool isDetached() const; }
/**
* Each time a thread receives a signal, it stores the signal number locally
*/
void signal(int signo);
// Cancellation // 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); void setCancel(int mode);
/** /**
@ -176,44 +216,163 @@ public:
void exitCancel(int cancel); 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) #if defined(U_STDCPP_ENABLE) && defined(DEBUG)
const char* dump(bool reset) const; const char* dump(bool reset) const;
#endif #endif
protected: protected:
UThread* next; 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 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 sigInstall(int signo);
void manageSignal(int signo);
static void lock() { lock(&_lock); } static void lock() { lock(&mlock); }
static void unlock() { unlock(&_lock); } static void unlock() { unlock(&mlock); }
static void sigHandler(int signo);
static void execHandler(UThread* th); 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) 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();
} }
#endif
// 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;
private: private:
class UThreadImpl* priv; // private data
friend class UNotifier; friend class UNotifier;
friend class UThreadImpl;
#ifdef U_COMPILER_DELETE_MEMBERS #ifdef U_COMPILER_DELETE_MEMBERS
UThread(const UThread&) = delete; UThread(const UThread&) = delete;
@ -224,4 +383,14 @@ private:
#endif #endif
}; };
class U_EXPORT UThreadPool {
public:
// Check for memory error
U_MEMORY_TEST
// Allocator e Deallocator
U_MEMORY_ALLOCATOR
U_MEMORY_DEALLOCATOR
};
#endif #endif

View File

@ -43,7 +43,7 @@ const char* ULog::prefix;
struct iovec ULog::iov_vec[5]; struct iovec ULog::iov_vec[5];
ULog::log_date ULog::date; ULog::log_date ULog::date;
ULog::log_date* ULog::ptr_shared_date; ULog::log_date* ULog::ptr_shared_date;
#ifdef ENABLE_THREAD #if defined(ENABLE_THREAD) && !defined(_MSWINDOWS_)
pthread_rwlock_t* ULog::prwlock; pthread_rwlock_t* ULog::prwlock;
#endif #endif
@ -281,7 +281,7 @@ void ULog::updateDate1()
* 012345678901234567890123456789 * 012345678901234567890123456789
*/ */
#ifdef ENABLE_THREAD #if defined(ENABLE_THREAD) && !defined(_MSWINDOWS_)
if (u_pthread_time) if (u_pthread_time)
{ {
(void) U_SYSCALL(pthread_rwlock_rdlock, "%p", prwlock); (void) U_SYSCALL(pthread_rwlock_rdlock, "%p", prwlock);
@ -353,7 +353,7 @@ void ULog::updateDate2()
* 012345678901234567890123456789 * 012345678901234567890123456789
*/ */
#ifdef ENABLE_THREAD #if defined(ENABLE_THREAD) && !defined(_MSWINDOWS_)
if (u_pthread_time) if (u_pthread_time)
{ {
(void) U_SYSCALL(pthread_rwlock_rdlock, "%p", prwlock); (void) U_SYSCALL(pthread_rwlock_rdlock, "%p", prwlock);
@ -426,7 +426,7 @@ void ULog::updateDate3()
* 0123456789012345678901234567890123456789 * 0123456789012345678901234567890123456789
*/ */
#ifdef ENABLE_THREAD #if defined(ENABLE_THREAD) && !defined(_MSWINDOWS_)
if (u_pthread_time) if (u_pthread_time)
{ {
(void) U_SYSCALL(pthread_rwlock_rdlock, "%p", prwlock); (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; UVector<UIPAllow*>* UServer_Base::vallow_IP_prv;
#endif #endif
#ifdef ENABLE_THREAD #if defined(ENABLE_THREAD) && !defined(_MSWINDOWS_)
# include <ulib/thread.h> # include <ulib/thread.h>
class UTimeThread U_DECL_FINAL : public UThread { class UTimeThread U_DECL_FINAL : public UThread {
public: public:
UTimeThread() : UThread(true, false) {} UTimeThread() : UThread(PTHREAD_CREATE_DETACHED) {}
virtual void run() virtual void run()
{ {
@ -234,7 +234,7 @@ public:
class UClientThread U_DECL_FINAL : public UThread { class UClientThread U_DECL_FINAL : public UThread {
public: public:
UClientThread() : UThread(true, false) {} UClientThread() : UThread(PTHREAD_CREATE_DETACHED) {}
virtual void run() virtual void run()
{ {
@ -251,7 +251,7 @@ public:
class UOCSPStapling U_DECL_FINAL : public UThread { class UOCSPStapling U_DECL_FINAL : public UThread {
public: public:
UOCSPStapling() : UThread(true, false) {} UOCSPStapling() : UThread(PTHREAD_CREATE_DETACHED) {}
virtual void run() virtual void run()
{ {
@ -352,7 +352,7 @@ UServer_Base::~UServer_Base()
U_INTERNAL_ASSERT_POINTER(socket) U_INTERNAL_ASSERT_POINTER(socket)
U_INTERNAL_ASSERT_POINTER(vplugin) U_INTERNAL_ASSERT_POINTER(vplugin)
#ifdef ENABLE_THREAD #if defined(ENABLE_THREAD) && !defined(_MSWINDOWS_)
if (u_pthread_time) if (u_pthread_time)
{ {
((UTimeThread*)u_pthread_time)->suspend(); ((UTimeThread*)u_pthread_time)->suspend();
@ -1540,7 +1540,7 @@ void UServer_Base::init()
U_INTERNAL_ASSERT_POINTER(ptr_shared_data) U_INTERNAL_ASSERT_POINTER(ptr_shared_data)
U_INTERNAL_ASSERT_DIFFERS(ptr_shared_data, MAP_FAILED) 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... bool bpthread_time = (preforked_num_kids >= 4); // intuitive heuristic...
#else #else
bool bpthread_time = false; bool bpthread_time = false;
@ -1553,7 +1553,7 @@ void UServer_Base::init()
#endif #endif
ULog::initDate(); ULog::initDate();
#ifdef ENABLE_THREAD #if defined(ENABLE_THREAD) && !defined(_MSWINDOWS_)
if (bpthread_time) if (bpthread_time)
{ {
U_INTERNAL_ASSERT_POINTER(ptr_shared_data) 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... flag_loop = true; // NB: UTimeThread loop depend on this setting...
#ifdef ENABLE_THREAD #if defined(ENABLE_THREAD) && !defined(_MSWINDOWS_)
if (bpthread_time) if (bpthread_time)
{ {
U_INTERNAL_ASSERT_EQUALS(ULog::prwlock, 0) U_INTERNAL_ASSERT_EQUALS(ULog::prwlock, 0)
@ -1678,7 +1678,7 @@ void UServer_Base::init()
pthis->preallocate(); 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 (bssl)
{ {
if (USSLSocket::setDataForStapling() == false) if (USSLSocket::setDataForStapling() == false)
@ -1834,7 +1834,7 @@ RETSIGTYPE UServer_Base::handlerForSigHUP(int signo)
(void) U_SYSCALL(gettimeofday, "%p,%p", u_now, 0); (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 defined(USE_LIBSSL) && !defined(OPENSSL_NO_OCSP) && defined(SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB)
if (pthread_ocsp) pthread_ocsp->suspend(); if (pthread_ocsp) pthread_ocsp->suspend();
# endif # endif
@ -1855,7 +1855,7 @@ RETSIGTYPE UServer_Base::handlerForSigHUP(int signo)
UInterrupt::insert(SIGTERM, (sighandler_t)UServer_Base::handlerForSigTERM); // async signal UInterrupt::insert(SIGTERM, (sighandler_t)UServer_Base::handlerForSigTERM); // async signal
#endif #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 defined(USE_LIBSSL) && !defined(OPENSSL_NO_OCSP) && defined(SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB)
if (pthread_ocsp) pthread_ocsp->resume(); if (pthread_ocsp) pthread_ocsp->resume();
# endif # endif
@ -1881,7 +1881,7 @@ RETSIGTYPE UServer_Base::handlerForSigTERM(int signo)
if (proc->parent()) if (proc->parent())
{ {
# ifdef ENABLE_THREAD # if defined(ENABLE_THREAD) && !defined(_MSWINDOWS_)
if (u_pthread_time) ((UTimeThread*)u_pthread_time)->suspend(); if (u_pthread_time) ((UTimeThread*)u_pthread_time)->suspend();
# endif # endif
@ -1912,10 +1912,11 @@ RETSIGTYPE UServer_Base::handlerForSigTERM(int signo)
"SIGTERM (Interrupt): " "SIGTERM (Interrupt): "
"address space usage: %.2f MBytes - " "address space usage: %.2f MBytes - "
"rss usage: %.2f MBytes\n" "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)vsz / (1024.0 * 1024.0),
(double)rss / (1024.0 * 1024.0), UNotifier::max_nfd_ready, (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); ostrstream os(buffer + len, sizeof(buffer) - len);

View File

@ -85,6 +85,7 @@ fd_set UNotifier::fd_set_write;
#endif #endif
#ifdef U_EPOLLET_POSTPONE_STRATEGY #ifdef U_EPOLLET_POSTPONE_STRATEGY
bool UNotifier::bepollet; bool UNotifier::bepollet;
unsigned UNotifier::bepollet_threshold = 10;
#endif #endif
int UNotifier::nfd_ready; // the number of file descriptors ready for the requested I/O int UNotifier::nfd_ready; // the number of file descriptors ready for the requested I/O
int UNotifier::max_nfd_ready; int UNotifier::max_nfd_ready;
@ -668,9 +669,9 @@ void UNotifier::waitForEvent(UEventTime* timeout)
# ifdef U_EPOLLET_POSTPONE_STRATEGY # ifdef U_EPOLLET_POSTPONE_STRATEGY
bool bloop1 = false; 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 # endif
loop: U_INTERNAL_ASSERT_POINTER(pevents->data.ptr) loop: U_INTERNAL_ASSERT_POINTER(pevents->data.ptr)
@ -736,10 +737,17 @@ loop: U_INTERNAL_ASSERT_POINTER(pevents->data.ptr)
} }
# ifdef U_EPOLLET_POSTPONE_STRATEGY # ifdef U_EPOLLET_POSTPONE_STRATEGY
while (bloop1) if (bepollet)
{ {
U_INTERNAL_ASSERT(bepollet) if (bloop1 == false)
{
bepollet_threshold += bepollet_threshold / 2;
U_INTERNAL_DUMP("bepollet_threshold = %u", bepollet_threshold)
}
else
{
do {
i = 0; i = 0;
bloop1 = false; bloop1 = false;
pevents = events; pevents = events;
@ -773,6 +781,9 @@ loop2: if (pevents->events)
goto loop2; goto loop2;
} }
} }
while (bloop1);
}
}
# endif # endif
# else # else
int fd = 1, fd_cnt = (fd_read_cnt + fd_write_cnt); int fd = 1, fd_cnt = (fd_read_cnt + fd_write_cnt);

View File

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

View File

@ -19,8 +19,13 @@
# include <sys/syscall.h> # include <sys/syscall.h>
#endif #endif
typedef void* (*exec_t) (void*); #ifndef HAVE_PTHREAD_CANCEL
typedef void (*cleanup_t)(void*); # ifdef SIGCANCEL
# define U_SIG_THREAD_CANCEL SIGCANCEL
# else
# define U_SIG_THREAD_CANCEL SIGQUIT
# endif
#endif
#ifndef HAVE_NANOSLEEP #ifndef HAVE_NANOSLEEP
extern "C" { int nanosleep (const struct timespec* requested_time, extern "C" { int nanosleep (const struct timespec* requested_time,
@ -28,128 +33,50 @@ extern "C" { int nanosleep (const struct timespec* requested_time,
#endif #endif
UThread* UThread::first; UThread* UThread::first;
pthread_cond_t UThread::cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t UThread::_lock = PTHREAD_MUTEX_INITIALIZER;
class UThreadImpl { #ifndef _MSWINDOWS_
public: pthread_mutex_t UThread::mlock = PTHREAD_MUTEX_INITIALIZER;
// 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;
#endif #endif
private: UThread::UThread(int _detachstate)
pthread_t _tid; {
pthread_attr_t _attr; U_TRACE_REGISTER_OBJECT(0, UThread, "%d", _detachstate)
int _cancel, _signal, _suspendCount;
bool _suspendEnable;
// 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 #ifdef _MSWINDOWS_
UThreadImpl(const UThreadImpl&) = delete; HANDLE process = GetCurrentProcess();
UThreadImpl& operator=(const UThreadImpl&) = delete;
DuplicateHandle(process, GetCurrentThread(), process, (LPHANDLE)&tid, 0, FALSE, DUPLICATE_SAME_ACCESS);
cancellation = CreateEvent(NULL, TRUE, FALSE, NULL);
#else #else
UThreadImpl(const UThreadImpl&) {} suspendCount = 0;
UThreadImpl& operator=(const UThreadImpl&) { return *this; }
#endif
friend class UThread; (void) U_SYSCALL(pthread_attr_init, "%p", &attr);
}; (void) U_SYSCALL(pthread_attr_setdetachstate, "%p,%d", &attr, _detachstate);
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);
#endif #endif
} }
void UThread::close() void UThread::close()
{ {
U_TRACE(1, "UThread::close()") U_TRACE(0, "UThread::close()")
#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)
if (priv)
{
UThread* obj; UThread* obj;
UThread** ptr = &first; UThread** ptr = &first;
@ -157,10 +84,17 @@ void UThread::close()
{ {
U_INTERNAL_ASSERT_POINTER(obj) U_INTERNAL_ASSERT_POINTER(obj)
if (pthread_equal(priv->_tid, obj->priv->_tid)) # ifdef _MSWINDOWS_
if (tid == obj->tid)
# else
if (pthread_equal(tid, obj->tid))
# endif
{ {
*ptr = obj->next; U_INTERNAL_ASSERT_EQUALS(this, obj)
obj->next = 0; U_INTERNAL_ASSERT_EQUALS(next, obj->next)
*ptr = next;
next = 0;
break; break;
} }
@ -168,40 +102,93 @@ void UThread::close()
ptr = &(*ptr)->next; ptr = &(*ptr)->next;
} }
delete priv; if (_tid)
priv = 0; {
# 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() void UThread::yield()
{ {
U_TRACE(1, "UThread::yield()") U_TRACE(1, "UThread::yield()")
// Yields the current thread's CPU time slice to allow another thread to begin immediate execution // 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); U_SYSCALL_VOID_NO_PARAM(pthread_testcancel);
#else #elif !defined(_MSWINDOWS_)
sigset_t cancel, old; sigset_t old = 0;
bool bcancel = (priv->_cancel != cancelDisabled && priv->_cancel != cancelInitial);
if (bcancel) if (cancel != cancelInitial &&
cancel != cancelDisabled)
{ {
sigset_t scancel;
# ifdef sigemptyset # ifdef sigemptyset
sigemptyset(&cancel); sigemptyset(&scancel);
# else # else
(void) U_SYSCALL(sigemptyset, "%p", &cancel); (void) U_SYSCALL(sigemptyset, "%p", &scancel);
# endif # endif
# ifdef sigaddset # ifdef sigaddset
sigaddset(&cancel, CCXX_SIG_THREAD_CANCEL); sigaddset(&scancel, U_SIG_THREAD_CANCEL);
# else # else
(void) U_SYSCALL(sigaddset, "%p,%d", &cancel, CCXX_SIG_THREAD_CANCEL); (void) U_SYSCALL(sigaddset, "%p,%d", &scancel, U_SIG_THREAD_CANCEL);
# endif # 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 #endif
@ -209,32 +196,12 @@ void UThread::yield()
(void) U_SYSCALL_NO_PARAM(pthread_yield); (void) U_SYSCALL_NO_PARAM(pthread_yield);
#endif #endif
#ifdef CCXX_SIG_THREAD_CANCEL #if !defined(HAVE_PTHREAD_CANCEL) && !defined(_MSWINDOWS_)
if (bcancel) (void) U_SYSCALL(pthread_sigmask, "%d,%p,%p", SIG_SETMASK, &old, 0); if (old) (void) U_SYSCALL(pthread_sigmask, "%d,%p,%p", SIG_SETMASK, &old, 0);
#endif #endif
} }
bool UThread::isDetached() const #ifndef _MSWINDOWS_
{
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);
}
void UThread::sigInstall(int signo) void UThread::sigInstall(int signo)
{ {
U_TRACE(1, "UThread::sigInstall(%d)", signo) U_TRACE(1, "UThread::sigInstall(%d)", signo)
@ -261,96 +228,72 @@ void UThread::sigInstall(int signo)
(void) U_SYSCALL(sigaction, "%d,%p,%p", signo, &sa, 0); (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 && if (signo == U_SIGSTOP &&
th->priv->_suspendCount++ == 0) suspendCount++ == 0)
{ {
U_INTERNAL_DUMP("SUSPEND: start(%2D)") 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)") U_INTERNAL_DUMP("SUSPEND: end(%2D)")
} }
else if (signo == U_SIGCONT && else if (signo == U_SIGCONT &&
th->priv->_suspendCount > 0 && suspendCount > 0 &&
th->priv->_suspendCount-- == 1) 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 U_INTERNAL_DUMP("th->tid = %p", ((UThread*)th)->tid)
// thread is associated with. If called from a different process, the given signal is sent to the process
pthread_t _tid = (pthread_t) U_SYSCALL_NO_PARAM(pthread_self); ((UThread*)th)->setCancel(cancelDeferred);
if (pthread_equal(_tid, priv->_tid)) sigHandler(signo); ((UThread*)th)->run();
else
{
(void) U_SYSCALL(pthread_kill, "%p,%d", priv->_tid, signo);
yield(); // give the signal a time to kick in ((UThread*)th)->close();
}
U_RETURN(0);
} }
#else
/**
* 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);
}
void UThread::execHandler(UThread* th) void UThread::execHandler(UThread* th)
{ {
U_TRACE(1, "UThread::execHandler(%p)", 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; sigset_t mask;
th->tid = (pthread_t) U_SYSCALL_NO_PARAM(pthread_self);
U_INTERNAL_DUMP("th->tid = %p", th->tid)
#ifdef sigemptyset #ifdef sigemptyset
sigemptyset(&mask); sigemptyset(&mask);
#else #else
@ -373,14 +316,7 @@ void UThread::execHandler(UThread* th)
(void) U_SYSCALL(pthread_sigmask, "%d,%p,%p", SIG_BLOCK, &mask, 0); (void) U_SYSCALL(pthread_sigmask, "%d,%p,%p", SIG_BLOCK, &mask, 0);
if (th->priv->_suspendEnable) #ifndef HAVE_PTHREAD_SUSPEND
{
# 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)
# ifdef sigemptyset # ifdef sigemptyset
sigemptyset(&mask); sigemptyset(&mask);
# else # else
@ -399,10 +335,9 @@ void UThread::execHandler(UThread* th)
th->sigInstall(U_SIGSTOP); th->sigInstall(U_SIGSTOP);
th->sigInstall(U_SIGCONT); th->sigInstall(U_SIGCONT);
# endif #endif
}
pthread_cleanup_push((cleanup_t)UThread::threadCleanup, th); pthread_cleanup_push(threadCleanup, th);
th->setCancel(cancelDeferred); th->setCancel(cancelDeferred);
@ -410,24 +345,50 @@ void UThread::execHandler(UThread* th)
pthread_cleanup_pop(0); 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) bool UThread::start(uint32_t timeoutMS)
{ {
U_TRACE(1, "UThread::start(%u)", 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) if (u_plock == 0)
{ {
static pthread_mutex_t plock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t plock = PTHREAD_MUTEX_INITIALIZER;
u_plock = &plock; u_plock = &plock;
} }
#endif #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) if (timeoutMS)
{ {
@ -442,26 +403,11 @@ bool UThread::start(uint32_t timeoutMS)
U_RETURN(true); U_RETURN(true);
} }
#endif
U_RETURN(false); 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) void UThread::setCancel(int mode)
{ {
U_TRACE(1, "UThread::setCancel(%d)", mode) U_TRACE(1, "UThread::setCancel(%d)", mode)
@ -473,37 +419,45 @@ void UThread::setCancel(int mode)
case cancelImmediate: case cancelImmediate:
case cancelDeferred: case cancelDeferred:
{ {
# ifdef HAVE_PTHREAD_CANCEL
(void) U_SYSCALL(pthread_setcancelstate, "%d,%p", PTHREAD_CANCEL_ENABLE, &old); (void) U_SYSCALL(pthread_setcancelstate, "%d,%p", PTHREAD_CANCEL_ENABLE, &old);
(void) U_SYSCALL(pthread_setcanceltype, "%d,%p", (mode == cancelDeferred ? PTHREAD_CANCEL_DEFERRED (void) U_SYSCALL(pthread_setcanceltype, "%d,%p", (mode == cancelDeferred ? PTHREAD_CANCEL_DEFERRED
: PTHREAD_CANCEL_ASYNCHRONOUS), &old); : PTHREAD_CANCEL_ASYNCHRONOUS), &old);
# endif
} }
break; break;
case cancelInitial: case cancelInitial:
case cancelDisabled: case cancelDisabled:
# ifdef HAVE_PTHREAD_CANCEL
(void) U_SYSCALL(pthread_setcancelstate, "%d,%p", PTHREAD_CANCEL_DISABLE, &old); (void) U_SYSCALL(pthread_setcancelstate, "%d,%p", PTHREAD_CANCEL_DISABLE, &old);
# endif
break; break;
} }
priv->_cancel = mode; cancel = mode;
U_INTERNAL_DUMP("_cancel = %d", priv->_cancel) U_INTERNAL_DUMP("cancel = %d", cancel)
} }
int UThread::enterCancel() int UThread::enterCancel()
{ {
U_TRACE(1, "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 && if (old != cancelDisabled &&
old != cancelImmediate) old != cancelImmediate)
{ {
setCancel(cancelImmediate); setCancel(cancelImmediate);
# ifdef HAVE_PTHREAD_CANCEL
U_SYSCALL_VOID_NO_PARAM(pthread_testcancel); U_SYSCALL_VOID_NO_PARAM(pthread_testcancel);
# elif defined(_MSWINDOWS_)
yield();
# endif
} }
U_RETURN(old); U_RETURN(old);
@ -513,11 +467,13 @@ void UThread::exitCancel(int old)
{ {
U_TRACE(1, "UThread::exitCancel(%d)", 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); U_SYSCALL_VOID_NO_PARAM(pthread_testcancel);
# endif
setCancel(old); setCancel(old);
} }
@ -525,20 +481,37 @@ void UThread::exitCancel(int old)
void UThread::sleep(time_t timeoutMS) 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(ts.tv_sec >= 0L)
U_INTERNAL_ASSERT_RANGE(0L, ts.tv_nsec, 999999999L) U_INTERNAL_ASSERT_RANGE(0L, ts.tv_nsec, 999999999L)
#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 #ifdef HAVE_PTHREAD_DELAY
pthread_delay(&ts); (void) pthread_delay(&ts);
#elif defined(HAVE_PTHREAD_DELAY_NP)
(void) pthread_delay_np(&ts);
#else #else
U_INTERNAL_DUMP("Call nanosleep(%2D)") U_INTERNAL_DUMP("Call nanosleep(%2D)")
@ -547,37 +520,38 @@ void UThread::sleep(time_t timeoutMS)
U_INTERNAL_DUMP("Return nanosleep(%2D)") U_INTERNAL_DUMP("Return nanosleep(%2D)")
#endif #endif
#ifdef CCXX_SIG_THREAD_CANCEL #ifdef HAVE_PTHREAD_CANCEL
th->exitCancel(old); exitCancel(old);
#endif #endif
} }
// Inter Process Communication // 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; pthread_mutexattr_t mutexattr;
if (U_SYSCALL(pthread_mutexattr_init, "%p", &mutexattr) != 0 || 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_setrobust, "%p,%d", &mutexattr, PTHREAD_MUTEX_ROBUST) != 0 ||
U_SYSCALL(pthread_mutexattr_setpshared, "%p,%d", &mutexattr, PTHREAD_PROCESS_SHARED) != 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); U_RETURN(false);
} }
} }
if (cond) /* initialize condition variable */ if (pcond) /* initialize condition variable */
{ {
pthread_condattr_t condattr; pthread_condattr_t condattr;
if (U_SYSCALL(pthread_condattr_init, "%p", &condattr) != 0 || if (U_SYSCALL(pthread_condattr_init, "%p", &condattr) != 0 ||
U_SYSCALL(pthread_condattr_setpshared, "%p,%d", &condattr, PTHREAD_PROCESS_SHARED) != 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); U_RETURN(false);
} }
@ -586,43 +560,29 @@ bool UThread::initIPC(pthread_mutex_t* mutex, pthread_cond_t* cond)
U_RETURN(true); 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 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) #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 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 << ')'; << "first (UThread " << (void*)first << ')';
if (reset) if (reset)

View File

@ -22,9 +22,10 @@ export ORM_DRIVER ORM_OPTION UMEMPOOL
# ---------------------------------------------------------------------------------------------------------------------------------------------------------- # ----------------------------------------------------------------------------------------------------------------------------------------------------------
# PLAINTEXT # PLAINTEXT
# ---------------------------------------------------------------------------------------------------------------------------------------------------------- # ----------------------------------------------------------------------------------------------------------------------------------------------------------
UMEMPOOL="52,0,0,39,8205,8205,-11,-20,22"
#UMEMPOOL="982,0,0,36,9846,-24,-23,1727,1151" #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|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|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_THRESHOLD .*|CLIENT_THRESHOLD 4000|g" benchmark/FrameworkBenchmarks/fbenchmark.cfg
#sed -i "s|CLIENT_FOR_PARALLELIZATION .*|CLIENT_FOR_PARALLELIZATION 8000|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 # Transfer/sec: 5.96MB
# ---------------------------------------------------------------------------------------------------------------------------------------------------------- # ----------------------------------------------------------------------------------------------------------------------------------------------------------
#export REDIS_HOST=localhost #export REDIS_HOST=localhost
UMEMPOOL="146,0,0,90,150,-22,-12,-20,0" #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|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|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_THRESHOLD .*|CLIENT_THRESHOLD 80|g" benchmark/FrameworkBenchmarks/fbenchmark.cfg
#sed -i "s|CLIENT_FOR_PARALLELIZATION .*|CLIENT_FOR_PARALLELIZATION 100|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 #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 ### 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 ### Data-Store/Database Mapping Test
* [Database test source](SQL)(src/db.usp) * [Database test source (SQL)](src/db.usp)
* [Database test source](REDIS)(src/rdb.usp) * [Database test source (REDIS)](src/rdb.usp)
### Variable Query Test ### Variable Query Test
* [Variable Query test source](SQL)(src/query.usp) * [Variable Query test source (SQL)](src/query.usp)
* [Variable Query test source](REDIS)(src/rquery.usp) * [Variable Query test source (REDIS)](src/rquery.usp)
### Fortune Query Test ### Fortune Query Test
* [Fortune Query test source](SQL)(src/fortune.usp) * [Fortune Query test source (SQL)](src/fortune.usp)
* [Fortune Query test source](REDIS)(src/rfortune.usp) * [Fortune Query test source (REDIS)](src/rfortune.usp)
### Variable Query (update) Test ### Variable Query (update) Test
* [Variable Query (update) test source](SQL)(src/update.usp) * [Variable Query (update) test source (SQL)](src/update.usp)
* [Variable Query (update) test source](REDIS)(src/rupdate.usp) * [Variable Query (update) test source (REDIS)](src/rupdate.usp)
### Plaintext Test ### Plaintext Test

View File

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

View File

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

View File

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

View File

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

View File

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