Jelajahi Sumber

feature merge bs-coreoptimize->trunk: Atomic Operations, Threading, Spinlock implemnetation. [commit 1/2, windows will followup]

- Added Abstractions for Atomic Operations (lock instructions.. windows guy's may now this as Interlocked* stuff ..)
- Added Threading api abstraction for Pthread based OS's and Windows
- Added Spinlock Implementation (uses CAS / if you need more informations - just read the source - its simple.)

- Due to Interlocked(Compare)Exchange64 .. we now require at least i686 (Pentium Pro) for 32Bit Builds :)
	youll also may feel some performance improvements when using 32bit builsd due to "newer" minimal arch
	the compiler is now able to use CMOV's ....


================================================================
= Important Warning: 
================================================================
Dont use threading at the moment athena is not threadsafe!
you'll mess up everthing when accessing data from other threads .., no synchronization is provided.

A way to process tasks asynchronously will come up after / with the new socket system.




git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@16221 54d463be-8e91-2dee-dedb-b68131a5f0ec
blacksirius 13 tahun lalu
induk
melakukan
04165cfcff
11 mengubah file dengan 1256 tambahan dan 2 penghapusan
  1. 6 0
      Makefile.in
  2. 380 1
      configure
  3. 40 0
      configure.in
  4. 1 1
      src/common/Makefile.in
  5. 157 0
      src/common/atomic.h
  6. 5 0
      src/common/core.c
  7. 104 0
      src/common/spinlock.h
  8. 270 0
      src/common/thread.c
  9. 115 0
      src/common/thread.h
  10. 61 0
      src/test/Makefile.in
  11. 117 0
      src/test/test_spinlock.c

+ 6 - 0
Makefile.in

@@ -28,6 +28,7 @@ endif
 	map_sql \
 	tools \
 	import \
+	test \
 	clean help
 
 all: $(ALL_DEPENDS)
@@ -55,6 +56,9 @@ map_sql: $(MAP_SQL_DEPENDS)
 tools:
 	@$(MAKE) -C src/tool
 
+test:
+	@$(MAKE) -C src/test
+
 import:
 # 1) create conf/import folder
 # 2) add missing files
@@ -72,6 +76,7 @@ clean:
 	@$(MAKE) -C src/char $@
 	@$(MAKE) -C src/map $@
 	@$(MAKE) -C src/tool $@
+	@$(MAKE) -C src/test $@
 
 help:
 	@echo "most common targets are 'all' 'sql' 'conf' 'clean' 'help'"
@@ -87,6 +92,7 @@ help:
 	@echo "'all'         - builds all the above targets"
 	@echo "'sql'         - builds sql servers (targets 'common_sql' 'login_sql' 'char_sql'"
 	@echo "                'map_sql' and 'import')"
+	@echo "'test'        - builds tests"
 	@echo "'clean'       - cleans builds and objects"
 	@echo "'help'        - outputs this message"
 

+ 380 - 1
configure

@@ -1,5 +1,5 @@
 #! /bin/sh
-# From configure.in Revision: 16200 .
+# From configure.in Revision: 16203 .
 # Guess values for system-dependent variables and create Makefiles.
 # Generated by GNU Autoconf 2.67.
 #
@@ -2126,6 +2126,8 @@ ac_config_files="$ac_config_files src/char/Makefile src/login/Makefile"
 
 ac_config_files="$ac_config_files src/map/Makefile src/tool/Makefile"
 
+ac_config_files="$ac_config_files src/test/Makefile"
+
 
 ac_ext=c
 ac_cpp='$CPP $CPPFLAGS'
@@ -4666,6 +4668,46 @@ $as_echo "$pointers_fit_in_ints" >&6; }
 fi
 
 
+#
+# check if we're producing 32bit code - so well produce binarys for at least i686 (speedup: cmovs, and cmpchg8 support)
+#
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC produces 32bit code" >&5
+$as_echo_n "checking whether $CC produces 32bit code... " >&6; }
+if test "$cross_compiling" = yes; then :
+
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: guessing no" >&5
+$as_echo "guessing no" >&6; }
+
+
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+		int main(int argc, char **argv){
+			if(sizeof(void*) == 4) return 0;
+			else return 1;
+		}
+
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+		CFLAGS="$CFLAGS -march=i686"
+		LDFLAGS="$LDFLAGS -march=i686"
+
+else
+
+		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -Wno-unused-parameter" >&5
 $as_echo_n "checking whether $CC supports -Wno-unused-parameter... " >&6; }
 OLD_CFLAGS="$CFLAGS"
@@ -5284,6 +5326,342 @@ fi
 fi
 
 
