added some checks for compiler builtins.

enhanced SpinLock code
This commit is contained in:
hyung-hwan 2018-01-30 08:33:45 +00:00
parent 3a9e278f0b
commit d0bb9ae911
10 changed files with 204 additions and 27 deletions

2
qse/configure vendored
View File

@ -19091,7 +19091,7 @@ $as_echo "#define STDC_HEADERS 1" >>confdefs.h
fi fi
for ac_header in stddef.h wchar.h wctype.h errno.h signal.h fcntl.h dirent.h for ac_header in stddef.h wchar.h wctype.h errno.h signal.h fcntl.h dirent.h stdatomic.h
do : do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default"

View File

@ -120,7 +120,7 @@ AC_SUBST(LIBM, $LIBM)
dnl check header files. dnl check header files.
AC_HEADER_STDC AC_HEADER_STDC
AC_CHECK_HEADERS([stddef.h wchar.h wctype.h errno.h signal.h fcntl.h dirent.h]) AC_CHECK_HEADERS([stddef.h wchar.h wctype.h errno.h signal.h fcntl.h dirent.h stdatomic.h])
AC_CHECK_HEADERS([time.h sys/time.h utime.h spawn.h execinfo.h ucontext.h]) AC_CHECK_HEADERS([time.h sys/time.h utime.h spawn.h execinfo.h ucontext.h])
AC_CHECK_HEADERS([sys/resource.h sys/wait.h sys/syscall.h sys/ioctl.h]) AC_CHECK_HEADERS([sys/resource.h sys/wait.h sys/syscall.h sys/ioctl.h])
AC_CHECK_HEADERS([sys/sendfile.h sys/epoll.h sys/event.h sys/poll.h poll.h]) AC_CHECK_HEADERS([sys/sendfile.h sys/epoll.h sys/event.h sys/poll.h poll.h])

View File

@ -35,7 +35,7 @@
#include <qse/macros.h> #include <qse/macros.h>
#if (__cplusplus >= 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1900) // C++11 or later #if (__cplusplus >= 201103L) || (defined(_MSC_VER) && _MSC_VER >= 1900) // C++11 or later
#define QSE_CPP_CPP11 1 #define QSE_LANG_CPP11 1
#define QSE_CPP_NOEXCEPT noexcept(true) #define QSE_CPP_NOEXCEPT noexcept(true)
#define QSE_CPP_EXPLICIT explicit #define QSE_CPP_EXPLICIT explicit
@ -55,7 +55,7 @@
#elif (__cplusplus >= 199711L) // C++98 #elif (__cplusplus >= 199711L) // C++98
#undef QSE_CPP_CPP11 #undef QSE_LANG_CPP11
#define QSE_CPP_NOEXCEPT throw() #define QSE_CPP_NOEXCEPT throw()
#define QSE_CPP_EXPLICIT #define QSE_CPP_EXPLICIT

View File

@ -596,6 +596,9 @@
/* Define to 1 if you have the `stat64' function. */ /* Define to 1 if you have the `stat64' function. */
#undef HAVE_STAT64 #undef HAVE_STAT64
/* Define to 1 if you have the <stdatomic.h> header file. */
#undef HAVE_STDATOMIC_H
/* Define to 1 if you have the <stddef.h> header file. */ /* Define to 1 if you have the <stddef.h> header file. */
#undef HAVE_STDDEF_H #undef HAVE_STDDEF_H

View File

