diff --git a/qse/configure b/qse/configure index 460c94e7..0d382a07 100755 --- a/qse/configure +++ b/qse/configure @@ -19091,7 +19091,7 @@ $as_echo "#define STDC_HEADERS 1" >>confdefs.h 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 : 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" diff --git a/qse/configure.ac b/qse/configure.ac index a7f58d06..b8af58f9 100644 --- a/qse/configure.ac +++ b/qse/configure.ac @@ -120,7 +120,7 @@ AC_SUBST(LIBM, $LIBM) dnl check header files. 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([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]) diff --git a/qse/include/qse/Types.hpp b/qse/include/qse/Types.hpp index 1ccb7bb6..add6ac21 100644 --- a/qse/include/qse/Types.hpp +++ b/qse/include/qse/Types.hpp @@ -35,7 +35,7 @@ #include #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_EXPLICIT explicit @@ -55,7 +55,7 @@ #elif (__cplusplus >= 199711L) // C++98 - #undef QSE_CPP_CPP11 + #undef QSE_LANG_CPP11 #define QSE_CPP_NOEXCEPT throw() #define QSE_CPP_EXPLICIT diff --git a/qse/include/qse/config.h.in b/qse/include/qse/config.h.in index f097b7ba..20e8f74a 100644 --- a/qse/include/qse/config.h.in +++ b/qse/include/qse/config.h.in @@ -596,6 +596,9 @@ /* Define to 1 if you have the `stat64' function. */ #undef HAVE_STAT64 +/* Define to 1 if you have the header file. */ +#undef HAVE_STDATOMIC_H + /* Define to 1 if you have the header file. */ #undef HAVE_STDDEF_H diff --git a/qse/include/qse/macros.h b/qse/include/qse/macros.h index fc534bc8..1fb5b370 100644 --- a/qse/include/qse/macros.h +++ b/qse/include/qse/macros.h @@ -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 diff --git a/qse/include/qse/si/SpinLock.hpp b/qse/include/qse/si/SpinLock.hpp index 83e2c1e8..93f5bbb2 100644 --- a/qse/include/qse/si/SpinLock.hpp +++ b/qse/include/qse/si/SpinLock.hpp @@ -30,40 +30,73 @@ #include #include -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: in C11 doesn't seem compatible due to lack of + // the keyword _Atomic in C++11 +# include +#endif +QSE_BEGIN_NAMESPACE(QSE) class SpinLock { public: + SpinLock(): flag(0) {} + 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); + #elif defined(QSE_LANG_CPP11) + return !this->flag.test_and_set(); + #else + # error UNSUPPORTED + #endif } void lock () { - //while (!this->tryLock()); - while (__sync_lock_test_and_set(&this->flag, 1)); + #if defined(QSE_HAVE_SYNC_LOCK_TEST_AND_SET) && defined(QSE_HAVE_SYNC_LOCK_RELEASE) + 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 () { + #if defined(QSE_HAVE_SYNC_LOCK_TEST_AND_SET) && defined(QSE_HAVE_SYNC_LOCK_RELEASE) __sync_lock_release (&this->flag); + #elif defined(QSE_LANG_CPP11) + flag.clear (); + #else + # error UNSUPPORTED + #endif } protected: +#if defined(QSE_HAVE_SYNC_LOCK_TEST_AND_SET) && defined(QSE_HAVE_SYNC_LOCK_RELEASE) 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 (); } - ~ScopedSpinLock () + ~ScopedSpinLocker () { this->spl.unlock (); } diff --git a/qse/include/qse/si/Thread.hpp b/qse/include/qse/si/Thread.hpp index f580e380..e558dad2 100644 --- a/qse/include/qse/si/Thread.hpp +++ b/qse/include/qse/si/Thread.hpp @@ -130,7 +130,7 @@ protected: F __lfunc; }; -#if defined(QSE_CPP_CPP11) +#if defined(QSE_LANG_CPP11) #if 0 @@ -219,7 +219,7 @@ protected: }; #endif -#endif // QSE_CPP_CPP11 +#endif // QSE_LANG_CPP11 QSE_END_NAMESPACE(QSE) diff --git a/qse/include/qse/types.h b/qse/include/qse/types.h index 02bd66ae..74ed03f0 100644 --- a/qse/include/qse/types.h +++ b/qse/include/qse/types.h @@ -52,6 +52,11 @@ # error Unsupported operating system #endif +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) +# define QSE_LANG_C11 +#else +# undef QSE_LANG_C11 +#endif #if defined(EMSCRIPTEN) # if defined(QSE_SIZEOF___INT128) @@ -537,12 +542,17 @@ typedef int qse_mcint_t; * #QSE_WCHAR_EOF. */ -#if defined(QSE_WCHAR_PREFER_CHAR16) && defined(__GNUC__) && defined(__CHAR16_TYPE__) && \ - defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) +#if defined(QSE_WCHAR_PREFER_CHAR16) && defined(__GNUC__) && defined(__CHAR16_TYPE__) /* C11 */ + #if defined(__cplusplus) + typedef char16_t qse_wchar_t; + #else + /* i don't want to include */ typedef __CHAR16_TYPE__ qse_wchar_t; + #endif typedef qse_uint16_t qse_wchau_t; - + + #if (QSE_SIZEOF_INT > 2) typedef int qse_wcint_t; #else diff --git a/qse/samples/si/spl02.cpp b/qse/samples/si/spl02.cpp index 56abae90..d7e9aa19 100644 --- a/qse/samples/si/spl02.cpp +++ b/qse/samples/si/spl02.cpp @@ -83,7 +83,7 @@ static int test1 (void) { int localstopreq = 0; -#if defined(QSE_CPP_CPP11) +#if defined(QSE_LANG_CPP11) auto lambda = [](QSE::Thread* thr)->int { int i = 0; @@ -129,7 +129,7 @@ static int test1 (void) QSE::ThreadR thr2; thr2.setStackSize (64000); 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 // as long as the signature matches QSE::Thread::ThreadRoutine. if (thr2.start(lambda, QSE::Thread::SIGNALS_BLOCKED) <= -1) @@ -141,7 +141,7 @@ static int test1 (void) return -1; } -#if defined(QSE_CPP_CPP11) +#if defined(QSE_LANG_CPP11) QSE::ThreadF thr3 (lambda); thr3.setStackSize (64000); thr3.setContext (&localstopreq); @@ -198,7 +198,7 @@ static int test1 (void) { if (thr1.getState() == QSE::Thread::TERMINATED && thr2.getState() == QSE::Thread::TERMINATED && -#if defined(QSE_CPP_CPP11) +#if defined(QSE_LANG_CPP11) thr3.getState() == QSE::Thread::TERMINATED && thr4.getState() == QSE::Thread::TERMINATED && thr5.getState() == QSE::Thread::TERMINATED && @@ -215,7 +215,7 @@ static int test1 (void) thr1.join (); thr2.join (); -#if defined(QSE_CPP_CPP11) +#if defined(QSE_LANG_CPP11) thr3.join (); thr4.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("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("thread4 ended with retcode %d\n"), thr4.getReturnCode()); qse_printf (QSE_T("thread5 ended with retcode %d\n"), thr5.getReturnCode()); diff --git a/qse/samples/si/thr02.cpp b/qse/samples/si/thr02.cpp index 8970dd39..d31d88b2 100644 --- a/qse/samples/si/thr02.cpp +++ b/qse/samples/si/thr02.cpp @@ -83,7 +83,7 @@ static int test1 (void) 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 { int i = 0; @@ -129,7 +129,7 @@ static int test1 (void) QSE::ThreadR thr2; thr2.setStackSize (64000); 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 // as long as the signature matches QSE::Thread::ThreadRoutine. if (thr2.start(lambda, QSE::Thread::SIGNALS_BLOCKED) <= -1) @@ -141,7 +141,7 @@ static int test1 (void) return -1; } -#if defined(QSE_CPP_CPP11) +#if defined(QSE_LANG_CPP11) QSE::ThreadF thr3 (lambda); thr3.setStackSize (64000); thr3.setContext (&localstopreq); @@ -198,7 +198,7 @@ static int test1 (void) { if (thr1.getState() == QSE::Thread::TERMINATED && thr2.getState() == QSE::Thread::TERMINATED && -#if defined(QSE_CPP_CPP11) +#if defined(QSE_LANG_CPP11) thr3.getState() == QSE::Thread::TERMINATED && thr4.getState() == QSE::Thread::TERMINATED && thr5.getState() == QSE::Thread::TERMINATED && @@ -215,7 +215,7 @@ static int test1 (void) thr1.join (); thr2.join (); -#if defined(QSE_CPP_CPP11) +#if defined(QSE_LANG_CPP11) thr3.join (); thr4.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("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("thread4 ended with retcode %d\n"), thr4.getReturnCode()); qse_printf (QSE_T("thread5 ended with retcode %d\n"), thr5.getReturnCode());