+#
+# pthread
+#
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5
+$as_echo_n "checking for pthread_create in -lpthread... " >&6; }
+if test "${ac_cv_lib_pthread_pthread_create+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread  $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_create ();
+int
+main ()
+{
+return pthread_create ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_pthread_pthread_create=yes
+else
+  ac_cv_lib_pthread_pthread_create=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5
+$as_echo "$ac_cv_lib_pthread_pthread_create" >&6; }
+if test "x$ac_cv_lib_pthread_pthread_create" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBPTHREAD 1
+_ACEOF
+
+  LIBS="-lpthread $LIBS"
+
+else
+  as_fn_error $? "pthread library not found or incompatible" "$LINENO" 5
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_sigmask in -lpthread" >&5
+$as_echo_n "checking for pthread_sigmask in -lpthread... " >&6; }
+if test "${ac_cv_lib_pthread_pthread_sigmask+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread  $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_sigmask ();
+int
+main ()
+{
+return pthread_sigmask ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_pthread_pthread_sigmask=yes
+else
+  ac_cv_lib_pthread_pthread_sigmask=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_sigmask" >&5
+$as_echo "$ac_cv_lib_pthread_pthread_sigmask" >&6; }
+if test "x$ac_cv_lib_pthread_pthread_sigmask" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBPTHREAD 1
+_ACEOF
+
+  LIBS="-lpthread $LIBS"
+
+else
+  as_fn_error $? "pthread library not found or incompatible" "$LINENO" 5
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_attr_init in -lpthread" >&5
+$as_echo_n "checking for pthread_attr_init in -lpthread... " >&6; }
+if test "${ac_cv_lib_pthread_pthread_attr_init+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread  $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_attr_init ();
+int
+main ()
+{
+return pthread_attr_init ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_pthread_pthread_attr_init=yes
+else
+  ac_cv_lib_pthread_pthread_attr_init=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_attr_init" >&5
+$as_echo "$ac_cv_lib_pthread_pthread_attr_init" >&6; }
+if test "x$ac_cv_lib_pthread_pthread_attr_init" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBPTHREAD 1
+_ACEOF
+
+  LIBS="-lpthread $LIBS"
+
+else
+  as_fn_error $? "pthread library not found or incompatible" "$LINENO" 5
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_attr_setstacksize in -lpthread" >&5
+$as_echo_n "checking for pthread_attr_setstacksize in -lpthread... " >&6; }
+if test "${ac_cv_lib_pthread_pthread_attr_setstacksize+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread  $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_attr_setstacksize ();
+int
+main ()
+{
+return pthread_attr_setstacksize ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_pthread_pthread_attr_setstacksize=yes
+else
+  ac_cv_lib_pthread_pthread_attr_setstacksize=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_attr_setstacksize" >&5
+$as_echo "$ac_cv_lib_pthread_pthread_attr_setstacksize" >&6; }
+if test "x$ac_cv_lib_pthread_pthread_attr_setstacksize" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBPTHREAD 1
+_ACEOF
+
+  LIBS="-lpthread $LIBS"
+
+else
+  as_fn_error $? "pthread library not found or incompatible" "$LINENO" 5
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_attr_destroy in -lpthread" >&5
+$as_echo_n "checking for pthread_attr_destroy in -lpthread... " >&6; }
+if test "${ac_cv_lib_pthread_pthread_attr_destroy+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread  $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_attr_destroy ();
+int
+main ()
+{
+return pthread_attr_destroy ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_pthread_pthread_attr_destroy=yes
+else
+  ac_cv_lib_pthread_pthread_attr_destroy=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_attr_destroy" >&5
+$as_echo "$ac_cv_lib_pthread_pthread_attr_destroy" >&6; }
+if test "x$ac_cv_lib_pthread_pthread_attr_destroy" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBPTHREAD 1
+_ACEOF
+
+  LIBS="-lpthread $LIBS"
+
+else
+  as_fn_error $? "pthread library not found or incompatible" "$LINENO" 5
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_cancel in -lpthread" >&5
+$as_echo_n "checking for pthread_cancel in -lpthread... " >&6; }
+if test "${ac_cv_lib_pthread_pthread_cancel+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread  $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_c_try_link "$LINENO"; then :
+  ac_cv_lib_pthread_pthread_cancel=yes
+else
+  ac_cv_lib_pthread_pthread_cancel=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_cancel" >&5
+$as_echo "$ac_cv_lib_pthread_pthread_cancel" >&6; }
+if test "x$ac_cv_lib_pthread_pthread_cancel" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBPTHREAD 1
+_ACEOF
+
+  LIBS="-lpthread $LIBS"
+
+else
+  as_fn_error $? "pthread library not found or incompatible" "$LINENO" 5
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_join in -lpthread" >&5
+$as_echo_n "checking for pthread_join in -lpthread... " >&6; }
+if test "${ac_cv_lib_pthread_pthread_join+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lpthread  $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_join ();
+int
+main ()
+{
+return pthread_join ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_pthread_pthread_join=yes
+else
+  ac_cv_lib_pthread_pthread_join=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_join" >&5
+$as_echo "$ac_cv_lib_pthread_pthread_join" >&6; }
+if test "x$ac_cv_lib_pthread_pthread_join" = x""yes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBPTHREAD 1
+_ACEOF
+
+  LIBS="-lpthread $LIBS"
+
+else
+  as_fn_error $? "pthread library not found or incompatible" "$LINENO" 5
+fi
+
+
+LDFLAGS="$LDFLAGS -lpthread"
+
+
 #
 # MySQL library
 #