@ -508,6 +508,137 @@ static inline qse_uint32_t QSE_ROTR32 (qse_uint32_t v, int i)
/* =========================================================================
* COMPILER FEATURE TEST MACROS
* =========================================================================*/
#if !defined(__has_builtin) && defined(_INTELC32_)
/* intel c code builder 1.0 ended up with an error without this override */
#define __has_builtin(x) 0
#endif
/*
#if !defined(__is_identifier)
#define __is_identifier(x) 0
#endif
#if !defined(__has_attribute)
#define __has_attribute(x) 0
#endif
*/
#if defined(__has_builtin)
#if __has_builtin(__builtin_ctz)
#define QSE_HAVE_BUILTIN_CTZ
#endif
#if __has_builtin(__builtin_ctzl)
#define QSE_HAVE_BUILTIN_CTZL
#endif
#if __has_builtin(__builtin_ctzll)
#define QSE_HAVE_BUILTIN_CTZLL
#endif
#if __has_builtin(__builtin_uadd_overflow)
#define QSE_HAVE_BUILTIN_UADD_OVERFLOW
#endif
#if __has_builtin(__builtin_uaddl_overflow)
#define QSE_HAVE_BUILTIN_UADDL_OVERFLOW
#endif
#if __has_builtin(__builtin_uaddll_overflow)
#define QSE_HAVE_BUILTIN_UADDLL_OVERFLOW
#endif
#if __has_builtin(__builtin_umul_overflow)
#define QSE_HAVE_BUILTIN_UMUL_OVERFLOW
#endif
#if __has_builtin(__builtin_umull_overflow)
#define QSE_HAVE_BUILTIN_UMULL_OVERFLOW
#endif
#if __has_builtin(__builtin_umulll_overflow)
#define QSE_HAVE_BUILTIN_UMULLL_OVERFLOW
#endif
#if __has_builtin(__builtin_sadd_overflow)
#define QSE_HAVE_BUILTIN_SADD_OVERFLOW
#endif
#if __has_builtin(__builtin_saddl_overflow)
#define QSE_HAVE_BUILTIN_SADDL_OVERFLOW
#endif
#if __has_builtin(__builtin_saddll_overflow)
#define QSE_HAVE_BUILTIN_SADDLL_OVERFLOW
#endif
#if __has_builtin(__builtin_smul_overflow)
#define QSE_HAVE_BUILTIN_SMUL_OVERFLOW
#endif
#if __has_builtin(__builtin_smull_overflow)
#define QSE_HAVE_BUILTIN_SMULL_OVERFLOW
#endif
#if __has_builtin(__builtin_smulll_overflow)
#define QSE_HAVE_BUILTIN_SMULLL_OVERFLOW
#endif
#if __has_builtin(__builtin_expect)
#define QSE_HAVE_BUILTIN_EXPECT
#endif
#if __has_builtin(__sync_lock_test_and_set)
#define QSE_HAVE_SYNC_LOCK_TEST_AND_SET
#endif
#if __has_builtin(__sync_lock_release)
#define QSE_HAVE_SYNC_LOCK_RELEASE
#endif
#if __has_builtin(__sync_synchronize)
#define QSE_HAVE_SYNC_SYNCHRONIZE
#endif
#if __has_builtin(__sync_bool_compare_and_swap)
#define QSE_HAVE_SYNC_BOOL_COMPARE_AND_SWAP
#endif
#if __has_builtin(__sync_val_compare_and_swap)
#define QSE_HAVE_SYNC_VAL_COMPARE_AND_SWAP
#endif
#elif defined(__GNUC__) && defined(__GNUC_MINOR__)
#if (__GNUC__ >= 4)
#define QSE_HAVE_SYNC_LOCK_TEST_AND_SET
#define QSE_HAVE_SYNC_LOCK_RELEASE
#define QSE_HAVE_SYNC_SYNCHRONIZE
#define QSE_HAVE_SYNC_BOOL_COMPARE_AND_SWAP
#define QSE_HAVE_SYNC_VAL_COMPARE_AND_SWAP
#endif
#if (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
#define QSE_HAVE_BUILTIN_CTZ
#define QSE_HAVE_BUILTIN_EXPECT
#endif
#if (__GNUC__ >= 5)
#define QSE_HAVE_BUILTIN_UADD_OVERFLOW
#define QSE_HAVE_BUILTIN_UADDL_OVERFLOW
#define QSE_HAVE_BUILTIN_UADDLL_OVERFLOW
#define QSE_HAVE_BUILTIN_UMUL_OVERFLOW
#define QSE_HAVE_BUILTIN_UMULL_OVERFLOW
#define QSE_HAVE_BUILTIN_UMULLL_OVERFLOW
#define QSE_HAVE_BUILTIN_SADD_OVERFLOW
#define QSE_HAVE_BUILTIN_SADDL_OVERFLOW
#define QSE_HAVE_BUILTIN_SADDLL_OVERFLOW
#define QSE_HAVE_BUILTIN_SMUL_OVERFLOW
#define QSE_HAVE_BUILTIN_SMULL_OVERFLOW
#define QSE_HAVE_BUILTIN_SMULLL_OVERFLOW
#endif
#endif
#if defined(QSE_HAVE_BUILTIN_EXPECT)
# define QSE_LIKELY(x) (__builtin_expect(!!(x),1))
# define QSE_UNLIKELY(x) (__builtin_expect(!!(x),0))
#else
# define QSE_LIKELY(x) (x)
# define QSE_UNLIKELY(x) (x)
#endif
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
* C++ NAMESPACE * C++ NAMESPACE

