diff --git a/configure b/configure index 8f363475..4e0d170a 100755 --- a/configure +++ b/configure @@ -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; } diff --git a/configure.ac b/configure.ac index 3c23aaa7..a30e7104 100644 --- a/configure.ac +++ b/configure.ac @@ -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]) ]) diff --git a/include/ulib/base/base.h b/include/ulib/base/base.h index 2c269c75..7462fdfc 100644 --- a/include/ulib/base/base.h +++ b/include/ulib/base/base.h @@ -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; diff --git a/include/ulib/internal/config.h.in b/include/ulib/internal/config.h.in index cc7774bb..5fbb27f5 100644 --- a/include/ulib/internal/config.h.in +++ b/include/ulib/internal/config.h.in @@ -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 diff --git a/include/ulib/log.h b/include/ulib/log.h index bed24a8f..a6c155d1 100644 --- a/include/ulib/log.h +++ b/include/ulib/log.h @@ -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 diff --git a/include/ulib/net/server/server.h b/include/ulib/net/server/server.h index 9e28f3a6..07fd4036 100644 --- a/include/ulib/net/server/server.h +++ b/include/ulib/net/server/server.h @@ -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; diff --git a/include/ulib/notifier.h b/include/ulib/notifier.h index a0255e10..0eb74318 100644 --- a/include/ulib/notifier.h +++ b/include/ulib/notifier.h @@ -124,6 +124,7 @@ protected: #ifdef U_EPOLLET_POSTPONE_STRATEGY static bool bepollet; + static unsigned bepollet_threshold; #endif #ifdef USE_LIBEVENT diff --git a/include/ulib/thread.h b/include/ulib/thread.h index fc5d31ac..af3cdf14 100644 --- a/include/ulib/thread.h +++ b/include/ulib/thread.h @@ -14,14 +14,15 @@ #ifndef ULIB_THREAD_H #define ULIB_THREAD_H -#include - -#define U_SIGSTOP (SIGRTMIN+5) -#define U_SIGCONT (SIGRTMIN+6) +#include #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 diff --git a/src/ulib/log.cpp b/src/ulib/log.cpp index 8bd13f42..0323172c 100644 --- a/src/ulib/log.cpp +++ b/src/ulib/log.cpp @@ -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); diff --git a/src/ulib/net/server/server.cpp b/src/ulib/net/server/server.cpp index 3c0ffe52..db4a371e 100644 --- a/src/ulib/net/server/server.cpp +++ b/src/ulib/net/server/server.cpp @@ -166,13 +166,13 @@ UString* UServer_Base::allow_IP_prv; UVector* UServer_Base::vallow_IP_prv; #endif -#ifdef ENABLE_THREAD +#if defined(ENABLE_THREAD) && !defined(_MSWINDOWS_) # include 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); diff --git a/src/ulib/notifier.cpp b/src/ulib/notifier.cpp index 8e88fdd9..a873383d 100644 --- a/src/ulib/notifier.cpp +++ b/src/ulib/notifier.cpp @@ -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 diff --git a/src/ulib/ssl/net/sslsocket.cpp b/src/ulib/ssl/net/sslsocket.cpp index 54717fc2..56099036 100644 --- a/src/ulib/ssl/net/sslsocket.cpp +++ b/src/ulib/ssl/net/sslsocket.cpp @@ -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 diff --git a/src/ulib/thread.cpp b/src/ulib/thread.cpp index 49308ff7..3058b160 100644 --- a/src/ulib/thread.cpp +++ b/src/ulib/thread.cpp @@ -19,189 +19,176 @@ # include #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) diff --git a/tests/examples/FrameworkBenchmarks.sh b/tests/examples/FrameworkBenchmarks.sh index 47c6f392..41f00d23 100755 --- a/tests/examples/FrameworkBenchmarks.sh +++ b/tests/examples/FrameworkBenchmarks.sh @@ -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 # ---------------------------------------------------------------------------------------------------------------------------------------------------------- diff --git a/tests/examples/benchmark/FrameworkBenchmarks/ULib/README.md b/tests/examples/benchmark/FrameworkBenchmarks/ULib/README.md index 65d5518d..0cbc812a 100644 --- a/tests/examples/benchmark/FrameworkBenchmarks/ULib/README.md +++ b/tests/examples/benchmark/FrameworkBenchmarks/ULib/README.md @@ -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 diff --git a/tests/examples/benchmark/FrameworkBenchmarks/ULib/benchmark_config.json b/tests/examples/benchmark/FrameworkBenchmarks/ULib/benchmark_config.json index 79ca08a1..d31a97e1 100644 --- a/tests/examples/benchmark/FrameworkBenchmarks/ULib/benchmark_config.json +++ b/tests/examples/benchmark/FrameworkBenchmarks/ULib/benchmark_config.json @@ -104,6 +104,7 @@ "db_url": "/rdb", "query_url": "/rquery?queries=", "fortune_url": "/rfortune", + "update_url": "/rupdate?queries=", "port": 8080, "approach": "Realistic", "classification": "Platform", diff --git a/tests/examples/benchmark/FrameworkBenchmarks/fbenchmark.cfg b/tests/examples/benchmark/FrameworkBenchmarks/fbenchmark.cfg index 936d155d..a39d11df 100644 --- a/tests/examples/benchmark/FrameworkBenchmarks/fbenchmark.cfg +++ b/tests/examples/benchmark/FrameworkBenchmarks/fbenchmark.cfg @@ -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 diff --git a/tests/ulib/ok/thread.ok b/tests/ulib/ok/thread.ok index 1127ca3f..559fe670 100644 --- a/tests/ulib/ok/thread.ok +++ b/tests/ulib/ok/thread.ok @@ -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... :) diff --git a/tests/ulib/test_thread.cpp b/tests/ulib/test_thread.cpp index b2250d3d..3ea2364a 100644 --- a/tests/ulib/test_thread.cpp +++ b/tests/ulib/test_thread.cpp @@ -4,42 +4,47 @@ #include +#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"); diff --git a/tests/ulib/thread.test b/tests/ulib/thread.test index 4e2f9b2d..7dca8be7 100755 --- a/tests/ulib/thread.test +++ b/tests/ulib/thread.test @@ -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