@@ -6304,6 +6682,7 @@ do
     "src/login/Makefile") CONFIG_FILES="$CONFIG_FILES src/login/Makefile" ;;
     "src/map/Makefile") CONFIG_FILES="$CONFIG_FILES src/map/Makefile" ;;
     "src/tool/Makefile") CONFIG_FILES="$CONFIG_FILES src/tool/Makefile" ;;
+    "src/test/Makefile") CONFIG_FILES="$CONFIG_FILES src/test/Makefile" ;;
 
   *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5 ;;
   esac

+ 40 - 0
configure.in

@@ -9,6 +9,7 @@ AC_CONFIG_FILES([Makefile src/common/Makefile])
 AC_CONFIG_FILES([3rdparty/mt19937ar/Makefile 3rdparty/libconfig/Makefile])
 AC_CONFIG_FILES([src/char/Makefile src/login/Makefile])
 AC_CONFIG_FILES([src/map/Makefile src/tool/Makefile])
+AC_CONFIG_FILES([src/test/Makefile])
 
 AC_GNU_SOURCE
 
@@ -337,6 +338,31 @@ if test "$enable_64bit" = "no" ; then
 fi
 
 
+# 
+# check if we're producing 32bit code - so well produce binarys for at least i686 (speedup: cmovs, and cmpchg8 support)
+#
+AC_MSG_CHECKING([whether $CC produces 32bit code])
+AC_RUN_IFELSE(
+	[
+		int main(int argc, char **argv){
+			if(sizeof(void*) == 4) return 0;
+			else return 1;
+		}
+	],
+	[
+		AC_MSG_RESULT([yes])
+		CFLAGS="$CFLAGS -march=i686"
+		LDFLAGS="$LDFLAGS -march=i686"
+	],
+	[
+		AC_MSG_RESULT([no])
+	],
+	[
+		AC_MSG_RESULT([guessing no])
+	]
+)
+
+
 AC_MSG_CHECKING([whether $CC supports -Wno-unused-parameter])
 OLD_CFLAGS="$CFLAGS"
 CFLAGS="$CFLAGS -Wno-unused-parameter"
@@ -636,6 +662,20 @@ if test "$ac_cv_search_clock_gettime" != "no" ; then
 fi
 
 
+#
+# pthread
+#
+AC_CHECK_LIB([pthread], [pthread_create], [], [AC_MSG_ERROR([pthread library not found or incompatible])])
+AC_CHECK_LIB([pthread], [pthread_sigmask], [], [AC_MSG_ERROR([pthread library not found or incompatible])])
+AC_CHECK_LIB([pthread], [pthread_attr_init], [], [AC_MSG_ERROR([pthread library not found or incompatible])])
+AC_CHECK_LIB([pthread], [pthread_attr_setstacksize], [], [AC_MSG_ERROR([pthread library not found or incompatible])])
+AC_CHECK_LIB([pthread], [pthread_attr_destroy], [], [AC_MSG_ERROR([pthread library not found or incompatible])])
+AC_CHECK_LIB([pthread], [pthread_cancel], [], [AC_MSG_ERROR([pthread library not found or incompatible])])
+AC_CHECK_LIB([pthread], [pthread_join], [], [AC_MSG_ERROR([pthread library not found or incompatible])])
+
+LDFLAGS="$LDFLAGS -lpthread"
+
+
 #
 # MySQL library
 #

+ 1 - 1
src/common/Makefile.in

@@ -3,7 +3,7 @@ COMMON_OBJ = obj_all/core.o obj_all/socket.o obj_all/timer.o obj_all/db.o obj_al
 	obj_all/nullpo.o obj_all/malloc.o obj_all/showmsg.o obj_all/strlib.o obj_all/utils.o \
 	obj_all/grfio.o obj_all/mapindex.o obj_all/ers.o obj_all/md5calc.o \
 	obj_all/minicore.o obj_all/minisocket.o obj_all/minimalloc.o obj_all/random.o obj_all/des.o \