View File

@ -30,40 +30,73 @@
#include <qse/Types.hpp> #include <qse/Types.hpp>
#include <qse/Uncopyable.hpp> #include <qse/Uncopyable.hpp>
QSE_BEGIN_NAMESPACE(QSE) #if defined(QSE_HAVE_SYNC_LOCK_TEST_AND_SET) && defined(QSE_HAVE_SYNC_LOCK_RELEASE)
// don't include anything
#elif defined(QSE_LANG_CPP11)
// NOTE: <stdatomic.h> in C11 doesn't seem compatible due to lack of
// the keyword _Atomic in C++11
# include <atomic>
#endif
QSE_BEGIN_NAMESPACE(QSE)
class SpinLock class SpinLock
{ {
public: public:
SpinLock(): flag(0) {}
bool tryock() bool tryock()
{ {
#if defined(QSE_HAVE_SYNC_LOCK_TEST_AND_SET) && defined(QSE_HAVE_SYNC_LOCK_RELEASE)
return !__sync_lock_test_and_set(&this->flag, 1); return !__sync_lock_test_and_set(&this->flag, 1);
#elif defined(QSE_LANG_CPP11)
return !this->flag.test_and_set();
#else
# error UNSUPPORTED
#endif
} }
void lock () void lock ()
{ {
//while (!this->tryLock()); #if defined(QSE_HAVE_SYNC_LOCK_TEST_AND_SET) && defined(QSE_HAVE_SYNC_LOCK_RELEASE)
while (__sync_lock_test_and_set(&this->flag, 1)); while (__sync_lock_test_and_set(&this->flag, 1)) { /* do nothing special */ }
#elif defined(QSE_LANG_CPP11)
while (flag.test_and_set()) { /* do nothing sepcial */ }
#else
# error UNSUPPORTED
#endif
} }
void unlock () void unlock ()
{ {
#if defined(QSE_HAVE_SYNC_LOCK_TEST_AND_SET) && defined(QSE_HAVE_SYNC_LOCK_RELEASE)
__sync_lock_release (&this->flag); __sync_lock_release (&this->flag);
#elif defined(QSE_LANG_CPP11)
flag.clear ();
#else
# error UNSUPPORTED
#endif
} }
protected: protected:
#if defined(QSE_HAVE_SYNC_LOCK_TEST_AND_SET) && defined(QSE_HAVE_SYNC_LOCK_RELEASE)
volatile int flag; volatile int flag;
#elif defined(QSE_LANG_CPP11)
std::atomic_flag flag;
#else
# error UNSUPPORTED;
#endif
}; };
class ScopedSpinLock: public Uncopyable class ScopedSpinLocker: public Uncopyable
{ {
ScopedSpinLock (SpinLock& spl): spl(spl) public:
ScopedSpinLocker (SpinLock& spl): spl(spl)
{ {
this->spl.lock (); this->spl.lock ();
} }
~ScopedSpinLock () ~ScopedSpinLocker ()
{ {
this->spl.unlock (); this->spl.unlock ();
} }

View File

@ -130,7 +130,7 @@ protected:
F __lfunc; F __lfunc;
}; };
#if defined(QSE_CPP_CPP11) #if defined(QSE_LANG_CPP11)
#if 0 #if 0
@ -219,7 +219,7 @@ protected:
}; };
#endif #endif
#endif // QSE_CPP_CPP11 #endif // QSE_LANG_CPP11
QSE_END_NAMESPACE(QSE) QSE_END_NAMESPACE(QSE)

View File

