From be51ae8e61faf5f1cd622fc4be69a09c34578d77 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Wed, 31 Jan 2018 10:34:38 +0000 Subject: [PATCH] added spl.h changed SpinLock.hpp to use spl.h --- qse/include/qse/si/Makefile.am | 1 + qse/include/qse/si/Makefile.in | 7 +- qse/include/qse/si/SpinLock.hpp | 29 ++++-- qse/include/qse/si/spl.h | 147 +++++++++++++++++++++++++++ qse/samples/si/Makefile.am | 4 +- qse/samples/si/Makefile.in | 24 +++-- qse/samples/si/spl01.c | 174 ++++++++++++++++++++++++++++++++ 7 files changed, 366 insertions(+), 20 deletions(-) create mode 100644 qse/include/qse/si/spl.h create mode 100644 qse/samples/si/spl01.c diff --git a/qse/include/qse/si/Makefile.am b/qse/include/qse/si/Makefile.am index 008b1d3f..e773d4b2 100644 --- a/qse/include/qse/si/Makefile.am +++ b/qse/include/qse/si/Makefile.am @@ -21,6 +21,7 @@ pkginclude_HEADERS = \ sck.h \ sinfo.h \ sio.h \ + spl.h \ task.h \ thr.h \ tio.h diff --git a/qse/include/qse/si/Makefile.in b/qse/include/qse/si/Makefile.in index 97496a26..d97d3339 100644 --- a/qse/include/qse/si/Makefile.in +++ b/qse/include/qse/si/Makefile.in @@ -133,8 +133,8 @@ am__can_run_installinfo = \ esac am__pkginclude_HEADERS_DIST = aio.h aio-pro.h aio-sck.h cnd.h dir.h \ fio.h fs.h glob.h intr.h log.h mtx.h mux.h nwad.h nwif.h \ - nwio.h pio.h rwl.h sck.h sinfo.h sio.h task.h thr.h tio.h \ - AppRoot.hpp SocketAddress.hpp Socket.hpp SpinLock.hpp \ + nwio.h pio.h rwl.h sck.h sinfo.h sio.h spl.h task.h thr.h \ + tio.h AppRoot.hpp SocketAddress.hpp Socket.hpp SpinLock.hpp \ Thread.hpp am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ @@ -369,7 +369,8 @@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ pkginclude_HEADERS = aio.h aio-pro.h aio-sck.h cnd.h dir.h fio.h fs.h \ glob.h intr.h log.h mtx.h mux.h nwad.h nwif.h nwio.h pio.h \ - rwl.h sck.h sinfo.h sio.h task.h thr.h tio.h $(am__append_1) + rwl.h sck.h sinfo.h sio.h spl.h task.h thr.h tio.h \ + $(am__append_1) all: all-am .SUFFIXES: diff --git a/qse/include/qse/si/SpinLock.hpp b/qse/include/qse/si/SpinLock.hpp index 3141512d..bb7ac6c2 100644 --- a/qse/include/qse/si/SpinLock.hpp +++ b/qse/include/qse/si/SpinLock.hpp @@ -30,8 +30,13 @@ #include #include -#if defined(QSE_HAVE_SYNC_LOCK_TEST_AND_SET) && defined(QSE_HAVE_SYNC_LOCK_RELEASE) - // don't include anything +#undef QSE_SPL_NO_UNSUPPORTED_ERROR +#define QSE_SPL_NO_UNSUPPORTED_ERROR +#include +#undef QSE_SPL_NO_UNSUPPORTED_ERROR + +#if defined(QSE_SUPPORT_SPL) + // don't include anything else #elif defined(QSE_LANG_CPP11) // NOTE: in C11 doesn't seem compatible due to lack of // the keyword _Atomic in C++11 @@ -43,12 +48,16 @@ QSE_BEGIN_NAMESPACE(QSE) class SpinLock { public: +#if defined(QSE_SUPPORT_SPL) + SpinLock() QSE_CPP_NOEXCEPT: flag(QSE_SPL_INIT) {} +#else SpinLock() QSE_CPP_NOEXCEPT: flag(0) {} +#endif bool tryock() QSE_CPP_NOEXCEPT { - #if defined(QSE_HAVE_SYNC_LOCK_TEST_AND_SET) && defined(QSE_HAVE_SYNC_LOCK_RELEASE) - return !__sync_lock_test_and_set(&this->flag, 1); + #if defined(QSE_SUPPORT_SPL) + return !qse_spl_trylock(&this->flag); #elif defined(QSE_LANG_CPP11) return !this->flag.test_and_set(); #else @@ -58,8 +67,8 @@ public: void lock () QSE_CPP_NOEXCEPT { - #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 */ } + #if defined(QSE_SUPPORT_SPL) + qse_spl_lock (&this->flag); #elif defined(QSE_LANG_CPP11) while (flag.test_and_set()) { /* do nothing sepcial */ } #else @@ -69,8 +78,8 @@ public: void unlock () QSE_CPP_NOEXCEPT { - #if defined(QSE_HAVE_SYNC_LOCK_TEST_AND_SET) && defined(QSE_HAVE_SYNC_LOCK_RELEASE) - __sync_lock_release (&this->flag); + #if defined(QSE_SUPPORT_SPL) + qse_spl_unlock (&this->flag); #elif defined(QSE_LANG_CPP11) flag.clear (); #else @@ -79,8 +88,8 @@ public: } protected: -#if defined(QSE_HAVE_SYNC_LOCK_TEST_AND_SET) && defined(QSE_HAVE_SYNC_LOCK_RELEASE) - volatile int flag; +#if defined(QSE_SUPPORT_SPL) + qse_spl_t flag; #elif defined(QSE_LANG_CPP11) std::atomic_flag flag; #else diff --git a/qse/include/qse/si/spl.h b/qse/include/qse/si/spl.h new file mode 100644 index 00000000..0e762da3 --- /dev/null +++ b/qse/include/qse/si/spl.h @@ -0,0 +1,147 @@ +/* + * $Id$ + * + Copyright (c) 2006-2014 Chung, Hyung-Hwan. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EQSERESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _QSE_SI_SPL_H_ +#define _QSE_SI_SPL_H_ + +#include +#include + +#define QSE_SUPPORT_SPL + +typedef volatile qse_uint32_t qse_spl_t; + +#define QSE_SPL_INIT (0) + +#if defined(QSE_HAVE_INLINE) + static QSE_INLINE void qse_spl_init (qse_spl_t* spl) { *spl = QSE_SPL_INIT; } +#else +# define qse_spl_init(spl) ((*(spl)) = QSE_SPL_INIT) +#endif + +#if defined(QSE_HAVE_SYNC_LOCK_TEST_AND_SET) && defined(QSE_HAVE_SYNC_LOCK_RELEASE) + /* ======================================================================= + * MODERN COMPILERS WITH BUILTIN ATOMICS + * ======================================================================= */ + +#if defined(QSE_HAVE_INLINE) + static QSE_INLINE int qse_spl_trylock (qse_spl_t* spl) { return !__sync_lock_test_and_set(spl, 1); } + static QSE_INLINE void qse_spl_lock (qse_spl_t* spl) { do {} while(__sync_lock_test_and_set(spl, 1)); } + static QSE_INLINE void qse_spl_unlock (qse_spl_t* spl) { __sync_lock_release(spl); } +#else +# define qse_spl_trylock(spl) (!__sync_lock_test_and_set(spl, 1)) +# define qse_spl_lock(spl) do {} while(__sync_lock_test_and_set(spl, 1)) +# define qse_spl_unlock(spl) (__sync_lock_release(spl)) +#endif + +#elif defined(_SCO_DS) +/* ======================================================================= + * SCO DEVELOPEMENT SYSTEM + * + * NOTE: when the asm macros were indented, the compiler/linker ended up + * with undefined symbols. never indent qse_spl_xxx macros. + * ======================================================================= */ +asm int qse_spl_trylock (qse_spl_t* spl) +{ +%reg spl + movl $1, %eax + xchgl (spl), %eax + xorl $1, %eax / return zero on failure, non-zero on success + +%mem spl + movl spl, %ecx + movl $1, %eax + xchgl (%ecx), %eax + xorl $1, %eax / return zero on failure, non-zero on success +} + +#if 0 +/* i can't figure out how to make jump labels unique when there are + * multiple occurrences of qse_spl_lock(). so let me just use the while loop + * instead. */ +asm void qse_spl_lock (qse_spl_t* spl) +{ +%reg spl +.lock_set_loop: + movl $1, %eax + xchgl (spl), %eax + testl %eax, %eax / set ZF to 1 if eax is zero, 0 if eax is non-zero + jne .lock_set_loop / if ZF is 0(eax is non-zero), loop around + +%mem spl +.lock_set_loop: + movl spl, %ecx + movl $1, %eax + xchgl (%ecx), %eax + testl %eax, %eax / set ZF to 1 if eax is zero, 0 if eax is non-zero + jne .lock_set_loop / if ZF is 0(eax is non-zero), loop around +} +#else +#define qse_spl_lock(x) do {} while(!spl_trylock(x)) +#endif + +#if 0 +asm void qse_spl_unlock (moo_uint8_t* spl) +{ +%reg spl + movl $0, %eax + xchgl (spl), %eax + +%mem spl + movl spl, %ecx + movl $0, %eax + xchgl (%ecx), %eax +} +#else +asm void qse_spl_unlock (qse_spl_t* spl) +{ + /* don't need xchg as movl on an aligned data is atomic */ + /* mfence is 0F AE F0 */ +%reg spl + .byte 0x0F + .byte 0xAE + .byte 0xF0 + movl $0, (spl) + +%mem spl + .byte 0x0F + .byte 0xAE + .byte 0xF0 + movl spl, %ecx + movl $0, (%ecx) +} +#endif + +#elif defined(QSE_SPL_NO_UNSUPPORTED_ERROR) + /* don't raise the compile time error */ + #undef QSE_SUPPORT_SPL +#else + #undef QSE_SUPPORT_SPL +# error UNSUPPORTED +#endif + + +#endif diff --git a/qse/samples/si/Makefile.am b/qse/samples/si/Makefile.am index 64226f6e..cde3ef31 100644 --- a/qse/samples/si/Makefile.am +++ b/qse/samples/si/Makefile.am @@ -23,8 +23,9 @@ bin_PROGRAMS = \ sio01 \ sio02 \ sio03 \ + spl01 \ task01 \ - thr01 + thr01 AM_LDFLAGS = -L../../lib/si -L../../lib/cmn AM_CFLAGS = $(PTHREAD_CFLAGS) @@ -53,6 +54,7 @@ rwl01_SOURCES = rwl01.c sio01_SOURCES = sio01.c sio02_SOURCES = sio02.c sio03_SOURCES = sio03.c +spl01_SOURCES = spl01.c task01_SOURCES = task01.c thr01_SOURCES = thr01.c diff --git a/qse/samples/si/Makefile.in b/qse/samples/si/Makefile.in index 5159193f..59113925 100644 --- a/qse/samples/si/Makefile.in +++ b/qse/samples/si/Makefile.in @@ -92,8 +92,8 @@ bin_PROGRAMS = aio01$(EXEEXT) dir01$(EXEEXT) fio01$(EXEEXT) \ fio02$(EXEEXT) fs01$(EXEEXT) fs02$(EXEEXT) fs03$(EXEEXT) \ glob01$(EXEEXT) log01$(EXEEXT) nwad01$(EXEEXT) nwif01$(EXEEXT) \ nwif02$(EXEEXT) pio01$(EXEEXT) rwl01$(EXEEXT) sio01$(EXEEXT) \ - sio02$(EXEEXT) sio03$(EXEEXT) task01$(EXEEXT) thr01$(EXEEXT) \ - $(am__EXEEXT_1) + sio02$(EXEEXT) sio03$(EXEEXT) spl01$(EXEEXT) task01$(EXEEXT) \ + thr01$(EXEEXT) $(am__EXEEXT_1) @WCHAR_TRUE@@WIN32_TRUE@am__append_1 = $(UNICOWS_LIBS) @ENABLE_CXX_TRUE@am__append_2 = thr02 spl02 subdir = samples/si @@ -190,6 +190,10 @@ am_sio03_OBJECTS = sio03.$(OBJEXT) sio03_OBJECTS = $(am_sio03_OBJECTS) sio03_LDADD = $(LDADD) sio03_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) +am_spl01_OBJECTS = spl01.$(OBJEXT) +spl01_OBJECTS = $(am_spl01_OBJECTS) +spl01_LDADD = $(LDADD) +spl01_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) am__spl02_SOURCES_DIST = spl02.cpp @ENABLE_CXX_TRUE@am_spl02_OBJECTS = spl02.$(OBJEXT) spl02_OBJECTS = $(am_spl02_OBJECTS) @@ -266,15 +270,17 @@ SOURCES = $(aio01_SOURCES) $(dir01_SOURCES) $(fio01_SOURCES) \ $(fs03_SOURCES) $(glob01_SOURCES) $(log01_SOURCES) \ $(nwad01_SOURCES) $(nwif01_SOURCES) $(nwif02_SOURCES) \ $(pio01_SOURCES) $(rwl01_SOURCES) $(sio01_SOURCES) \ - $(sio02_SOURCES) $(sio03_SOURCES) $(spl02_SOURCES) \ - $(task01_SOURCES) $(thr01_SOURCES) $(thr02_SOURCES) + $(sio02_SOURCES) $(sio03_SOURCES) $(spl01_SOURCES) \ + $(spl02_SOURCES) $(task01_SOURCES) $(thr01_SOURCES) \ + $(thr02_SOURCES) DIST_SOURCES = $(aio01_SOURCES) $(dir01_SOURCES) $(fio01_SOURCES) \ $(fio02_SOURCES) $(fs01_SOURCES) $(fs02_SOURCES) \ $(fs03_SOURCES) $(glob01_SOURCES) $(log01_SOURCES) \ $(nwad01_SOURCES) $(nwif01_SOURCES) $(nwif02_SOURCES) \ $(pio01_SOURCES) $(rwl01_SOURCES) $(sio01_SOURCES) \ - $(sio02_SOURCES) $(sio03_SOURCES) $(am__spl02_SOURCES_DIST) \ - $(task01_SOURCES) $(thr01_SOURCES) $(am__thr02_SOURCES_DIST) + $(sio02_SOURCES) $(sio03_SOURCES) $(spl01_SOURCES) \ + $(am__spl02_SOURCES_DIST) $(task01_SOURCES) $(thr01_SOURCES) \ + $(am__thr02_SOURCES_DIST) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ @@ -507,6 +513,7 @@ rwl01_SOURCES = rwl01.c sio01_SOURCES = sio01.c sio02_SOURCES = sio02.c sio03_SOURCES = sio03.c +spl01_SOURCES = spl01.c task01_SOURCES = task01.c thr01_SOURCES = thr01.c @ENABLE_CXX_TRUE@CXXLIB = -lqsesixx -lqsecmnxx @@ -665,6 +672,10 @@ sio03$(EXEEXT): $(sio03_OBJECTS) $(sio03_DEPENDENCIES) $(EXTRA_sio03_DEPENDENCIE @rm -f sio03$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sio03_OBJECTS) $(sio03_LDADD) $(LIBS) +spl01$(EXEEXT): $(spl01_OBJECTS) $(spl01_DEPENDENCIES) $(EXTRA_spl01_DEPENDENCIES) + @rm -f spl01$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(spl01_OBJECTS) $(spl01_LDADD) $(LIBS) + spl02$(EXEEXT): $(spl02_OBJECTS) $(spl02_DEPENDENCIES) $(EXTRA_spl02_DEPENDENCIES) @rm -f spl02$(EXEEXT) $(AM_V_CXXLD)$(CXXLINK) $(spl02_OBJECTS) $(spl02_LDADD) $(LIBS) @@ -704,6 +715,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sio01.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sio02.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sio03.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spl01.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spl02.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/task01.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thr01.Po@am__quote@ diff --git a/qse/samples/si/spl01.c b/qse/samples/si/spl01.c new file mode 100644 index 00000000..2e243018 --- /dev/null +++ b/qse/samples/si/spl01.c @@ -0,0 +1,174 @@ +#include +#include +#include +#include + + +#include +#if defined(_WIN32) +# include +#endif + +#include +#include +#include + +static int g_stopreq = 0; + +struct thr_xtn_t +{ + int stopreq; + qse_char_t name[32]; + qse_spl_t* spl; +}; +typedef struct thr_xtn_t thr_xtn_t; + +static int thr_func (qse_thr_t* thr, void* ctx) +{ + int i = 0; + thr_xtn_t* xtn = qse_thr_getxtn(thr); + + while (!xtn->stopreq) + { + qse_spl_lock (xtn->spl); + qse_printf (QSE_T("%s: [% 16d] [% 16d] [% 16d]\n"), xtn->name, i, i, i); + qse_spl_unlock (xtn->spl); + i++; + //sleep (1); + } + + return i; +} + +static int test1 (void) +{ + qse_thr_t* thr1, * thr2; + qse_spl_t spl; + thr_xtn_t* xtn1, * xtn2; + + qse_spl_init (&spl); + + thr1 = qse_thr_open (QSE_MMGR_GETDFL(), QSE_SIZEOF(thr_xtn_t)); + if (!thr1) + { + qse_printf (QSE_T("cannot open thread1\n")); + return -1; + } + + thr2 = qse_thr_open (QSE_MMGR_GETDFL(), QSE_SIZEOF(thr_xtn_t)); + if (!thr2) + { + qse_printf (QSE_T("cannot open thread2\n")); + return -1; + } + + xtn1 = qse_thr_getxtn(thr1); + xtn2 = qse_thr_getxtn(thr2); + + qse_strcpy (xtn1->name, QSE_T("Thr-X")); + qse_strcpy (xtn2->name, QSE_T("Thr-Y")); + xtn1->spl = &spl; + xtn2->spl = &spl; + + qse_thr_setstacksize (thr1, 64000); + qse_thr_setstacksize (thr2, 64000); + + if (qse_thr_start(thr1, thr_func, QSE_NULL, QSE_THR_SIGNALS_BLOCKED) <= -1) + { + qse_printf (QSE_T("cannot start thread1\n")); + qse_thr_close (thr1 ); + return -1; + } + + if (qse_thr_start(thr2, thr_func, QSE_NULL, QSE_THR_SIGNALS_BLOCKED) <= -1) + { + qse_printf (QSE_T("cannot start thread1\n")); + qse_thr_close (thr1 ); + return -1; + } + + while (!g_stopreq) + { + if (qse_thr_getstate(thr1) == QSE_THR_TERMINATED && + qse_thr_getstate(thr2) == QSE_THR_TERMINATED) break; + sleep (1); + } + + if (g_stopreq) + { + xtn1->stopreq = 1; + xtn2->stopreq = 1; + } + + qse_thr_join (thr1); + qse_thr_join (thr2); + + qse_printf (QSE_T("thread1 ended with retcode %d\n"), qse_thr_getretcode(thr1)); + qse_printf (QSE_T("thread2 ended with retcode %d\n"), qse_thr_getretcode(thr2)); + qse_thr_close (thr1); + qse_thr_close (thr2); + + return 0; +} + +static void handle_sigint (int sig, siginfo_t* siginfo, void* ctx) +{ + g_stopreq = 1; +} + +static void set_signal (int sig, void(*handler)(int, siginfo_t*, void*)) +{ + struct sigaction sa; + + memset (&sa, 0, sizeof(sa)); + /*sa.sa_handler = handler;*/ + sa.sa_flags = SA_SIGINFO; + sa.sa_sigaction = handler; + sigemptyset (&sa.sa_mask); + + sigaction (sig, &sa, NULL); +} + +static void set_signal_to_default (int sig) +{ + struct sigaction sa; + + memset (&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_DFL; + sa.sa_flags = 0; + sigemptyset (&sa.sa_mask); + + sigaction (sig, &sa, NULL); +} + +int main () +{ +#if defined(_WIN32) + char locale[100]; + UINT codepage = GetConsoleOutputCP(); + if (codepage == CP_UTF8) + { + /*SetConsoleOUtputCP (CP_UTF8);*/ + qse_setdflcmgrbyid (QSE_CMGR_UTF8); + } + else + { + sprintf (locale, ".%u", (unsigned int)codepage); + setlocale (LC_ALL, locale); + /*qse_setdflcmgrbyid (QSE_CMGR_SLMB);*/ + } +#else + setlocale (LC_ALL, ""); + /*qse_setdflcmgrbyid (QSE_CMGR_SLMB);*/ +#endif + + set_signal (SIGINT, handle_sigint); + + qse_open_stdsios (); + test1(); + qse_close_stdsios (); + + set_signal_to_default (SIGINT); + + return 0; +}