-	obj_all/conf.o
+	obj_all/conf.o obj_all/thread.o
 
 COMMON_H = $(shell ls ../common/*.h)
 

+ 157 - 0
src/common/atomic.h

@@ -0,0 +1,157 @@
+#ifndef _rA_ATOMIC_H_
+#define _rA_ATOMIC_H_
+
+// Atomic Operations 
+// (Interlocked CompareExchange, Add .. and so on ..)
+// 
+// Implementation varies / depends on:
+//	- Architecture
+//	- Compiler
+//	- Operating System
+//
+// our Abstraction is fully API-Compatible to Microsofts implementation @ NT5.0+
+// 
+#include "../common/cbasetypes.h"
+
+#if defined(_MSC_VER)
+#include "../common/winapi.h"
+
+#if !defined(_M_X64)
+// When compiling for windows 32bit, the 8byte interlocked operations are not provided by microsoft
+// (because they need at least i586 so its not generic enough.. ... )
+forceinline int64 InterlockedCompareExchange64(volatile int64 *dest, int64 exch, int64 _cmp){
+	_asm{
+		lea esi,_cmp;
+		lea edi,exch;
+        
+		mov eax,[esi];
+		mov edx,4[esi];
+		mov ebx,[edi];
+		mov ecx,4[edi];
+		mov esi,dest;
+		
+		lock CMPXCHG8B [esi];					
+	}
+}
+
+
+forceinline volatile int64 InterlockedIncrement64(volatile int64 *addend){
+	__int64 old;
+	do{
+		old = *addend;
+	}while(InterlockedCompareExchange64(addend, (old+1), old) != old);
+
+	return (old + 1);
+}
+
+
+
+forceinline volatile int64 InterlockedDecrement64(volatile int64 *addend){
+	__int64 old;
+
+	do{
+		old = *addend;
+	}while(InterlockedCompareExchange64(addend, (old-1), old) != old);
+
+	return (old - 1);
+}
+
+forceinline volatile int64 InterlockedExchangeAdd64(volatile int64 *addend, int64 increment){
+	__int64 old;
+
+	do{
+		old = *addend;
+	}while(InterlockedCompareExchange64(addend, (old + increment), old) != old);
+
+	return old;
+}
+
+forceinline volatile int64 InterlockedExchange64(volatile int64 *target, int64 val){
+	__int64 old;
+	do{
+		old = *target;
+	}while(InterlockedCompareExchange64(target, val, old) != old);
+
+	return old;
+}
+
+#endif //endif 32bit windows
+
+#elif defined(__GNUC__)
+
+#if !defined(__x86_64__) && !defined(__i386__)
+#error Your Target Platfrom is not supported
+#endif
+
+static forceinline volatile int64 InterlockedExchangeAdd64(volatile int64 *addend, int64 increment){
+	return __sync_fetch_and_add(addend, increment);
+}//end: InterlockedExchangeAdd64()
+
+
+static forceinline volatile int32 InterlockedExchangeAdd(volatile int32 *addend, int32 increment){
+	return __sync_fetch_and_add(addend, increment);
+}//end: InterlockedExchangeAdd()
+
+
+static forceinline volatile int64 InterlockedIncrement64(volatile int64 *addend){
+	return __sync_add_and_fetch(addend, 1);
+}//end: InterlockedIncrement64()
+
+
+static forceinline volatile int32 InterlockedIncrement(volatile int32 *addend){
+        return __sync_add_and_fetch(addend, 1);
+}//end: InterlockedIncrement()
+
+
+static forceinline volatile int64 InterlockedDecrement64(volatile int64 *addend){
+	return __sync_sub_and_fetch(addend, 1);
+}//end: InterlockedDecrement64()
+
+
+static forceinline volatile int32 InterlockedDecrement(volatile int32 *addend){
+	return __sync_sub_and_fetch(addend, 1);
+}//end: InterlockedDecrement()
+
+
+static forceinline volatile int64 InterlockedCompareExchange64(volatile int64 *dest, int64 exch, int64 cmp){
+	return __sync_val_compare_and_swap(dest, cmp, exch);
+}//end: InterlockedCompareExchange64()
+
+
+static forceinline volatile int32 InterlockedCompareExchange(volatile int32 *dest, int32 exch, int32 cmp){
+        return __sync_val_compare_and_swap(dest, cmp, exch);
+}//end: InterlockedCompareExchnage()
+
+
+static forceinline volatile int64 InterlockedExchange64(volatile int64 *target, int64 val){
+	int ret;
+	
+	__asm__ __volatile__(
+		"lock xchg %2, (%1)"
+		:"=r" (ret)
+		:"r" (target), "0" (val)
+		:"memory"
+	);
+	
+	return ret;
+}//end: InterlockedExchange64()
+
+
+static forceinline volatile int32 InterlockedExchange(volatile int32 *target, int32 val){
+	int ret;
+	
+	__asm__ __volatile__(
+		"lock xchgl %2, (%1)"
+		:"=r" (ret)
+		:"r" (target), "0" (val)
+		:"memory"
+	);
+	
+	return ret;
+}//end: InterlockedExchange()
+
+
+#endif //endif compiler decission
+
+
+#endif

+ 5 - 0
src/common/core.c

@@ -9,6 +9,7 @@
 #include "../common/db.h"
 #include "../common/socket.h"
 #include "../common/timer.h"
+#include "../common/thread.h"
 #endif
 
 #include <stdio.h>
@@ -278,6 +279,8 @@ int main (int argc, char **argv)
 	display_title();
 	usercheck();
 
+	rathread_init();
+
 	db_init();
 	signals_init();
 
@@ -303,6 +306,8 @@ int main (int argc, char **argv)
 	timer_final();
 	socket_final();
 	db_final();
+	
+	rathread_final();
 #endif
 
 	malloc_final();

+ 104 - 0
src/common/spinlock.h

@@ -0,0 +1,104 @@
+#pragma once
+#ifndef _rA_SPINLOCK_H_
+#define _rA_SPINLOCK_H_
+
+//
+// CAS based Spinlock Implementation
+//
+// CamelCase names are choosen to be consistent with microsofts winapi
+// which implements CriticalSection by this naming...
+//
+// Author: Florian Wilkemeyer <fw@f-ws.de>
+//
+// Copyright (c) rAthena Project (www.rathena.org) - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+//
+//
+ 
+#ifdef WIN32
+#include "../common/winapi.h"
+#endif
+
+#include "../common/cbasetypes.h"
+#include "../common/atomic.h"
+#include "../common/thread.h"
+
+#ifdef WIN32
+
+typedef struct __declspec( align(64) ) SPIN_LOCK{
+	volatile LONG lock;
+	volatile LONG nest;
+	volatile LONG sync_lock;
+}  SPIN_LOCK, *PSPIN_LOCK;
+#else
+typedef struct SPIN_LOCK{
+		volatile int32 lock;
+		volatile int32 nest; // nesting level.
+		
+		volatile int32 sync_lock;
+} __attribute__((aligned(64))) SPIN_LOCK, *PSPIN_LOCK;
+#endif
+
+
+
+static forceinline void InitializeSpinLock(PSPIN_LOCK lck){
+		lck->lock = 0;
+		lck->nest = 0;
+		lck->sync_lock = 0;
+}
+
+static forceinline void FinalizeSpinLock(PSPIN_LOCK lck){
+		return;
+}
+
+
+#define getsynclock(l) { while(1){ if(InterlockedCompareExchange(l, 1, 0) == 0) break; rathread_yield(); } }
+#define dropsynclock(l) { InterlockedExchange(l, 0); }
+
+static forceinline void EnterSpinLock(PSPIN_LOCK lck){
+		int tid = rathread_get_tid();
+		
+		// Get Sync Lock && Check if the requester thread already owns the lock. 
+		// if it owns, increase nesting level
+		getsynclock(&lck->sync_lock);
+		if(InterlockedCompareExchange(&lck->lock, tid, tid) == tid){
+				InterlockedIncrement(&lck->nest);
+				dropsynclock(&lck->sync_lock);
+				return; // Got Lock
+		}
+		// drop sync lock
+		dropsynclock(&lck->sync_lock);
+		
+		
+		// Spin until we've got it ! 
+		while(1){
+				
+				if(InterlockedCompareExchange(&lck->lock, tid, 0) == 0){
+						
+						InterlockedIncrement(&lck->nest);
+						return; // Got Lock
+				}
+				
+				rathread_yield(); // Force ctxswitch to another thread.
+		}
+
+}
+
+
+static forceinline void LeaveSpinLock(PSPIN_LOCK lck){
+		int tid = rathread_get_tid();
+
+		getsynclock(&lck->sync_lock);
+		
+		if(InterlockedCompareExchange(&lck->lock, tid, tid) == tid){ // this thread owns the lock.
+			if(InterlockedDecrement(&lck->nest) == 0)
+					InterlockedExchange(&lck->lock, 0); // Unlock!
+		}
+		
+		dropsynclock(&lck->sync_lock);
+}
+
+
+
+
+#endif

+ 270 - 0
src/common/thread.c

@@ -0,0 +1,270 @@
+
+#ifdef WIN32
+#include "../common/winapi.h"
+#define getpagesize() 4096 // @TODO: implement this properly (GetSystemInfo .. dwPageSize..). (Atm as on all supported win platforms its 4k its static.)
+#define __thread __declspec( thread ) 
+#else
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <pthread.h>
+#include <sched.h>
+#endif
+
+#include "cbasetypes.h"
+#include "malloc.h"
+#include "showmsg.h"
+#include "thread.h"
+
+
+#define RA_THREADS_MAX 64
+
+struct rAthread {
+	unsigned int myID;
+	
+	RATHREAD_PRIO  prio;
+	rAthreadProc proc;
+	void *param; 
+
+	#ifdef WIN32
+	HANDLE hThread;
+	#else
+	pthread_t hThread;
+	#endif
+};
+
+
+__thread int g_rathread_ID = -1;
+
+
+///
+/// Subystem Code
+///
+static struct rAthread l_threads[RA_THREADS_MAX];
+
+void rathread_init(){
+	register unsigned int i;
+	memset(&l_threads, 0x00, RA_THREADS_MAX * sizeof(struct rAthread) );
+	
+	for(i = 0; i < RA_THREADS_MAX; i++){
+		l_threads[i].myID = i;
+	}
+
+	// now lets init thread id 0, which represnts the main thread
+	g_rathread_ID = 0;
+	l_threads[0].prio = RAT_PRIO_NORMAL;
+	l_threads[0].proc = (rAthreadProc)0xDEADCAFE;
+
+}//end: rathread_init()
+
+
+
+void rathread_final(){
+	register unsigned int i;
+	
+	// Unterminated Threads Left? 
+	// Should'nt happen ..
+	// Kill 'em all! 
+	//
+	for(i = 1; i < RA_THREADS_MAX; i++){
+		if(l_threads[i].proc != NULL){
+			ShowWarning("rAthread_final: unterminated Thread (tid %u entryPoint %p) - forcing to terminate (kill)\n", i, l_threads[i].proc);
+			rathread_destroy(&l_threads[i]);
+		}
+	}
+	
+	
+}//end: rathread_final()
+
+
+
+// gets called whenever a thread terminated ..
+static void rat_thread_terminated( rAthread handle ){
+
+	int id_backup = handle->myID;
+
+	// Simply set all members to 0 (except the id)
+	memset(handle, 0x00, sizeof(struct rAthread));
+	
+	handle->myID = id_backup; // done ;)
+
+}//end: rat_thread_terminated()
+
+#ifdef WIN32
+DWORD WINAPI _raThreadMainRedirector(LPVOID p){
+#else
+static void *_raThreadMainRedirector( void *p ){
+	sigset_t set; // on Posix Thread platforms
+#endif
+	void *ret;
+	
+	// Update myID @ TLS to right id.
+	g_rathread_ID = ((rAthread)p)->myID; 
+
+#ifndef WIN32
+	// When using posix threads
+	// the threads inherits the Signal mask from the thread which's spawned 
+	// this thread
+	// so we've to block everything we dont care about.
+	sigemptyset(&set);
+	sigaddset(&set, SIGINT);
+	sigaddset(&set, SIGTERM);
+	sigaddset(&set, SIGPIPE);
+
+	pthread_sigmask(SIG_BLOCK, &set, NULL);
+		
+#endif
+
+
+	ret = ((rAthread)p)->proc( ((rAthread)p)->param ) ;
+
+#ifdef WIN32	
+	CloseHandle( ((rAthread)p)->hThread );
+#endif
+
+	rat_thread_terminated( (rAthread)p );
+#ifdef WIN32
+	return (DWORD)ret;
+#else
+	return ret;
+#endif
+}//end: _raThreadMainRedirector()
+
+
+
+
+
+///
+/// API Level
+/// 
+rAthread rathread_create( rAthreadProc entryPoint,  void *param ){
+	return rathread_createEx( entryPoint, param,  (1<<23) /*8MB*/,  RAT_PRIO_NORMAL );
+}//end: rathread_create()
+
+
+rAthread rathread_createEx( rAthreadProc entryPoint,  void *param,  size_t szStack,  RATHREAD_PRIO prio ){
+#ifndef WIN32
+	pthread_attr_t attr;
+#endif
+	size_t tmp;
+	unsigned int i;
+	rAthread handle = NULL;
+
+
+	// given stacksize aligned to systems pagesize?
+	tmp = szStack % getpagesize();
+	if(tmp != 0)
+		szStack += tmp;
+
+
+	// Get a free Thread Slot. 
+	for(i = 0; i < RA_THREADS_MAX; i++){
+		if(l_threads[i].proc == NULL){
+			handle = &l_threads[i];
+			break;
+		}
+	}
+	
+	if(handle == NULL){
+		ShowError("rAthread: cannot create new thread (entryPoint: %p) - no free thread slot found!", entryPoint);
+		return NULL;
+	}
+	
+	
+	
+	handle->proc = entryPoint;
+	handle->param = param;
+
+#ifdef WIN32
+	handle->hThread = CreateThread(NULL, szStack, _raThreadMainRedirector, (void*)handle, 0, NULL);
+#else
+	pthread_attr_init(&attr);
+	pthread_attr_setstacksize(&attr, szStack);
+	
+	if(pthread_create(&handle->hThread, &attr, _raThreadMainRedirector, (void*)handle) != 0){
+		handle->proc = NULL;
+		handle->param = NULL;
+		return NULL;
+	}
+	pthread_attr_destroy(&attr);
+#endif
+
+	rathread_prio_set( handle,  prio );
+	
+	return handle;
+}//end: rathread_createEx
+
+
+void rathread_destroy ( rAthread handle ){
+#ifdef WIN32
+	if( TerminateThread(handle->hThread, 0) != FALSE){
+		CloseHandle(handle->hThread);
+		rat_thread_terminated(handle);
+	}
+#else
+	if( pthread_cancel( handle->hThread ) == 0){
+	
+		// We have to join it, otherwise pthread wont re-cycle its internal ressources assoc. with this thread.
+		// 
+		pthread_join( handle->hThread, NULL );
+		
+		// Tell our manager to release ressources ;)
+		rat_thread_terminated(handle);
+	}
+#endif
+}//end: rathread_destroy()
+
+rAthread rathread_self( ){
+	rAthread handle = &l_threads[g_rathread_ID];
+	
+	if(handle->proc != NULL) // entry point set, so its used!	
+		return handle;
+		
+	return NULL;	
+}//end: rathread_self()
+
+
+int rathread_get_tid(){
+	
+	return g_rathread_ID;
+	
+}//end: rathread_get_tid()
+
+
+bool rathread_wait( rAthread handle,  void* *out_exitCode ){
+	
+	// Hint:
+	// no thread data cleanup routine call here!
+	// its managed by the callProxy itself..
+	//
+#ifdef WIN32
+	WaitForSingleObject(handle->hThread, INFINITE);
+	return true; 
+#else
+	if(pthread_join(handle->hThread, out_exitCode) == 0)
+		return true;
+	return false;
+#endif
+
+}//end: rathread_wait()
+
+
+void rathread_prio_set( rAthread handle, RATHREAD_PRIO prio ){
+	handle->prio = RAT_PRIO_NORMAL; 
+	//@TODO 
+}//end: rathread_prio_set()
+
+
+RATHREAD_PRIO rathread_prio_get( rAthread handle){
+	return handle->prio;
+}//end: rathread_prio_get()
+
+
+void rathread_yield(){
+#ifdef WIN32 
+	SwitchToThread();
+#else
+	sched_yield();
+#endif	
+}//end: rathread_yield()