@ -52,6 +52,11 @@
# error Unsupported operating system # error Unsupported operating system
#endif #endif
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
# define QSE_LANG_C11
#else
# undef QSE_LANG_C11
#endif
#if defined(EMSCRIPTEN) #if defined(EMSCRIPTEN)
# if defined(QSE_SIZEOF___INT128) # if defined(QSE_SIZEOF___INT128)
@ -537,12 +542,17 @@ typedef int qse_mcint_t;
* #QSE_WCHAR_EOF. * #QSE_WCHAR_EOF.
*/ */
#if defined(QSE_WCHAR_PREFER_CHAR16) && defined(__GNUC__) && defined(__CHAR16_TYPE__) && \ #if defined(QSE_WCHAR_PREFER_CHAR16) && defined(__GNUC__) && defined(__CHAR16_TYPE__)
defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
/* C11 */ /* C11 */
#if defined(__cplusplus)
typedef char16_t qse_wchar_t;
#else
/* i don't want to include <uchar.h> */
typedef __CHAR16_TYPE__ qse_wchar_t; typedef __CHAR16_TYPE__ qse_wchar_t;
#endif
typedef qse_uint16_t qse_wchau_t; typedef qse_uint16_t qse_wchau_t;
#if (QSE_SIZEOF_INT > 2) #if (QSE_SIZEOF_INT > 2)
typedef int qse_wcint_t; typedef int qse_wcint_t;
#else #else

View File