+ 115 - 0
src/common/thread.h

@@ -0,0 +1,115 @@
+#pragma once 
+#ifndef _rA_THREAD_H_
+#define _rA_THREAD_H_
+
+#include "../common/cbasetypes.h"
+
+typedef struct rAthread *rAthread;
+typedef void* (*rAthreadProc)(void*);
+
+typedef enum RATHREAD_PRIO {
+	RAT_PRIO_LOW = 0,
+	RAT_PRIO_NORMAL,
+	RAT_PRIO_HIGH	
+} RATHREAD_PRIO;
+
+
+/**
+ * Creates a new Thread
+ *
+ * @param entyPoint  - entryProc,
+ * @param param - general purpose parameter, would be given as parameter to the thread's entrypoint.
+ * 
+ * @return not NULL if success
+ */
+rAthread rathread_create( rAthreadProc entryPoint,  void *param );
+
+
+/** 
+ * Creates a new Thread (with more creation options)
+ *
+ * @param entyPoint  - entryProc,
+ * @param param - general purpose parameter, would be given as parameter to the thread's entrypoint
+ * @param szStack - stack Size in bytes 
+ * @param prio - Priority of the Thread @ OS Scheduler..
+ *
+ * @return not NULL if success
+ */
+rAthread rathread_createEx( rAthreadProc entryPoint,  void *param,  size_t szStack,  RATHREAD_PRIO prio );
+
+
+/**
+ * Destroys the given Thread immediatly
+ *
+ * @note The Handle gets invalid after call! dont use it afterwards. 
+ *
+ * @param handle - thread to destroy.
+ */
+void rathread_destroy ( rAthread handle );
+
+
+/** 
+ * Returns the thread handle of the thread calling this function
+ * 
+ * @note this wont work @ programms main thread
+ * @note the underlying implementation might not perform very well, cache the value received! 
+ * 
+ * @return not NULL if success
+ */
+rAthread rathread_self( );
+
+
+/**
+ * Returns own thrad id (TID) 
+ *
+ * @note this is not the operating system THREAD ID!
+ *
+ * @return -1 when fails, otherwise >= 0
+ */
+int rathread_get_tid();
+
+
+/**
+ * Waits for the given thread to terminate 
+ *
+ * @param handle - thread to wait (join) for
+ * @param out_Exitcode - [OPTIONAL] - if given => Exitcode (value) of the given thread - if it's terminated
+ * 
+ * @return true - if the given thread has been terminated.
+ */
+bool rathread_wait( rAthread handle,  void* *out_exitCode );
+
+
+/** 
+ * Sets the given PRIORITY @ OS Task Scheduler
+ * 
+ * @param handle - thread to set prio for
+ * @param rio - the priority (RAT_PRIO_LOW ... )
+ */
+void rathread_prio_set( rAthread handle, RATHREAD_PRIO prio );
+
+
+/** 
+ * Gets the current Prio of the given trhead
+ *
+ * @param handle - the thread to get the prio for.
+ */
+RATHREAD_PRIO rathread_prio_get( rAthread handle);
+
+
+/**
+ * Tells the OS scheduler to yield the execution of the calling thread
+ * 
+ * @note: this will not "pause" the thread,
+ *			it just allows the OS to spent the remaining time 
+ *			of the slice to another thread.
+ */
+void rathread_yield();
+
+
+
+void rathread_init();
+void rathread_final();
+
+
+#endif

+ 61 - 0
src/test/Makefile.in

@@ -0,0 +1,61 @@
+
+COMMON_H = $(shell ls ../common/*.h)
+
+MT19937AR_OBJ = ../../3rdparty/mt19937ar/mt19937ar.o
+MT19937AR_H = ../../3rdparty/mt19937ar/mt19937ar.h
+MT19937AR_INCLUDE = -I../../3rdparty/mt19937ar
+
+LIBCONFIG_OBJ = ../../3rdparty/libconfig/libconfig.o ../../3rdparty/libconfig/grammar.o \
+	../../3rdparty/libconfig/scanctx.o ../../3rdparty/libconfig/scanner.o ../../3rdparty/libconfig/strbuf.o
+LIBCONFIG_H = ../../3rdparty/libconfig/libconfig.h ../../3rdparty/libconfig/grammar.h \
+	../../3rdparty/libconfig/parsectx.h ../../3rdparty/libconfig/scanctx.h ../../3rdparty/libconfig/scanner.h \
+	../../3rdparty/libconfig/strbuf.h ../../3rdparty/libconfig/wincompat.h
+LIBCONFIG_INCLUDE = -I../../3rdparty/libconfig
+
+TEST_SPINLOCK_OBJ=obj/test_spinlock.o
+TEST_SPINLOCK_H=
+TEST_SPINLOCK_DEPENDS=obj $(TEST_SPINLOCK_OBJ) ../common/obj_sql/common_sql.a ../common/obj_all/common.a $(MT19937AR_OBJ)
+    
+@SET_MAKE@
+
+#####################################################################
+.PHONY :all test_spinlock
+
+all: test_spinlock
+
+clean:
+	@echo "	CLEAN	test"
+	@rm -rf *.o obj ../../test_spinlock@EXEEXT@ 
+
+#####################################################################
+
+# object directories
+
+obj:
+	@echo "	MKDIR	obj"
+	@-mkdir obj
+	
+#executables
+
+test_spinlock: $(TEST_SPINLOCK_DEPENDS)
+	@echo "	LD	$@"
+	@@CC@ @LDFLAGS@ -o ../../test_spinlock@EXEEXT@ $(TEST_SPINLOCK_OBJ) ../common/obj_sql/common_sql.a ../common/obj_all/common.a $(MT19937AR_OBJ) $(LIBCONFIG_OBJ) @LIBS@ @MYSQL_LIBS@
+
+# login object files
+
+obj/%.o: %.c $(COMMON_H) $(MT19937AR_H) $(LIBCONFIG_H)
+	@echo "	CC	$<"
+	@@CC@ @CFLAGS@ $(MT19937AR_INCLUDE) $(LIBCONFIG_INCLUDE) -DWITH_SQL @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
+
+# missing object files
+../common/obj_all/common.a:
+	@$(MAKE) -C ../common sql
+	
+../common/obj_sql/common_sql.a:
+	@$(MAKE) -C ../common sql
+
+MT19937AR_OBJ:
+	@$(MAKE) -C ../../3rdparty/mt19937ar
+
+LIBCONFIG_OBJ:
+	@$(MAKE) -C ../../3rdparty/libconfig

+ 117 - 0
src/test/test_spinlock.c

@@ -0,0 +1,117 @@
+
+#include "../common/core.h"
+#include "../common/atomic.h"
+#include "../common/thread.h"
+#include "../common/spinlock.h"
+#include "../common/showmsg.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+// 
+// Simple test for the spinlock implementation to see if it works properly..  
+//
+
+
+
+#define THRC 32 //thread Count 
+#define PERINC 100000
+#define LOOPS 47
+
+
+static SPIN_LOCK lock;
+static int val = 0;
+static volatile int32 done_threads = 0;
+
+static  void *worker(void *p){
+	register int i;
+	
+	for(i = 0; i < PERINC; i++){
+		EnterSpinLock(&lock);
+		EnterSpinLock(&lock);
+		
+		val++;
+		
+		LeaveSpinLock(&lock);
+		LeaveSpinLock(&lock);
+	}
+	
+	InterlockedIncrement(&done_threads);
+	
+	return NULL;
+}//end: worker()
+
+
+int do_init(int argc, char **argv){
+	rAthread t[THRC];
+	int j, i;
+	int ok;
+	
+	ShowStatus("==========\n");
+	ShowStatus("TEST: %u Runs,  (%u Threads)\n", LOOPS, THRC);
+	ShowStatus("This can take a while\n");
+	ShowStatus("\n\n");
+	
+	ok =0;
+	for(j = 0; j < LOOPS; j++){
+		val = 0;
+		done_threads = 0;
+		
+		InitializeSpinLock(&lock);
+		
+
+		for(i =0; i < THRC; i++){
+			t[i] = rathread_createEx( worker,  NULL,  1024*512,  RAT_PRIO_NORMAL);
+		}
+		
+		
+		while(1){
+			if(InterlockedCompareExchange(&done_threads, THRC, THRC) == THRC) 
+				break;
+			
+			rathread_yield();
+		}
+		
+		FinalizeSpinLock(&lock);
+		
+		// Everything fine?
+		if(val != (THRC*PERINC) ){
+			printf("FAILED! (Result: %u, Expected: %u)\n",  val,  (THRC*PERINC) );
+		}else{
+			printf("OK! (Result: %u, Expected: %u)\n", val, (THRC*PERINC) );
+			ok++;
+		}
+
+	}
+	
+
+	if(ok != LOOPS){
+		ShowFatalError("Test failed.\n");		
+		exit(1);
+	}else{
+		ShowStatus("Test passed.\n");
+		exit(0);
+	}
+
+
+return 0;
+}//end: do_init()
+
+
+void do_abort(){
+}//end: do_abort()
+
+
+void set_server_type(){
+	SERVER_TYPE = ATHENA_SERVER_NONE;
+}//end: set_server_type()
+
+
+void do_final(){
+}//end: do_final()
+
+
+int parse_console(const char* command){
+	return 0;
+}//end: parse_console
+