@ -83,7 +83,7 @@ static int test1 (void)
{ {
int localstopreq = 0; int localstopreq = 0;
#if defined(QSE_CPP_CPP11) #if defined(QSE_LANG_CPP11)
auto lambda = [](QSE::Thread* thr)->int auto lambda = [](QSE::Thread* thr)->int
{ {
int i = 0; int i = 0;
@ -129,7 +129,7 @@ static int test1 (void)
QSE::ThreadR thr2; QSE::ThreadR thr2;
thr2.setStackSize (64000); thr2.setStackSize (64000);
thr2.setContext (&localstopreq); thr2.setContext (&localstopreq);
#if defined(QSE_CPP_CPP11) #if defined(QSE_LANG_CPP11)
// the lambda expression with no capture can be passed as a function pointer // the lambda expression with no capture can be passed as a function pointer
// as long as the signature matches QSE::Thread::ThreadRoutine. // as long as the signature matches QSE::Thread::ThreadRoutine.
if (thr2.start(lambda, QSE::Thread::SIGNALS_BLOCKED) <= -1) if (thr2.start(lambda, QSE::Thread::SIGNALS_BLOCKED) <= -1)
@ -141,7 +141,7 @@ static int test1 (void)
return -1; return -1;
} }
#if defined(QSE_CPP_CPP11) #if defined(QSE_LANG_CPP11)
QSE::ThreadF<decltype(lambda)> thr3 (lambda); QSE::ThreadF<decltype(lambda)> thr3 (lambda);
thr3.setStackSize (64000); thr3.setStackSize (64000);
thr3.setContext (&localstopreq); thr3.setContext (&localstopreq);
@ -198,7 +198,7 @@ static int test1 (void)
{ {
if (thr1.getState() == QSE::Thread::TERMINATED && if (thr1.getState() == QSE::Thread::TERMINATED &&
thr2.getState() == QSE::Thread::TERMINATED && thr2.getState() == QSE::Thread::TERMINATED &&
#if defined(QSE_CPP_CPP11) #if defined(QSE_LANG_CPP11)
thr3.getState() == QSE::Thread::TERMINATED && thr3.getState() == QSE::Thread::TERMINATED &&
thr4.getState() == QSE::Thread::TERMINATED && thr4.getState() == QSE::Thread::TERMINATED &&
thr5.getState() == QSE::Thread::TERMINATED && thr5.getState() == QSE::Thread::TERMINATED &&
@ -215,7 +215,7 @@ static int test1 (void)
thr1.join (); thr1.join ();
thr2.join (); thr2.join ();
#if defined(QSE_CPP_CPP11) #if defined(QSE_LANG_CPP11)
thr3.join (); thr3.join ();
thr4.join (); thr4.join ();
thr5.join (); thr5.join ();
@ -224,7 +224,7 @@ static int test1 (void)
qse_printf (QSE_T("thread1 ended with retcode %d\n"), thr1.getReturnCode()); qse_printf (QSE_T("thread1 ended with retcode %d\n"), thr1.getReturnCode());
qse_printf (QSE_T("thread2 ended with retcode %d\n"), thr2.getReturnCode()); qse_printf (QSE_T("thread2 ended with retcode %d\n"), thr2.getReturnCode());
#if defined(QSE_CPP_CPP11) #if defined(QSE_LANG_CPP11)
qse_printf (QSE_T("thread3 ended with retcode %d\n"), thr3.getReturnCode()); qse_printf (QSE_T("thread3 ended with retcode %d\n"), thr3.getReturnCode());
qse_printf (QSE_T("thread4 ended with retcode %d\n"), thr4.getReturnCode()); qse_printf (QSE_T("thread4 ended with retcode %d\n"), thr4.getReturnCode());
qse_printf (QSE_T("thread5 ended with retcode %d\n"), thr5.getReturnCode()); qse_printf (QSE_T("thread5 ended with retcode %d\n"), thr5.getReturnCode());

View File

@ -83,7 +83,7 @@ static int test1 (void)
g_prmtx = qse_mtx_open (QSE_MMGR_GETDFL(), 0); g_prmtx = qse_mtx_open (QSE_MMGR_GETDFL(), 0);
#if defined(QSE_CPP_CPP11) #if defined(QSE_LANG_CPP11)
auto lambda = [](QSE::Thread* thr)->int auto lambda = [](QSE::Thread* thr)->int
{ {
int i = 0; int i = 0;
@ -129,7 +129,7 @@ static int test1 (void)
QSE::ThreadR thr2; QSE::ThreadR thr2;
thr2.setStackSize (64000); thr2.setStackSize (64000);
thr2.setContext (&localstopreq); thr2.setContext (&localstopreq);
#if defined(QSE_CPP_CPP11) #if defined(QSE_LANG_CPP11)
// the lambda expression with no capture can be passed as a function pointer // the lambda expression with no capture can be passed as a function pointer
// as long as the signature matches QSE::Thread::ThreadRoutine. // as long as the signature matches QSE::Thread::ThreadRoutine.
if (thr2.start(lambda, QSE::Thread::SIGNALS_BLOCKED) <= -1) if (thr2.start(lambda, QSE::Thread::SIGNALS_BLOCKED) <= -1)
@ -141,7 +141,7 @@ static int test1 (void)
return -1; return -1;
} }
#if defined(QSE_CPP_CPP11) #if defined(QSE_LANG_CPP11)
QSE::ThreadF<decltype(lambda)> thr3 (lambda); QSE::ThreadF<decltype(lambda)> thr3 (lambda);
thr3.setStackSize (64000); thr3.setStackSize (64000);
thr3.setContext (&localstopreq); thr3.setContext (&localstopreq);
@ -198,7 +198,7 @@ static int test1 (void)
{ {
if (thr1.getState() == QSE::Thread::TERMINATED && if (thr1.getState() == QSE::Thread::TERMINATED &&
thr2.getState() == QSE::Thread::TERMINATED && thr2.getState() == QSE::Thread::TERMINATED &&
#if defined(QSE_CPP_CPP11) #if defined(QSE_LANG_CPP11)
thr3.getState() == QSE::Thread::TERMINATED && thr3.getState() == QSE::Thread::TERMINATED &&
thr4.getState() == QSE::Thread::TERMINATED && thr4.getState() == QSE::Thread::TERMINATED &&
thr5.getState() == QSE::Thread::TERMINATED && thr5.getState() == QSE::Thread::TERMINATED &&
@ -215,7 +215,7 @@ static int test1 (void)
thr1.join (); thr1.join ();
thr2.join (); thr2.join ();
#if defined(QSE_CPP_CPP11) #if defined(QSE_LANG_CPP11)
thr3.join (); thr3.join ();
thr4.join (); thr4.join ();
thr5.join (); thr5.join ();
@ -224,7 +224,7 @@ static int test1 (void)
qse_printf (QSE_T("thread1 ended with retcode %d\n"), thr1.getReturnCode()); qse_printf (QSE_T("thread1 ended with retcode %d\n"), thr1.getReturnCode());
qse_printf (QSE_T("thread2 ended with retcode %d\n"), thr2.getReturnCode()); qse_printf (QSE_T("thread2 ended with retcode %d\n"), thr2.getReturnCode());
#if defined(QSE_CPP_CPP11) #if defined(QSE_LANG_CPP11)
qse_printf (QSE_T("thread3 ended with retcode %d\n"), thr3.getReturnCode()); qse_printf (QSE_T("thread3 ended with retcode %d\n"), thr3.getReturnCode());
qse_printf (QSE_T("thread4 ended with retcode %d\n"), thr4.getReturnCode()); qse_printf (QSE_T("thread4 ended with retcode %d\n"), thr4.getReturnCode());
qse_printf (QSE_T("thread5 ended with retcode %d\n"), thr5.getReturnCode()); qse_printf (QSE_T("thread5 ended with retcode %d\n"), thr5.getReturnCode());