浏览代码

- makefile: - compile in 64bit mode by default on sparc64
- sparc <= v8 support
- -CC_GCC_LIKE_ASM is defined when the compiler supports gcc style
inline asm (gcc and icc)

- atomic operations and memory barriers support for:
- x86
- x86_64
- mips (only in NOSMP mode and if it supports ll and sc)
- mips2 (mips32, isa >= 2)
- mips64
- powerpc
- powerpc64
- sparc <= v8 (only memory barriers, the atomic operations are implemented
using locks because there is no hardware support for them)
- sparc64 - both 32 (v8plus) and 64 bit mode
If there is no support for the compiler/arch. combination, it falls back to
locks.

The code is tested (only basic tests: it runs and the results are ok, but no
parallel tests) on x86, x86_64, mips2, powerpc, sparc64 (both modes).
The sparc version runs ok on sparc64 (so it's most likely ok).
powerpc64 and mips64 not tested due to no access to the corresponding
hardware, but they do compile ok.
For more details see the comments at the beginning of atomic_ops.h.

Andrei Pelinescu-Onciul 19 年之前
父节点
当前提交
d307929c08
共有 13 个文件被更改,包括 2007 次插入449 次删除
  1. 88 11
      Makefile.defs
  2. 342 0
      atomic/atomic_mips2.h
  3. 296 0
      atomic/atomic_ppc.h
  4. 60 0
      atomic/atomic_sparc.h
  5. 286 0
      atomic/atomic_sparc64.h
  6. 233 0
      atomic/atomic_unknown.h
  7. 294 0
      atomic/atomic_x86.h
  8. 20 5
      atomic_ops.c
  9. 64 412
      atomic_ops.h
  10. 46 0
      atomic_ops_init.h
  11. 4 0
      main.c
  12. 57 21
      test/atomic_test.c
  13. 217 0
      test/atomic_test2.c

+ 88 - 11
Makefile.defs

@@ -45,6 +45,9 @@
 #  2005-07-25  better solaris arch detection (andrei)
 #  2005-09-12  -mallign-double removed (too many problems) (andrei)
 #  2005-10-02  distcc get gcc version hack (andrei)
+#  2006-03-30  64 bit mode compile by default on sparc64 (-m64), added
+#              CC_GCC_LIKE_ASM and SPARC64_MODE (andrei)
+#              sparc <= v8 support (andrei)
 
 
 # check if already included/exported
@@ -445,7 +448,7 @@ endif
 
 ifeq ($(ARCH), sparc)
 	# smp no supported on sparc32
-	DEFS+= -DNOSMP 
+	DEFS+= -DNOSMP # FIXME
 	use_fast_lock=yes
 endif
 
@@ -489,6 +492,7 @@ ifeq ($(mode), release)
 ifeq	($(ARCH), i386)
 		# if gcc 
 ifeq		($(CC_NAME), gcc)
+				DEFS+=-DCC_GCC_LIKE_ASM
 				#common stuff
 				CFLAGS=-g -O9 -funroll-loops  -Wcast-align $(PROFILE) \
 					-Wall  
@@ -532,6 +536,7 @@ endif			# CC_SHORTVER, 4.x
 
 else		# CC_NAME, gcc
 ifeq		($(CC_NAME), icc)
+			DEFS+=-DCC_GCC_LIKE_ASM
 			CFLAGS=-g -O3  -ipo -ipo_obj -unroll  $(PROFILE) \
 					 -tpp6 -xK  #-openmp  #optimize for PIII 
 				# -prefetch doesn't seem to work
@@ -549,6 +554,7 @@ endif	#ARCH, i386
 ifeq	($(ARCH), x86_64)
 		# if gcc 
 ifeq		($(CC_NAME), gcc)
+				DEFS+=-DCC_GCC_LIKE_ASM
 				#common stuff
 				CFLAGS=-g -O9 -funroll-loops  -Wcast-align $(PROFILE) \
 					-Wall 
@@ -592,6 +598,7 @@ endif			# CC_SHORTVER, 4.x
 
 else		# CC_NAME, gcc
 ifeq		($(CC_NAME), icc)
+			DEFS+=-DCC_GCC_LIKE_ASM
 			CFLAGS=-g -O3  -ipo -ipo_obj -unroll  $(PROFILE) \
 					 -tpp6 -xK  #-openmp  #optimize for PIII 
 				# -prefetch doesn't seem to work
@@ -605,15 +612,21 @@ endif		#CC_NAME, icc
 endif		#CC_NAME, gcc
 endif	#ARCH, x86_64
 
-	#if sparc
+	#if sparc64
 ifeq	($(ARCH), sparc64)
 			#if gcc
 ifeq		($(CC_NAME), gcc)
+				DEFS+=-DCC_GCC_LIKE_ASM -DSPARC64_MODE
 				#common stuff
-				CFLAGS=-g -O9 -funroll-loops  $(PROFILE) \
+				CFLAGS=-m64 -g -O9 -funroll-loops  $(PROFILE) \
 					-Wall\
 					#-Wcast-align \
 					#-Wmissing-prototypes 
+				# use -m64 to force 64 bit (but add it also to LDFLAGS and
+				#  don't forget to define SPARC64_MODE)
+				# -m32 for 32 bit (default on solaris),
+				# nothing for arch. default
+				LDFLAGS+=-m64
 				#if gcc 4.x
 ifeq			($(CC_SHORTVER), 4.x)
 					CPU ?= ultrasparc
@@ -633,9 +646,6 @@ ifeq			($(CC_SHORTVER), 3.0)
 					CPU ?= ultrasparc
 					#use 32bit for now
 					CFLAGS+= -mcpu=ultrasparc -mtune=$(CPU)   \
-					# use -m64 to force 64 bit (but add it also to LDFLAGS), 
-					# -m32 for 32 bit (default on solaris),
-					# nothing for arch. default
 					# -mcpu=v9 or ultrasparc? # -mtune implied by -mcpu
 					#-mno-epilogue #try to inline function exit code
 					#-mflat # omit save/restore
@@ -647,7 +657,7 @@ $(warning 			Old gcc detected ($(CC_SHORTVER)), use  gcc >= 3.1 \
 ifneq				($(OS), netbsd)
 						# on netbsd/sparc64,  gcc 2.95.3 does not compile
 						# ser with -mv8
-						CFLAGS+= -mv8 
+						CFLAGS+= -mv9 
 endif
 ifeq					($(ASTYPE), solaris)
 							CFLAGS+= -Wa,-xarch=v8plus
@@ -657,7 +667,7 @@ else			#CC_SHORTVER, 2.9x
 $(warning			You are using an old and unsupported gcc \
 					 version ($(CC_SHORTVER)), compile at your own risk!)
 					
-					CFLAGS+= -mv8 
+					CFLAGS+= -mv9 
 ifeq					($(ASTYPE), solaris)
 							CFLAGS+= -Wa,-xarch=v8plus
 endif					
@@ -666,10 +676,11 @@ endif			#CC_SHORTVER, 2.9x
 endif			#CC_SHORTVER, 3.0
 endif			#CC_SHORTVER, 3.4
 endif			#CC_SHORTVER, 4.x
-
+	
 else		#CC_NAME, gcc
 ifeq		($(CC_NAME), suncc)
-			CFLAGS+=-g -xO5 -fast -native -xarch=v8plusa -xCC \
+			DEFS+=-DSPARC64_MODE
+			CFLAGS+= -m64 -g -xO5 -fast -native -xarch=v9 -xCC \
 					-xc99 # C99 support
 			# -Dinline="" # add this if cc < 5.3 (define inline as null)
 else
@@ -679,10 +690,69 @@ endif		#CC_NAME, suncc
 endif		#CC_NAME, gcc
 endif	#ARCH, sparc64
 
+	#if sparc
+ifeq	($(ARCH), sparc)
+			#if gcc
+ifeq		($(CC_NAME), gcc)
+				DEFS+=-DCC_GCC_LIKE_ASM
+				#common stuff
+				CFLAGS=-g -O9 -funroll-loops  $(PROFILE) \
+					-Wall\
+					#-Wcast-align \
+					#-Wmissing-prototypes 
+				#if gcc 4.x
+ifeq			($(CC_SHORTVER), 4.x)
+					CPU ?= v8 
+					#use 32bit for now
+					CFLAGS+= -minline-all-stringops \
+							-mtune=$(CPU) \
+							-ftree-vectorize
+else
+				#if gcc 3.4
+ifeq			($(CC_SHORTVER), 3.4)
+					CPU ?= v8
+					#use 32bit for now
+					CFLAGS+= -mtune=$(CPU)
+else
+				#if gcc 3.0
+ifeq			($(CC_SHORTVER), 3.0)
+					CPU ?= v8 
+					#use 32bit for now
+					CFLAGS+= -mtune=$(CPU)   \
+					#-mno-epilogue #try to inline function exit code
+					#-mflat # omit save/restore
+					#-,faster-structs #faster non Sparc ABI structure copy ops
+else			# CC_SHORTVER, 3.0
+ifeq			($(CC_SHORTVER), 2.9x) #older gcc version (2.9[1-5])
+$(warning 			Old gcc detected ($(CC_SHORTVER)), use  gcc >= 3.1 \
+					for better results)
+else			#CC_SHORTVER, 2.9x
+				#really old version
+$(warning			You are using an old and unsupported gcc \
+					 version ($(CC_SHORTVER)), compile at your own risk!)
+					
+endif			#CC_SHORTVER, 2.9x
+endif			#CC_SHORTVER, 3.0
+endif			#CC_SHORTVER, 3.4
+endif			#CC_SHORTVER, 4.x
+	
+else		#CC_NAME, gcc
+ifeq		($(CC_NAME), suncc)
+			CFLAGS+= -g -xO5 -fast -native -xCC \
+					-xc99 # C99 support
+			# -Dinline="" # add this if cc < 5.3 (define inline as null)
+else
+				#other compilers
+$(error 			Unsupported compiler ($(CC):$(CC_NAME)), try gcc)
+endif		#CC_NAME, suncc
+endif		#CC_NAME, gcc
+endif	#ARCH, sparc
+
 	#if ipaq/netwinder
 ifeq	($(ARCH), arm)
 		# if gcc 
 ifeq		($(CC_NAME), gcc)
+				DEFS+=-DCC_GCC_LIKE_ASM
 				#common stuff
 				CFLAGS=-O9 -funroll-loops  -Wcast-align $(PROFILE) \
 					-Wall   
@@ -725,6 +795,7 @@ endif	#ARCH, arm
 ifeq	($(ARCH), mips)
 		# if gcc 
 ifeq		($(CC_NAME), gcc)
+				DEFS+=-DCC_GCC_LIKE_ASM
 				#common stuff
 				CFLAGS=-O9 -funroll-loops  $(PROFILE) \
 					-Wall 
@@ -766,6 +837,7 @@ endif	#ARCH, mips
 ifeq	($(ARCH), mips2)
 		# if gcc 
 ifeq		($(CC_NAME), gcc)
+				DEFS+=-DCC_GCC_LIKE_ASM
 				#common stuff
 				CFLAGS= -mips2 -O9 -funroll-loops $(PROFILE) \
 					-Wall 
@@ -806,6 +878,7 @@ endif	#ARCH, mips2
 ifeq	($(ARCH), alpha)
 		# if gcc 
 ifeq		($(CC_NAME), gcc)
+				DEFS+=-DCC_GCC_LIKE_ASM
 				#common stuff
 				CFLAGS= -O9 -funroll-loops $(PROFILE)  -Wall 
 			#if gcc 4.0+
@@ -844,6 +917,7 @@ endif	#ARCH, alpha
 ifeq	($(ARCH), ppc)
 		# if gcc 
 ifeq		($(CC_NAME), gcc)
+				DEFS+=-DCC_GCC_LIKE_ASM
 				#common stuff
 				CFLAGS= -O9 -funroll-loops $(PROFILE)  -Wall 
 			#if gcc 4.0+
@@ -884,6 +958,7 @@ endif	#ARCH, ppc
 ifeq	($(ARCH), ppc64)
 		# if gcc 
 ifeq		($(CC_NAME), gcc)
+				DEFS+=-DCC_GCC_LIKE_ASM
 				#common stuff
 				CFLAGS= -O9 -funroll-loops $(PROFILE)  -Wall 
 ifeq			($(CC_SHORTVER), 4.x)
@@ -950,7 +1025,9 @@ else	#mode,release
 ifeq	($(CC_NAME), gcc)
 		CFLAGS=-g -Wcast-align $(PROFILE)
 ifeq		($(ARCH), sparc64)
-			CFLAGS+= -mcpu=ultrasparc 
+			DEFS+=SPARC64_MODE
+			CFLAGS+= -mcpu=ultrasparc -m64
+			LDFLAGS+=-m64
 endif
 ifeq		($(LDTYPE), solaris)
 			#solaris ld

+ 342 - 0
atomic/atomic_mips2.h

@@ -0,0 +1,342 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2006 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+/*
+ *  atomic operations and memory barriers (mips isa 2 and mips64 specific)
+ *  WARNING: atomic ops do not include memory barriers
+ *  see atomic_ops.h for more details 
+ *  WARNING: not tested on mips64 (not even a compile test)
+ *
+ *  Config defines:  - NOSMP (in NOSMP mode it will also work on mips isa 1
+ *                            cpus that support LL and SC, see MIPS_HAS_LLSC
+ *                            in atomic_ops.h)
+ *                   - __CPU_MIPS64 (mips64 arch., in 64 bit mode: long and
+ *                                    void* are 64 bits)
+ *                   - __CPU_MIPS2 or __CPU_MIPS && MIPS_HAS_LLSC && NOSMP
+ *                                 (if __CPU_MIPS64 is not defined)
+ */
+/* 
+ * History:
+ * --------
+ *  2006-03-08  created by andrei
+ */
+
+
+#ifndef _atomic_mips2_h
+#define _atomic_mips2_h
+
+#define HAVE_ASM_INLINE_ATOMIC_OPS
+#define HAVE_ASM_INLINE_MEMBAR
+
+#ifdef __CPU_mips64
+#warning mips64 atomic code was not tested, please report problems to \
+		[email protected] or [email protected]
+#endif
+
+#ifdef NOSMP
+#define membar() asm volatile ("" : : : "memory") /* gcc do not cache barrier*/
+#define membar_read()  membar()
+#define membar_write() membar()
+#else
+
+#define membar() \
+	asm volatile( \
+			".set push \n\t" \
+			".set noreorder \n\t" \
+			".set mips2 \n\t" \
+			"    sync\n\t" \
+			".set pop \n\t" \
+			: : : "memory" \
+			) 
+
+#define membar_read()  membar()
+#define membar_write() membar()
+
+#endif /* NOSMP */
+
+
+
+/* main asm block */
+#define ATOMIC_ASM_OP_int(op) \
+			".set push \n\t" \
+			".set noreorder \n\t" \
+			".set mips2 \n\t" \
+			"1:   ll %1, %0 \n\t" \
+			"     " op "\n\t" \
+			"     sc %2, %0 \n\t" \
+			"     beqz %2, 1b \n\t" \
+			"     nop \n\t" /* delay slot */ \
+			".set pop \n\t" 
+
+#ifdef __CPU_mips64
+#define ATOMIC_ASM_OP_long(op) \
+			".set push \n\t" \
+			".set noreorder \n\t" \
+			"1:   lld %1, %0 \n\t" \
+			"     " op "\n\t" \
+			"     scd %2, %0 \n\t" \
+			"     beqz %2, 1b \n\t" \
+			"     nop \n\t" /* delay slot */ \
+			".set pop \n\t" 
+#else /* ! __CPU_mips64 => __CPU_mips2 or __CPU_mips & MIPS_HAS_LLSC */
+#define ATOMIC_ASM_OP_long(op) ATOMIC_ASM_OP_int(op)
+#endif
+
+
+#define ATOMIC_FUNC_DECL(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
+	inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var) \
+	{ \
+		P_TYPE ret, tmp; \
+		asm volatile( \
+			ATOMIC_ASM_OP_##P_TYPE(OP) \
+			: "=m"(*var), "=&r"(ret), "=&r"(tmp)  \
+			: "m"(*var) \
+			 \
+			); \
+		return RET_EXPR; \
+	}
+
+
+/* same as above, but with CT in %3 */
+#define ATOMIC_FUNC_DECL_CT(NAME, OP, CT, P_TYPE, RET_TYPE, RET_EXPR) \
+	inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var) \
+	{ \
+		P_TYPE ret, tmp; \
+		asm volatile( \
+			ATOMIC_ASM_OP_##P_TYPE(OP) \
+			: "=m"(*var), "=&r"(ret), "=&r"(tmp)  \
+			: "r"((CT)), "m"(*var) \
+			 \
+			); \
+		return RET_EXPR; \
+	}
+
+
+/* takes an extra param, i which goes in %3 */
+#define ATOMIC_FUNC_DECL1(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
+	inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
+														P_TYPE i) \
+	{ \
+		P_TYPE ret, tmp; \
+		asm volatile( \
+			ATOMIC_ASM_OP_##P_TYPE(OP) \
+			: "=m"(*var), "=&r"(ret), "=&r"(tmp)  \
+			: "r"((i)), "m"(*var) \
+			 \
+			); \
+		return RET_EXPR; \
+	}
+
+
+/* takes an extra param, like above, but i  goes in %2 */
+#define ATOMIC_FUNC_DECL2(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
+	inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
+														P_TYPE i) \
+	{ \
+		P_TYPE ret; \
+		asm volatile( \
+			ATOMIC_ASM_OP_##P_TYPE(OP) \
+			: "=m"(*var), "=&r"(ret), "+&r"(i)  \
+			: "m"(*var) \
+			 \
+			); \
+		return RET_EXPR; \
+	}
+
+
+
+ATOMIC_FUNC_DECL(inc,      "addiu %2, %1, 1", int, void, /* no return */ )
+ATOMIC_FUNC_DECL_CT(dec,   "subu %2, %1, %3", 1,  int, void, /* no return */ )
+ATOMIC_FUNC_DECL1(and, "and %2, %1, %3", int, void, /* no return */ )
+ATOMIC_FUNC_DECL1(or,  "or  %2, %1, %3", int, void,  /* no return */ )
+ATOMIC_FUNC_DECL(inc_and_test, "addiu %2, %1, 1", int, int, (ret+1)==0 )
+ATOMIC_FUNC_DECL_CT(dec_and_test, "subu %2, %1, %3", 1, int, int, (ret-1)==0 )
+ATOMIC_FUNC_DECL2(get_and_set, "" /* nothing needed */, int, int, ret )
+
+#ifdef __CPU_mips64
+
+ATOMIC_FUNC_DECL(inc,      "daddiu %2, %1, 1", long, void, /* no return */ )
+ATOMIC_FUNC_DECL_CT(dec,   "dsubu %2, %1, %3", 1,  long, void, /* no return */ )
+ATOMIC_FUNC_DECL1(and, "and %2, %1, %3", long, void, /* no return */ )
+ATOMIC_FUNC_DECL1(or,  "or  %2, %1, %3", long, void,  /* no return */ )
+ATOMIC_FUNC_DECL(inc_and_test, "daddiu %2, %1, 1", long, long, (ret+1)==0 )
+ATOMIC_FUNC_DECL_CT(dec_and_test, "dsubu %2, %1, %3", 1,long, long, (ret-1)==0 )
+ATOMIC_FUNC_DECL2(get_and_set, "" /* nothing needed */, long, long, ret )
+
+#else /* ! __CPU_mips64 => __CPU_mips2 or __CPU_mips */
+
+ATOMIC_FUNC_DECL(inc,      "addiu %2, %1, 1", long, void, /* no return */ )
+ATOMIC_FUNC_DECL_CT(dec,   "subu %2, %1, %3", 1,  long, void, /* no return */ )
+ATOMIC_FUNC_DECL1(and, "and %2, %1, %3", long, void, /* no return */ )
+ATOMIC_FUNC_DECL1(or,  "or  %2, %1, %3", long, void,  /* no return */ )
+ATOMIC_FUNC_DECL(inc_and_test, "addiu %2, %1, 1", long, long, (ret+1)==0 )
+ATOMIC_FUNC_DECL_CT(dec_and_test, "subu %2, %1, %3", 1,long, long, (ret-1)==0 )
+ATOMIC_FUNC_DECL2(get_and_set, "" /* nothing needed */, long, long, ret )
+
+#endif /* __CPU_mips64 */
+
+#define atomic_inc(var) atomic_inc_int(&(var)->val)
+#define atomic_dec(var) atomic_dec_int(&(var)->val)
+#define atomic_and(var, mask) atomic_and_int(&(var)->val, (mask))
+#define atomic_or(var, mask)  atomic_or_int(&(var)->val, (mask))
+#define atomic_dec_and_test(var) atomic_dec_and_test_int(&(var)->val)
+#define atomic_inc_and_test(var) atomic_inc_and_test_int(&(var)->val)
+#define atomic_get_and_set(var, i) atomic_get_and_set_int(&(var)->val, i)
+
+
+/* with integrated membar */
+
+#define mb_atomic_set_int(v, i) \
+	do{ \
+		membar(); \
+		atomic_set_int(v, i); \
+	}while(0)
+
+
+
+inline static int mb_atomic_get_int(volatile int* v)
+{
+	membar();
+	return atomic_get_int(v);
+}
+
+
+#define mb_atomic_inc_int(v) \
+	do{ \
+		membar(); \
+		atomic_inc_int(v); \
+	}while(0)
+
+#define mb_atomic_dec_int(v) \
+	do{ \
+		membar(); \
+		atomic_dec_int(v); \
+	}while(0)
+
+#define mb_atomic_or_int(v, m) \
+	do{ \
+		membar(); \
+		atomic_or_int(v, m); \
+	}while(0)
+
+#define mb_atomic_and_int(v, m) \
+	do{ \
+		membar(); \
+		atomic_and_int(v, m); \
+	}while(0)
+
+inline static int mb_atomic_inc_and_test_int(volatile int* v)
+{
+	membar();
+	return atomic_inc_and_test_int(v);
+}
+
+inline static int mb_atomic_dec_and_test_int(volatile int* v)
+{
+	membar();
+	return atomic_dec_and_test_int(v);
+}
+
+
+inline static int mb_atomic_get_and_set_int(volatile int* v, int i)
+{
+	membar();
+	return atomic_get_and_set_int(v, i);
+}
+
+
+
+#define mb_atomic_set_long(v, i) \
+	do{ \
+		membar(); \
+		atomic_set_long(v, i); \
+	}while(0)
+
+
+
+inline static long mb_atomic_get_long(volatile long* v)
+{
+	membar();
+	return atomic_get_long(v);
+}
+
+
+#define mb_atomic_inc_long(v) \
+	do{ \
+		membar(); \
+		atomic_inc_long(v); \
+	}while(0)
+
+
+#define mb_atomic_dec_long(v) \
+	do{ \
+		membar(); \
+		atomic_dec_long(v); \
+	}while(0)
+
+#define mb_atomic_or_long(v, m) \
+	do{ \
+		membar(); \
+		atomic_or_long(v, m); \
+	}while(0)
+
+#define mb_atomic_and_long(v, m) \
+	do{ \
+		membar(); \
+		atomic_and_long(v, m); \
+	}while(0)
+
+inline static long mb_atomic_inc_and_test_long(volatile long* v)
+{
+	membar();
+	return atomic_inc_and_test_long(v);
+}
+
+inline static long mb_atomic_dec_and_test_long(volatile long* v)
+{
+	membar();
+	return atomic_dec_and_test_long(v);
+}
+
+
+inline static long mb_atomic_get_and_set_long(volatile long* v, long l)
+{
+	membar();
+	return atomic_get_and_set_long(v, l);
+}
+
+
+#define mb_atomic_inc(var) mb_atomic_inc_int(&(var)->val)
+#define mb_atomic_dec(var) mb_atomic_dec_int(&(var)->val)
+#define mb_atomic_and(var, mask) mb_atomic_and_int(&(var)->val, (mask))
+#define mb_atomic_or(var, mask)  mb_atomic_or_int(&(var)->val, (mask))
+#define mb_atomic_dec_and_test(var) mb_atomic_dec_and_test_int(&(var)->val)
+#define mb_atomic_inc_and_test(var) mb_atomic_inc_and_test_int(&(var)->val)
+#define mb_atomic_get(var)	mb_atomic_get_int(&(var)->val)
+#define mb_atomic_set(var, i)	mb_atomic_set_int(&(var)->val, i)
+#define mb_atomic_get_and_set(var, i) mb_atomic_get_and_set_int(&(var)->val, i)
+
+#endif

+ 296 - 0
atomic/atomic_ppc.h

@@ -0,0 +1,296 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2006 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+/*
+ *  atomic operations and memory barriers (powerpc and powerpc64 versions)
+ *  WARNING: atomic ops do not include memory barriers
+ *  see atomic_ops.h for more details 
+ *  WARNING: not tested on ppc64
+ *
+ *  Config defines:  - NOSMP
+ *                   - __CPU_ppc64  (powerpc64 w/ 64 bits long and void*)
+ *                   - __CPU_ppc    (powerpc or powerpc64 32bit mode)
+ */
+/* 
+ * History:
+ * --------
+ *  2006-03-24  created by andrei
+ */
+
+#ifndef _atomic_ppc_h
+#define _atomic_ppc_h
+
+#define HAVE_ASM_INLINE_ATOMIC_OPS
+#define HAVE_ASM_INLINE_MEMBAR
+
+#ifdef __CPU_ppc64
+#warning powerpc64 atomic code was not tested, please report problems to \
+		[email protected] or [email protected]
+#endif
+
+
+#ifdef NOSMP
+#define membar() asm volatile ("" : : : "memory") /* gcc do not cache barrier*/
+#define membar_read()  membar()
+#define membar_write() membar()
+#else
+#define membar() asm volatile ("sync \n\t" : : : "memory") 
+/* lwsync orders LoadLoad, LoadStore and StoreStore */
+#define membar_read() asm volatile ("lwsync \n\t" : : : "memory") 
+/* on "normal" cached mem. eieio orders StoreStore */
+#define membar_write() asm volatile ("eieio \n\t" : : : "memory") 
+#endif /* NOSMP */
+
+
+#define ATOMIC_ASM_OP0_int(op) \
+	"1: lwarx  %0, 0, %2 \n\t" \
+	"   " op " \n\t" \
+	"   stwcx. %0, 0, %2 \n\t" \
+	"   bne- 1b \n\t"
+
+#define ATOMIC_ASM_OP3_int(op) \
+	"1: lwarx  %0, 0, %2 \n\t" \
+	"   " op " \n\t" \
+	"   stwcx. %3, 0, %2 \n\t" \
+	"   bne- 1b \n\t"
+
+#ifdef __CPU_ppc64
+#define ATOMIC_ASM_OP0_long(op) \
+	"1: ldarx  %0, 0, %2 \n\t" \
+	"   " op " \n\t" \
+	"   stdcx. %0, 0, %2 \n\t" \
+	"   bne- 1b \n\t"
+
+#define ATOMIC_ASM_OP3_long(op) \
+	"1: ldarx  %0, 0, %2 \n\t" \
+	"   " op " \n\t" \
+	"   stdcx. %3, 0, %2 \n\t" \
+	"   bne- 1b \n\t"
+
+#else /* __CPU_ppc */
+#define ATOMIC_ASM_OP0_long ATOMIC_ASM_OP0_int
+#define ATOMIC_ASM_OP3_long ATOMIC_ASM_OP3_int
+#endif
+
+
+#define ATOMIC_FUNC_DECL(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
+	inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var) \
+	{ \
+		P_TYPE ret; \
+		asm volatile( \
+			ATOMIC_ASM_OP0_##P_TYPE(OP) \
+			: "=&r"(ret), "=m"(*var) : "r"(var) : "cc" \
+			); \
+		return RET_EXPR; \
+	}
+
+/* same as above, but takes an extra param, v, which goes in %3 */
+#define ATOMIC_FUNC_DECL1(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
+	inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
+															P_TYPE v) \
+	{ \
+		P_TYPE ret; \
+		asm volatile( \
+			ATOMIC_ASM_OP0_##P_TYPE(OP) \
+			: "=&r"(ret), "=m"(*var) : "r"(var), "r"(v)  : "cc" \
+			); \
+		return RET_EXPR; \
+	}
+
+/* same as above, but uses ATOMIC_ASM_OP3, v in %3 and %3 not changed */
+#define ATOMIC_FUNC_DECL3(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
+	inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
+															P_TYPE v) \
+	{ \
+		P_TYPE ret; \
+		asm volatile( \
+			ATOMIC_ASM_OP3_##P_TYPE(OP) \
+			: "=&r"(ret), "=m"(*var) : "r"(var), "r"(v)  : "cc" \
+			); \
+		return RET_EXPR; \
+	}
+
+
+
+ATOMIC_FUNC_DECL(inc,      "addic  %0, %0,  1", int, void, /* no return */ )
+ATOMIC_FUNC_DECL(dec,      "addic %0, %0,  -1", int, void, /* no return */ )
+ATOMIC_FUNC_DECL1(and,     "and     %0, %0, %3", int, void, /* no return */ )
+ATOMIC_FUNC_DECL1(or,      "or     %0, %0, %3", int, void, /* no return */ )
+ATOMIC_FUNC_DECL(inc_and_test, "addic   %0, %0, 1", int, int, (ret==0) )
+ATOMIC_FUNC_DECL(dec_and_test, "addic  %0, %0, -1", int, int, (ret==0) )
+ATOMIC_FUNC_DECL3(get_and_set, /* no extra op needed */ , int, int,  ret)
+
+ATOMIC_FUNC_DECL(inc,      "addic  %0, %0,  1", long, void, /* no return */ )
+ATOMIC_FUNC_DECL(dec,      "addic %0, %0,  -1", long, void, /* no return */ )
+ATOMIC_FUNC_DECL1(and,     "and     %0, %0, %3",long, void, /* no return */ )
+ATOMIC_FUNC_DECL1(or,      "or     %0, %0, %3", long, void, /* no return */ )
+ATOMIC_FUNC_DECL(inc_and_test, "addic   %0, %0, 1", long, long, (ret==0) )
+ATOMIC_FUNC_DECL(dec_and_test, "addic  %0, %0, -1", long, long, (ret==0) )
+ATOMIC_FUNC_DECL3(get_and_set, /* no extra op needed */ , long, long,  ret)
+
+
+#define atomic_inc(var) atomic_inc_int(&(var)->val)
+#define atomic_dec(var) atomic_dec_int(&(var)->val)
+#define atomic_and(var, mask) atomic_and_int(&(var)->val, (mask))
+#define atomic_or(var, mask)  atomic_or_int(&(var)->val, (mask))
+#define atomic_dec_and_test(var) atomic_dec_and_test_int(&(var)->val)
+#define atomic_inc_and_test(var) atomic_inc_and_test_int(&(var)->val)
+#define atomic_get_and_set(var, i) atomic_get_and_set_int(&(var)->val, i)
+
+
+/* with integrated membar */
+
+#define mb_atomic_set_int(v, i) \
+	do{ \
+		membar(); \
+		atomic_set_int(v, i); \
+	}while(0)
+
+
+
+inline static int mb_atomic_get_int(volatile int* v)
+{
+	membar();
+	return atomic_get_int(v);
+}
+
+
+#define mb_atomic_inc_int(v) \
+	do{ \
+		membar(); \
+		atomic_inc_int(v); \
+	}while(0)
+
+#define mb_atomic_dec_int(v) \
+	do{ \
+		membar(); \
+		atomic_dec_int(v); \
+	}while(0)
+
+#define mb_atomic_or_int(v, m) \
+	do{ \
+		membar(); \
+		atomic_or_int(v, m); \
+	}while(0)
+
+#define mb_atomic_and_int(v, m) \
+	do{ \
+		membar(); \
+		atomic_and_int(v, m); \
+	}while(0)
+
+inline static int mb_atomic_inc_and_test_int(volatile int* v)
+{
+	membar();
+	return atomic_inc_and_test_int(v);
+}
+
+inline static int mb_atomic_dec_and_test_int(volatile int* v)
+{
+	membar();
+	return atomic_dec_and_test_int(v);
+}
+
+
+inline static int mb_atomic_get_and_set_int(volatile int* v, int i)
+{
+	membar();
+	return atomic_get_and_set_int(v, i);
+}
+
+
+
+#define mb_atomic_set_long(v, i) \
+	do{ \
+		membar(); \
+		atomic_set_long(v, i); \
+	}while(0)
+
+
+
+inline static long mb_atomic_get_long(volatile long* v)
+{
+	membar();
+	return atomic_get_long(v);
+}
+
+
+#define mb_atomic_inc_long(v) \
+	do{ \
+		membar(); \
+		atomic_inc_long(v); \
+	}while(0)
+
+
+#define mb_atomic_dec_long(v) \
+	do{ \
+		membar(); \
+		atomic_dec_long(v); \
+	}while(0)
+
+#define mb_atomic_or_long(v, m) \
+	do{ \
+		membar(); \
+		atomic_or_long(v, m); \
+	}while(0)
+
+#define mb_atomic_and_long(v, m) \
+	do{ \
+		membar(); \
+		atomic_and_long(v, m); \
+	}while(0)
+
+inline static long mb_atomic_inc_and_test_long(volatile long* v)
+{
+	membar();
+	return atomic_inc_and_test_long(v);
+}
+
+inline static long mb_atomic_dec_and_test_long(volatile long* v)
+{
+	membar();
+	return atomic_dec_and_test_long(v);
+}
+
+
+inline static long mb_atomic_get_and_set_long(volatile long* v, long l)
+{
+	membar();
+	return atomic_get_and_set_long(v, l);
+}
+
+
+#define mb_atomic_inc(var) mb_atomic_inc_int(&(var)->val)
+#define mb_atomic_dec(var) mb_atomic_dec_int(&(var)->val)
+#define mb_atomic_and(var, mask) mb_atomic_and_int(&(var)->val, (mask))
+#define mb_atomic_or(var, mask)  mb_atomic_or_int(&(var)->val, (mask))
+#define mb_atomic_dec_and_test(var) mb_atomic_dec_and_test_int(&(var)->val)
+#define mb_atomic_inc_and_test(var) mb_atomic_inc_and_test_int(&(var)->val)
+#define mb_atomic_get(var)	mb_atomic_get_int(&(var)->val)
+#define mb_atomic_set(var, i)	mb_atomic_set_int(&(var)->val, i)
+#define mb_atomic_get_and_set(var, i) mb_atomic_get_and_set_int(&(var)->val, i)
+
+#endif

+ 60 - 0
atomic/atomic_sparc.h

@@ -0,0 +1,60 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2006 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+/*
+ *  memory barriers for sparc32 ( version < v 9))
+ *  see atomic_ops.h for more details 
+ *
+ * Config defines: NOSMP
+ */
+/* 
+ * History:
+ * --------
+ *  2006-03-28  created by andrei
+ */
+
+
+#ifndef _atomic_sparc_h
+#define _atomic_sparc_h
+
+#define HAVE_ASM_INLINE_MEMBAR
+
+
+#warning "sparc32 atomic operations support not tested"
+
+#ifdef NOSMP
+#define membar() asm volatile ("" : : : "memory") /* gcc do not cache barrier*/
+#define membar_read()  membar()
+#define membar_write() membar()
+#else /* SMP */
+#define membar_write() asm volatile ("stbar \n\t" : : : "memory") 
+#define membar() membar_write()
+#define membar_read() asm volatile ("" : : : "memory") 
+#endif /* NOSMP */
+
+
+
+#endif

+ 286 - 0
atomic/atomic_sparc64.h

@@ -0,0 +1,286 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2006 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+/*
+ *  atomic operations and memory barriers (sparc64 version, 32 and 64 bit modes)
+ *  WARNING: atomic ops do not include memory barriers
+ *  see atomic_ops.h for more details 
+ *
+ *  Config defs: - SPARC64_MODE (if defined long is assumed to be 64 bits
+ *                               else long & void* are assumed to be 32 for
+ *                               sparc32plus code)
+ *               - NOSMP
+ */
+/* 
+ * History:
+ * --------
+ *  2006-03-28  created by andrei
+ */
+
+
+#ifndef _atomic_sparc64_h
+#define _atomic_sparc64_h
+
+#define HAVE_ASM_INLINE_ATOMIC_OPS
+#define HAVE_ASM_INLINE_MEMBAR
+
+
+
+/* try to guess if in SPARC64_MODE */
+#if ! defined SPARC64_MODE && \
+	(defined __LP64__ || defined _LP64 || defined __arch64__)
+#define SPARC64_MODE
+#endif
+
+
+#ifdef NOSMP
+#define membar() asm volatile ("" : : : "memory") /* gcc do not cache barrier*/
+#define membar_read()  membar()
+#define membar_write() membar()
+#else /* SMP */
+#define membar() \
+	asm volatile ( \
+			"membar #LoadLoad | #LoadStore | #StoreStore | #StoreLoad \n\t" \
+			: : : "memory")
+
+#define membar_read() asm volatile ("membar #LoadLoad \n\t" : : : "memory")
+#define membar_write() asm volatile ("membar #StoreStore \n\t" : : : "memory")
+#endif /* NOSMP */
+
+
+
+/* 32 bit version, op should store the result in %1, and use %0 as input,
+ *  both %0 and %1 are modified */
+#define ATOMIC_ASM_OP_int(op)\
+	"   ldsw [%3], %0 \n\t"  /* signed or lduw? */ \
+	"1: " op " \n\t" \
+	"   cas  [%3], %0, %1 \n\t" \
+	"   cmp %0, %1 \n\t" \
+	"   bne,a,pn  %%icc, 1b \n\t"  /* predict not taken, annul */ \
+	"   mov %1, %0\n\t"  /* delay slot */
+
+#ifdef SPARC64_MODE
+/* 64 bit version, same as above */
+#define ATOMIC_ASM_OP_long(op)\
+	"   ldx [%3], %0 \n\t" \
+	"1: " op " \n\t" \
+	"   casx  [%3], %0, %1 \n\t" \
+	"   cmp %0, %1 \n\t" \
+	"   bne,a,pn  %%xcc, 1b \n\t"  /* predict not taken, annul */ \
+	"   mov %1, %0\n\t"  /* delay slot */
+	
+#else /* no SPARC64_MODE => 32bit mode on a sparc64*/
+#define ATOMIC_ASM_OP_long(op) ATOMIC_ASM_OP_int(op)
+#endif
+
+#define ATOMIC_FUNC_DECL(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
+	inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var) \
+	{ \
+		P_TYPE ret, tmp; \
+		asm volatile( \
+			ATOMIC_ASM_OP_##P_TYPE(OP) \
+			: "=&r"(ret), "=&r"(tmp), "=m"(*var) : "r"(var) : "cc" \
+			); \
+		return RET_EXPR; \
+	}
+
+
+/* same as above, but takes an extra param, v, which goes in %4 */
+#define ATOMIC_FUNC_DECL1(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
+	inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
+															P_TYPE v) \
+	{ \
+		P_TYPE ret, tmp; \
+		asm volatile( \
+			ATOMIC_ASM_OP_##P_TYPE(OP) \
+			: "=&r"(ret), "=&r"(tmp), "=m"(*var) : "r"(var), "r"(v) : "cc" \
+			); \
+		return RET_EXPR; \
+	}
+
+
+
+
+ATOMIC_FUNC_DECL(inc,      "add  %0,  1, %1", int, void, /* no return */ )
+ATOMIC_FUNC_DECL(dec,      "sub  %0,  1, %1", int, void, /* no return */ )
+ATOMIC_FUNC_DECL1(and,     "and  %0, %4, %1", int, void, /* no return */ )
+ATOMIC_FUNC_DECL1(or,      "or   %0, %4, %1", int, void, /* no return */ )
+ATOMIC_FUNC_DECL(inc_and_test, "add   %0, 1, %1", int, int, ((ret+1)==0) )
+ATOMIC_FUNC_DECL(dec_and_test, "sub   %0, 1, %1", int, int, ((ret-1)==0) )
+ATOMIC_FUNC_DECL1(get_and_set, "mov %4, %1" , int, int,  ret)
+
+
+ATOMIC_FUNC_DECL(inc,      "add  %0,  1, %1", long, void, /* no return */ )
+ATOMIC_FUNC_DECL(dec,      "sub  %0,  1, %1", long, void, /* no return */ )
+ATOMIC_FUNC_DECL1(and,     "and  %0, %4, %1", long, void, /* no return */ )
+ATOMIC_FUNC_DECL1(or,      "or   %0, %4, %1", long, void, /* no return */ )
+ATOMIC_FUNC_DECL(inc_and_test, "add   %0, 1, %1", long, long, ((ret+1)==0) )
+ATOMIC_FUNC_DECL(dec_and_test, "sub   %0, 1, %1", long, long, ((ret-1)==0) )
+ATOMIC_FUNC_DECL1(get_and_set, "mov %4, %1" , long, long,  ret)
+
+
+#define atomic_inc(var) atomic_inc_int(&(var)->val)
+#define atomic_dec(var) atomic_dec_int(&(var)->val)
+#define atomic_and(var, mask) atomic_and_int(&(var)->val, (mask))
+#define atomic_or(var, mask)  atomic_or_int(&(var)->val, (mask))
+#define atomic_dec_and_test(var) atomic_dec_and_test_int(&(var)->val)
+#define atomic_inc_and_test(var) atomic_inc_and_test_int(&(var)->val)
+#define atomic_get_and_set(var, i) atomic_get_and_set_int(&(var)->val, i)
+
+
+/* with integrated membar */
+
+#define mb_atomic_set_int(v, i) \
+	do{ \
+		membar(); \
+		atomic_set_int(v, i); \
+	}while(0)
+
+
+
+inline static int mb_atomic_get_int(volatile int* v)
+{
+	membar();
+	return atomic_get_int(v);
+}
+
+
+#define mb_atomic_inc_int(v) \
+	do{ \
+		membar(); \
+		atomic_inc_int(v); \
+	}while(0)
+
+#define mb_atomic_dec_int(v) \
+	do{ \
+		membar(); \
+		atomic_dec_int(v); \
+	}while(0)
+
+#define mb_atomic_or_int(v, m) \
+	do{ \
+		membar(); \
+		atomic_or_int(v, m); \
+	}while(0)
+
+#define mb_atomic_and_int(v, m) \
+	do{ \
+		membar(); \
+		atomic_and_int(v, m); \
+	}while(0)
+
+inline static int mb_atomic_inc_and_test_int(volatile int* v)
+{
+	membar();
+	return atomic_inc_and_test_int(v);
+}
+
+inline static int mb_atomic_dec_and_test_int(volatile int* v)
+{
+	membar();
+	return atomic_dec_and_test_int(v);
+}
+
+
+inline static int mb_atomic_get_and_set_int(volatile int* v, int i)
+{
+	membar();
+	return atomic_get_and_set_int(v, i);
+}
+
+
+
+#define mb_atomic_set_long(v, i) \
+	do{ \
+		membar(); \
+		atomic_set_long(v, i); \
+	}while(0)
+
+
+
+inline static long mb_atomic_get_long(volatile long* v)
+{
+	membar();
+	return atomic_get_long(v);
+}
+
+
+#define mb_atomic_inc_long(v) \
+	do{ \
+		membar(); \
+		atomic_inc_long(v); \
+	}while(0)
+
+
+#define mb_atomic_dec_long(v) \
+	do{ \
+		membar(); \
+		atomic_dec_long(v); \
+	}while(0)
+
+#define mb_atomic_or_long(v, m) \
+	do{ \
+		membar(); \
+		atomic_or_long(v, m); \
+	}while(0)
+
+#define mb_atomic_and_long(v, m) \
+	do{ \
+		membar(); \
+		atomic_and_long(v, m); \
+	}while(0)
+
+inline static long mb_atomic_inc_and_test_long(volatile long* v)
+{
+	membar();
+	return atomic_inc_and_test_long(v);
+}
+
+inline static long mb_atomic_dec_and_test_long(volatile long* v)
+{
+	membar();
+	return atomic_dec_and_test_long(v);
+}
+
+
+inline static long mb_atomic_get_and_set_long(volatile long* v, long l)
+{
+	membar();
+	return atomic_get_and_set_long(v, l);
+}
+
+
+#define mb_atomic_inc(var) mb_atomic_inc_int(&(var)->val)
+#define mb_atomic_dec(var) mb_atomic_dec_int(&(var)->val)
+#define mb_atomic_and(var, mask) mb_atomic_and_int(&(var)->val, (mask))
+#define mb_atomic_or(var, mask)  mb_atomic_or_int(&(var)->val, (mask))
+#define mb_atomic_dec_and_test(var) mb_atomic_dec_and_test_int(&(var)->val)
+#define mb_atomic_inc_and_test(var) mb_atomic_inc_and_test_int(&(var)->val)
+#define mb_atomic_get(var)	mb_atomic_get_int(&(var)->val)
+#define mb_atomic_set(var, i)	mb_atomic_set_int(&(var)->val, i)
+#define mb_atomic_get_and_set(var, i) mb_atomic_get_and_set_int(&(var)->val, i)
+
+#endif

+ 233 - 0
atomic/atomic_unknown.h

@@ -0,0 +1,233 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2006 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+/*
+ *  atomic operations and memory barriers implemented using locks
+ *  (for architectures not yet supported via inline asm)
+ *
+ *  WARNING: atomic ops do not include memory barriers
+ *  see atomic_ops.h for more details 
+ *
+ *  Config defs: - NOSMP (membars are null in this case)
+ *               - HAVE_ASM_INLINE_MEMBAR (membars arleady defined =>
+ *                                          use them)
+ *               - HAVE_ASM_INLINE_ATOMIC_OPS (atomic ops already defined
+ *                                               => don't redefine them)
+ *
+ */
+/* 
+ * History:
+ * --------
+ *  2006-03-08  created by andrei
+ */
+
+#ifndef _atomic_unknown_h
+#define _atomic_unknown_h
+
+#include "../lock_ops.h"
+
+extern gen_lock_t* _atomic_lock; /* declared and init in ../atomic.c */
+
+#define atomic_lock    lock_get(_atomic_lock)
+#define atomic_unlock  lock_release(_atomic_lock)
+
+
+#ifndef HAVE_ASM_INLINE_MEMBAR
+
+#define ATOMIC_OPS_USE_LOCK
+
+
+#ifdef NOSMP
+#define membar()
+#else /* SMP */
+
+#warning no native memory barrier implementations, falling back to slow lock \
+	       based workarround
+
+/* memory barriers 
+ *  not a known cpu -> fall back lock/unlock: safe but costly  (it should 
+ *  include a memory barrier effect) */
+#define membar() \
+	do{\
+		atomic_lock; \
+		atomic_unlock; \
+	} while(0)
+#endif /* NOSMP */
+
+
+#define membar_write() membar()
+
+#define membar_read()  membar()
+
+#endif /* HAVE_ASM_INLINE_MEMBAR */
+
+
+#ifndef HAVE_ASM_INLINE_ATOMIC_OPS
+
+#ifndef ATOMIC_OPS_USE_LOCK
+#define ATOMIC_OPS_USE_LOCK
+#endif
+
+/* atomic ops */
+
+
+/* OP can include var (function param), no other var. is declared */
+#define ATOMIC_FUNC_DECL(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
+	inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var) \
+	{ \
+		atomic_lock; \
+		OP ; \
+		atomic_unlock; \
+		return RET_EXPR; \
+	}
+
+
+/* like above, but takes an extra param: v =>
+ *  OP can use var and v (function params) */
+#define ATOMIC_FUNC_DECL1(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
+	inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
+														P_TYPE v) \
+	{ \
+		atomic_lock; \
+		OP ; \
+		atomic_unlock; \
+		return RET_EXPR; \
+	}
+
+/* OP can include var (function param), and ret (return)
+ *  ( like ATOMIC_FUNC_DECL, but includes ret) */
+#define ATOMIC_FUNC_DECL_RET(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
+	inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var) \
+	{ \
+		P_TYPE ret; \
+		atomic_lock; \
+		OP ; \
+		atomic_unlock; \
+		return RET_EXPR; \
+	}
+
+/* like ATOMIC_FUNC_DECL1, but declares an extra variable: P_TYPE ret */
+#define ATOMIC_FUNC_DECL1_RET(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
+	inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
+														P_TYPE v) \
+	{ \
+		P_TYPE ret; \
+		atomic_lock; \
+		OP ; \
+		atomic_unlock; \
+		return RET_EXPR; \
+	}
+
+ATOMIC_FUNC_DECL(inc,      (*var)++, int, void, /* no return */ )
+ATOMIC_FUNC_DECL(dec,      (*var)--, int, void, /* no return */ )
+ATOMIC_FUNC_DECL1(and,     *var&=v, int, void, /* no return */ )
+ATOMIC_FUNC_DECL1(or,      *var|=v, int, void, /* no return */ )
+ATOMIC_FUNC_DECL_RET(inc_and_test, ret=++(*var), int, int, (ret==0) )
+ATOMIC_FUNC_DECL_RET(dec_and_test, ret=--(*var), int, int, (ret==0) )
+ATOMIC_FUNC_DECL1_RET(get_and_set, ret=*var;*var=v , int, int,  ret)
+
+ATOMIC_FUNC_DECL(inc,      (*var)++, long, void, /* no return */ )
+ATOMIC_FUNC_DECL(dec,      (*var)--, long, void, /* no return */ )
+ATOMIC_FUNC_DECL1(and,     *var&=v, long, void, /* no return */ )
+ATOMIC_FUNC_DECL1(or,      *var|=v, long, void, /* no return */ )
+ATOMIC_FUNC_DECL_RET(inc_and_test, ret=++(*var), long, long, (ret==0) )
+ATOMIC_FUNC_DECL_RET(dec_and_test, ret=--(*var), long, long, (ret==0) )
+ATOMIC_FUNC_DECL1_RET(get_and_set, ret=*var;*var=v , long, long,  ret)
+
+
+#define atomic_inc(var) atomic_inc_int(&(var)->val)
+#define atomic_dec(var) atomic_dec_int(&(var)->val)
+#define atomic_and(var, mask) atomic_and_int(&(var)->val, (mask))
+#define atomic_or(var, mask)  atomic_or_int(&(var)->val, (mask))
+#define atomic_dec_and_test(var) atomic_dec_and_test_int(&(var)->val)
+#define atomic_inc_and_test(var) atomic_inc_and_test_int(&(var)->val)
+#define atomic_get_and_set(var, i) atomic_get_and_set_int(&(var)->val, i)
+
+
+/* memory barrier versions, the same as "normal" versions (since the
+ *  locks act as membars), *  except fot * the set/get 
+ */
+
+/* mb_atomic_{set,get} use membar() : if we're lucky we have membars
+ * for the arch. (e.g. sparc32) => membar() might be cheaper then lock/unlock */
+#define mb_atomic_set_int(v, i) \
+	do{ \
+		membar(); \
+		atomic_set_int(v, i); \
+	}while(0)
+
+inline static int  mb_atomic_get_int(volatile int* v)
+{
+		membar();
+		return atomic_get_int(v);
+}
+
+
+#define mb_atomic_set_long(v, i) \
+	do{ \
+		membar(); \
+		atomic_set_long(v, i); \
+	}while(0)
+
+inline static long mb_atomic_get_long(volatile long* v)
+{
+		membar();
+		return atomic_get_long(v);
+}
+
+
+/* the rest are the same as the non membar version (the locks have a membar
+ * effect) */
+#define mb_atomic_inc_int(v)	atomic_inc_int(v)
+#define mb_atomic_dec_int(v)	atomic_dec_int(v)
+#define mb_atomic_or_int(v, m)	atomic_or_int(v, m)
+#define mb_atomic_and_int(v, m)	atomic_and_int(v, m)
+#define mb_atomic_inc_and_test_int(v)	atomic_inc_and_test_int(v)
+#define mb_atomic_dec_and_test_int(v)	atomic_dec_and_test_int(v)
+#define mb_atomic_get_and_set_int(v, i)	atomic_get_and_set_int(v, i)
+
+#define mb_atomic_inc_long(v)	atomic_inc_long(v)
+#define mb_atomic_dec_long(v)	atomic_dec_long(v)
+#define mb_atomic_or_long(v, m)	atomic_or_long(v, m)
+#define mb_atomic_and_long(v, m)	atomic_and_long(v, m)
+#define mb_atomic_inc_and_test_long(v)	atomic_inc_and_test_long(v)
+#define mb_atomic_dec_and_test_long(v)	atomic_dec_and_test_long(v)
+#define mb_atomic_get_and_set_long(v, i)	atomic_get_and_set_long(v, i)
+
+#define mb_atomic_inc(var) mb_atomic_inc_int(&(var)->val)
+#define mb_atomic_dec(var) mb_atomic_dec_int(&(var)->val)
+#define mb_atomic_and(var, mask) mb_atomic_and_int(&(var)->val, (mask))
+#define mb_atomic_or(var, mask)  mb_atomic_or_int(&(var)->val, (mask))
+#define mb_atomic_dec_and_test(var) mb_atomic_dec_and_test_int(&(var)->val)
+#define mb_atomic_inc_and_test(var) mb_atomic_inc_and_test_int(&(var)->val)
+#define mb_atomic_get_and_set(var, i) mb_atomic_get_and_set_int(&(var)->val, i)
+
+#define mb_atomic_get(var)	mb_atomic_get_int(&(var)->val)
+#define mb_atomic_set(var, i)	mb_atomic_set_int(&(var)->val, i)
+
+#endif /* if HAVE_ASM_INLINE_ATOMIC_OPS */
+
+#endif

+ 294 - 0
atomic/atomic_x86.h

@@ -0,0 +1,294 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2006 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+/*
+ *  atomic operations and memory barriers (x86 and x86_64/amd64 specific)
+ *  WARNING: atomic ops do not include memory barriers
+ *  see atomic_ops.h for more details 
+ *
+ *  Config defines:   - NOSMP
+ *                    - X86_OOSTORE (out of order store, defined by default)
+ *                    - __CPU_x86_64 (64 bit mode, long and void* is 64 bit and
+ *                                    the cpu has all of the mfence, lfence
+ *                                    and sfence instructions)
+ *                    - __CPU_i386  (486+, 32 bit)
+ */
+/* 
+ * History:
+ * --------
+ *  2006-03-08  created by andrei
+ */
+
+#ifndef _atomic_x86_h
+#define _atomic_x86_h
+
+#define HAVE_ASM_INLINE_ATOMIC_OPS
+#define HAVE_ASM_INLINE_MEMBAR
+
+#ifdef NOSMP
+#define __LOCK_PREF 
+#else
+#define __LOCK_PREF "lock ;"
+#endif
+
+
+/* memory barriers */
+
+#ifdef NOSMP
+
+#define membar()	asm volatile ("" : : : "memory")
+#define membar_read()	membar()
+#define membar_write()	membar()
+
+#else
+
+/* although most x86 do stores in order, we're playing it safe and use
+ *  oostore ready write barriers */
+#define X86_OOSTORE 
+
+#ifdef __CPU_x86_64
+/*
+#define membar() \
+	asm volatile( \
+					" lock; addq $0, 0(%%rsp) \n\t " \
+					: : : "memory" \
+				) 
+*/
+#define membar() 		asm volatile( " mfence \n\t " : : : "memory" )
+#define membar_read()	asm volatile( " lfence \n\t " : : : "memory" )
+#ifdef X86_OOSTORE
+#define membar_write()	asm volatile( " sfence \n\t " : : : "memory" )
+#else
+#define membar_write()	asm volatile ("" : : : "memory") /* gcc don't cache*/
+#endif /* X86_OOSTORE */
+
+#else /* ! __CPU_x86_64  => __CPU_i386*/
+/* membar: lfence, mfence, sfence available only on newer cpus, so for now
+ * stick to lock addl */
+#define membar() asm volatile(" lock; addl $0, 0(%%esp) \n\t " : : : "memory" )
+#define membar_read()	membar()
+#ifdef X86_OOSTORE
+/* out of order store version */
+#define membar_write()	membar()
+#else
+/* no oostore, most x86 cpus => do nothing, just a gcc do_not_cache barrier*/
+#define membar_write()	asm volatile ("" : : : "memory")
+#endif /* X86_OOSTORE */
+
+#endif /* __CPU_x86_64 */
+
+
+
+
+
+#endif /* NOSMP */
+
+/* 1 param atomic f */
+#define ATOMIC_FUNC_DECL1(NAME, OP, P_TYPE) \
+	inline static void atomic_##NAME##_##P_TYPE (volatile P_TYPE* var) \
+	{ \
+		asm volatile( \
+				__LOCK_PREF " " OP " \n\t" \
+				: "=m"(*var) : "m"(*var) : "cc", "memory" \
+				); \
+	}
+
+/* 2 params atomic f */
+#define ATOMIC_FUNC_DECL2(NAME, OP, P_TYPE) \
+	inline static void atomic_##NAME##_##P_TYPE (volatile P_TYPE* var, \
+			                                    P_TYPE v) \
+	{ \
+		asm volatile( \
+				__LOCK_PREF " " OP " \n\t" \
+				: "=m"(*var) : "ri" (v), "m"(*var) : "cc", "memory" \
+				); \
+	}
+
+#define ATOMIC_FUNC_XCHG(NAME, OP, TYPE) \
+	inline static TYPE atomic_##NAME##_##TYPE(volatile TYPE* var, TYPE v) \
+{ \
+	asm volatile( \
+			OP " \n\t" \
+			: "+q"(v), "=m"(*var) : "m"(*var) : "memory" \
+			); \
+	return v; \
+}
+
+/* returns a value, 1 param */
+#define ATOMIC_FUNC_TEST(NAME, OP, P_TYPE, RET_TYPE) \
+	inline static RET_TYPE atomic_##NAME##_##P_TYPE(volatile P_TYPE* var) \
+	{ \
+		char ret; \
+		asm volatile( \
+				__LOCK_PREF " " OP "\n\t" \
+				"setz %1 \n\t" \
+				: "=m" (*var), "=qm"(ret) : "m"(*var) : "cc", "memory" \
+				); \
+		return ret; \
+	}
+
+ATOMIC_FUNC_DECL1(inc, "incl %0", int)
+ATOMIC_FUNC_DECL1(dec, "decl %0", int)
+ATOMIC_FUNC_DECL2(and, "andl %1, %0", int)
+ATOMIC_FUNC_DECL2(or,  "orl %1, %0", int)
+ATOMIC_FUNC_TEST(inc_and_test, "incl %0", int, int)
+ATOMIC_FUNC_TEST(dec_and_test, "decl %0", int, int)
+ATOMIC_FUNC_XCHG(get_and_set,  "xchgl %1, %0", int)
+#ifdef __CPU_x86_64
+ATOMIC_FUNC_DECL1(inc, "incq %0", long)
+ATOMIC_FUNC_DECL1(dec, "decq %0", long)
+ATOMIC_FUNC_DECL2(and, "andq %1, %0", long)
+ATOMIC_FUNC_DECL2(or,  "orq %1, %0", long)
+ATOMIC_FUNC_TEST(inc_and_test, "incq %0", long, int)
+ATOMIC_FUNC_TEST(dec_and_test, "decq %0", long, int)
+ATOMIC_FUNC_XCHG(get_and_set,  "xchgq %1, %0", long)
+#else
+ATOMIC_FUNC_DECL1(inc, "incl %0", long)
+ATOMIC_FUNC_DECL1(dec, "decl %0", long)
+ATOMIC_FUNC_DECL2(and, "andl %1, %0", long)
+ATOMIC_FUNC_DECL2(or,  "orl %1, %0", long)
+ATOMIC_FUNC_TEST(inc_and_test, "incl %0", long, int)
+ATOMIC_FUNC_TEST(dec_and_test, "decl %0", long, int)
+ATOMIC_FUNC_XCHG(get_and_set,  "xchgl %1, %0", long)
+#endif
+
+#define atomic_inc(var) atomic_inc_int(&(var)->val)
+#define atomic_dec(var) atomic_dec_int(&(var)->val)
+#define atomic_and(var, mask) atomic_and_int(&(var)->val, (mask))
+#define atomic_or(var, mask)  atomic_or_int(&(var)->val, (mask))
+#define atomic_dec_and_test(var) atomic_dec_and_test_int(&(var)->val)
+#define atomic_inc_and_test(var) atomic_inc_and_test_int(&(var)->val)
+#define atomic_get_and_set(var, i) atomic_get_and_set_int(&(var)->val, i)
+
+
+#ifdef NOSMP
+
+#define mb_atomic_set_int(v, i) \
+	do{ \
+		membar(); atomic_set_int(v, i); \
+	}while(0)
+
+#define mb_atomic_set_long(v, i) \
+	do{ \
+		membar(); atomic_set_long(v, i); \
+	}while(0)
+
+
+
+inline static int mb_atomic_get_int(volatile int* v)
+{
+	membar(); return atomic_get_int(v);
+}
+
+inline static long mb_atomic_get_long(volatile long* v)
+{
+	membar(); return atomic_get_long(v);
+}
+
+
+#else /* NOSMP */
+
+
+inline static void mb_atomic_set_int(volatile int* v, int i)
+{
+	asm volatile(
+			"xchgl %1, %0 \n\t"
+			: "+q"(i), "=m"(*v) : "m"(*v) : "memory" 
+			);
+}
+
+
+inline static void mb_atomic_set_long(volatile long* v, long l)
+{
+	asm volatile(
+#ifdef __CPU_x86_64
+			"xchgq %1, %0 \n\t"
+#else
+			"xchgl %1, %0 \n\t"
+#endif
+			: "+q"(l), "=m"(*v) : "m"(*v) : "memory" 
+			);
+}
+
+
+inline static int mb_atomic_get_int(volatile int* var)
+{
+	int ret;
+	
+	asm volatile(
+			__LOCK_PREF " cmpxchgl %0, %1 \n\t"
+			: "=a"(ret)  : "m"(*var) : "cc", "memory"
+			);
+	return ret;
+}
+
+inline static long mb_atomic_get_long(volatile long* var)
+{
+	long ret;
+	
+	asm volatile(
+#ifdef __CPU_x86_64
+			__LOCK_PREF " cmpxchgq %0, %1 \n\t"
+#else
+			__LOCK_PREF " cmpxchgl %0, %1 \n\t"
+#endif
+			: "=a"(ret)  : "m"(*var) : "cc", "memory"
+			);
+	return ret;
+}
+
+#endif /* NOSMP */
+
+
+/* on x86 atomic intructions act also as barriers */
+#define mb_atomic_inc_int(v)	atomic_inc_int(v)
+#define mb_atomic_dec_int(v)	atomic_dec_int(v)
+#define mb_atomic_or_int(v, m)	atomic_or_int(v, m)
+#define mb_atomic_and_int(v, m)	atomic_and_int(v, m)
+#define mb_atomic_inc_and_test_int(v)	atomic_inc_and_test_int(v)
+#define mb_atomic_dec_and_test_int(v)	atomic_dec_and_test_int(v)
+#define mb_atomic_get_and_set_int(v, i)	atomic_get_and_set_int(v, i)
+
+#define mb_atomic_inc_long(v)	atomic_inc_long(v)
+#define mb_atomic_dec_long(v)	atomic_dec_long(v)
+#define mb_atomic_or_long(v, m)	atomic_or_long(v, m)
+#define mb_atomic_and_long(v, m)	atomic_and_long(v, m)
+#define mb_atomic_inc_and_test_long(v)	atomic_inc_and_test_long(v)
+#define mb_atomic_dec_and_test_long(v)	atomic_dec_and_test_long(v)
+#define mb_atomic_get_and_set_long(v, i)	atomic_get_and_set_long(v, i)
+
+#define mb_atomic_inc(v)	atomic_inc(v)
+#define mb_atomic_dec(v)	atomic_dec(v)
+#define mb_atomic_or(v, m)	atomic_or(v, m)
+#define mb_atomic_and(v, m)	atomic_and(v, m)
+#define mb_atomic_inc_and_test(v)	atomic_inc_and_test(v)
+#define mb_atomic_dec_and_test(v)	atomic_dec_and_test(v)
+#define mb_atomic_get(v)	mb_atomic_get_int( &(v)->val)
+#define mb_atomic_set(v, i)	mb_atomic_set_int(&(v)->val, i)
+#define mb_atomic_get_and_set(v, i)	atomic_get_and_set_int(&(v)->val, i)
+
+
+#endif

+ 20 - 5
atomic_ops.c

@@ -33,28 +33,31 @@
  *  2006-03-08  created by andrei
  */
 
+#include "atomic_ops_init.h"
 #include "atomic_ops.h"
 
-#ifdef ATOMIC_USE_LOCK
+#ifdef ATOMIC_OPS_USE_LOCK
+
+#include "locking.h"
+
 gen_lock_t* _atomic_lock;
 #endif
 
 
 /* returns 0 on success, -1 on error */
-int atomic_ops_init()
+int init_atomic_ops()
 {
 	int ret;
 	
 	ret=0;
-#ifdef ATOMIC_USE_LOCK
+#ifdef ATOMIC_OPS_USE_LOCK
 	if ((_atomic_lock=lock_alloc())==0){
 		ret=-1;
 		goto end;
 	}
 	if (lock_init(_atomic_lock)==0){
 		ret=-1;
-		lock_destroy(_atomic_lock);
-		_atomic_lock=0;
+		atomic_ops_destroy();
 		goto end;
 	}
 end:
@@ -62,3 +65,15 @@ end:
 	return ret;
 }
 
+
+
+void destroy_atomic_ops()
+{
+#ifdef ATOMIC_OPS_USE_LOCK
+	if (_atomic_lock!=0){
+		lock_destroy(_atomic_lock);
+		lock_dealloc(_atomic_lock);
+		_atomic_lock=0;
+	}
+#endif
+}

+ 64 - 412
atomic_ops.h

@@ -45,26 +45,52 @@
  *
  * not including memory barriers:
  *
- *  void atomic_set(atomic_t* v, long i)      -      v->val=i
- *  long atomic_get(atomic_t* v)              -       return v->val
+ *  void atomic_set(atomic_t* v, int i)      - v->val=i
+ *  int atomic_get(atomic_t* v)              - return v->val
+ *  int atomic_get_and_set(atomic_t *v, i)   - return old v->val, v->val=i
  *  void atomic_inc(atomic_t* v)
  *  void atomic_dec(atomic_t* v)
- *  long atomic_inc_and_test(atomic_t* v)     - returns 1 if the result is 0
- *  long atomic_dec_and_test(atomic_t* v)     - returns 1 if the result is 0
- *  void atomic_or (atomic_t* v, long mask)   - v->val|=mask 
- *  void atomic_and(atomic_t* v, long mask)   - v->val&=mask
+ *  int atomic_inc_and_test(atomic_t* v)     - returns 1 if the result is 0
+ *  int atomic_dec_and_test(atomic_t* v)     - returns 1 if the result is 0
+ *  void atomic_or (atomic_t* v, int mask)   - v->val|=mask 
+ *  void atomic_and(atomic_t* v, int mask)   - v->val&=mask
  * 
  * same ops, but with builtin memory barriers:
  *
- *  void mb_atomic_set(atomic_t* v, long i)      -      v->val=i
- *  long mb_atomic_get(atomic_t* v)              -       return v->val
+ *  void mb_atomic_set(atomic_t* v, int i)      -  v->val=i
+ *  int mb_atomic_get(atomic_t* v)              -  return v->val
+ *  int mb_atomic_get_and_set(atomic_t *v, i)   -  return old v->val, v->val=i
  *  void mb_atomic_inc(atomic_t* v)
  *  void mb_atomic_dec(atomic_t* v)
- *  long mb_atomic_inc_and_test(atomic_t* v)  - returns 1 if the result is 0
- *  long mb_atomic_dec_and_test(atomic_t* v)  - returns 1 if the result is 0
- *  void mb_atomic_or(atomic_t* v, long mask - v->val|=mask 
- *  void mb_atomic_and(atomic_t* v, long mask)- v->val&=mask
- * 
+ *  int mb_atomic_inc_and_test(atomic_t* v)  - returns 1 if the result is 0
+ *  int mb_atomic_dec_and_test(atomic_t* v)  - returns 1 if the result is 0
+ *  void mb_atomic_or(atomic_t* v, int mask - v->val|=mask 
+ *  void mb_atomic_and(atomic_t* v, int mask)- v->val&=mask
+ *
+ *  Same operations are available for int and long. The functions are named
+ *   after the following rules:
+ *     - add an int or long  suffix to the correspondent atomic function
+ *     -  volatile int* or volatile long* replace atomic_t* in the functions
+ *        declarations
+ *     -  long and int replace the parameter type (if the function has an extra
+ *        parameter) and the return value
+ *  E.g.:
+ *    long atomic_get_long(volatile long* v)
+ *    int atomic_get_int( volatile int* v)
+ *    long atomic_get_and_set(volatile long* v, long l)
+ *    int atomic_get_and_set(volatile int* v, int i)
+ *
+ * Config defines:   CC_GCC_LIKE_ASM  - the compiler support gcc style
+ *                     inline asm
+ *                   NOSMP - the code will be a little faster, but not SMP
+ *                            safe
+ *                   __CPU_i386, __CPU_x86_64, X86_OOSTORE - see 
+ *                       atomic/atomic_x86.h
+ *                   __CPU_mips, __CPU_mip2, __CPU_mip64, MIPS_HAS_LLSC - see
+ *                       atomic/atomic_mip2.h
+ *                   __CPU_ppc, __CPU_ppc64 - see atomic/atomic_ppc.h
+ *                   __CPU_sparc - see atomic/atomic_sparc.h
+ *                   __CPU_sparc64, SPARC64_MODE - see atomic/atomic_sparc64.h
  */
 /* 
  * History:
@@ -76,433 +102,59 @@
 
 /* atomic_t defined as a struct to easily catch non atomic ops. on it,
  * e.g.  atomic_t  foo; foo++  will generate a compile error */
-typedef struct{ volatile long val; } atomic_t; 
+typedef struct{ volatile int val; } atomic_t; 
 
 
 /* store and load operations are atomic on all cpus, note however that they
  * don't include memory barriers so if you want to use atomic_{get,set} 
- * to implement mutexes you must explicitely use the barriers */
-#define atomic_set(at_var, value)	((at_var)->val=(value))
-#define atomic_get(at_var) ((at_var)->val)
-
-/* init atomic ops */
-int atomic_ops_init();
-
-
-
-#if defined(__CPU_i386) || defined(__CPU_x86_64)
-
-#define HAVE_ASM_INLINE_ATOMIC_OPS
-
-#ifdef NOSMP
-#define __LOCK_PREF 
-#else
-#define __LOCK_PREF "lock ;"
-#endif
-
-
-/* memory barriers */
-
-#ifdef NOSMP
-
-#define membar()	asm volatile ("" : : : "memory")
-#define membar_read()	membar()
-#define membar_write()	membar()
+ * to implement mutexes you must use the mb_* versions or explicitely use
+ * the barriers */
 
-#else
+#define atomic_set_int(pvar, i) (*(pvar)=i)
+#define atomic_set_long(pvar, i) (*(pvar)=i)
+#define atomic_get_int(pvar) (*(pvar))
+#define atomic_get_long(pvar) (*(pvar))
 
-/* although most x86 do stores in order, we're playing it safe and use
- *  oostore ready write barriers */
-#define X86_OOSTORE 
+#define atomic_set(at_var, value)	(atomic_set_int(&((at_var)->val), (value)))
 
-/* membar: lfence, mfence, sfence available only on newer cpus, so for now
- * stick to lock addl */
-#define membar() \
-	asm volatile( \
-					" lock; addl $0, 0(%%esp) \n\t " \
-					: : : "memory" \
-				) 
-
-#define membar_read()	membar()
-
-#ifdef X86_OOSTORE
-/* out of order store version */
-#define membar_write()	membar()
-#else
-/* no oostore, most x86 cpus => do nothing, just a gcc do_not_cache barrier*/
-#define membar_write()	asm volatile ("" : : : "memory")
-#endif
-
-
-#endif /* NOSMP */
-
-
-#define atomic_inc(var) \
-	asm volatile( \
-			__LOCK_PREF " incl %0 \n\t"  \
-			: "=m"((var)->val) : "m"((var)->val) : "cc", "memory" \
-			) 
-
-#define atomic_dec(var) \
-	asm volatile( \
-			__LOCK_PREF " decl %0 \n\t" \
-			: "=m"((var)->val) : "m"((var)->val) : "cc", "memory" \
-			) 
-
-#define atomic_and(var, i) \
-	asm volatile( \
-			__LOCK_PREF " andl %1, %0 \n\t" \
-			: "=m"((var)->val) : "ri"((i)), "m"((var)->val) : "cc", "memory" \
-			)
-#define atomic_or(var, i) \
-	asm volatile( \
-			__LOCK_PREF " orl %1, %0 \n\t" \
-			: "=m"((var)->val) : "ri"((i)), "m"((var)->val) : "cc", "memory" \
-			)
-
-
-/* returns 1 if the result is 0 */
-inline static long atomic_inc_and_test(atomic_t* var)
+inline static int atomic_get(atomic_t *v)
 {
-	char ret;
-	
-	asm volatile(
-			__LOCK_PREF " incl %0 \n\t"
-			"setz  %1 \n\t"
-			: "=m"(var->val), "=qm"(ret) : "m" (var->val) : "cc", "memory"
-			);
-	return ret;
+	return atomic_get_int(&(v->val));
 }
 
 
-/* returns 1 if the result is 0 */
-inline static long atomic_dec_and_test(atomic_t* var)
-{
-	char ret;
-	
-	asm volatile(
-			__LOCK_PREF " decl %0 \n\t"
-			"setz  %1 \n\t"
-			: "=m"(var->val), "=qm"(ret) : "m" (var->val) : "cc", "memory"
-			);
-	return ret;
-}
-
-#ifdef NOSMP
-
-#define mb_atomic_set(v, i) \
-	do{ \
-		membar(); \
-		atomic_set(v, i); \
-	}while(0)
-
-
-inline static long mb_atomic_get(atomic_t* v)
-{
-	membar();
-	return atomic_get(v);
-}
-#else /* NOSMP */
-
-
-inline static void mb_atomic_set(atomic_t* v, long i)
-{
-	asm volatile(
-			"xchgl %1, %0 \n\t"
-			: "+q"(i), "=m"(v->val) : "m"((v)->val) : "memory" 
-			);
-}
-
-
-
-inline static long mb_atomic_get(atomic_t* var)
-{
-	long ret;
-	
-	asm volatile(
-			__LOCK_PREF " cmpxchg %0, %1 \n\t"
-			: "=a"(ret)  : "m"(var->val) : "cc", "memory"
-			);
-	return ret;
-}
-
-#endif /* NOSMP */
-
-
-/* on x86 atomic intructions act also as barriers */
-#define mb_atomic_inc(v)	atomic_inc(v)
-#define mb_atomic_dec(v)	atomic_dec(v)
-#define mb_atomic_or(v, m)	atomic_or(v, m)
-#define mb_atomic_and(v, m)	atomic_and(v, m)
-#define mb_atomic_inc_and_test(v)	atomic_inc_and_test(v)
-#define mb_atomic_dec_and_test(v)	atomic_dec_and_test(v)
-
-
-#elif defined __CPU_mips2 || ( defined __CPU_mips && defined MIPS_HAS_LLSC )
-
-#define HAVE_ASM_INLINE_ATOMIC_OPS
-
-#ifdef NOSMP
-#define membar() asm volatile ("" : : : "memory") /* gcc do not cache barrier*/
-#define membar_read()  membar()
-#define membar_write() membar()
-#else
-
-#define membar() \
-	asm volatile( \
-			".set push \n\t" \
-			".set noreorder \n\t" \
-			".set mips2 \n\t" \
-			"    sync\n\t" \
-			".set pop \n\t" \
-			: : : "memory" \
-			) 
-
-#define membar_read()  membar()
-#define membar_write() membar()
-
-#endif /* NOSMP */
-
 
+#ifdef CC_GCC_LIKE_ASM
 
-/* main asm block */
-#define ATOMIC_ASM_OP(op) \
-			".set push \n\t" \
-			".set noreorder \n\t" \
-			".set mips2 \n\t" \
-			"1:   ll %1, %0 \n\t" \
-			"     " op "\n\t" \
-			"     sc %2, %0 \n\t" \
-			"     beqz %2, 1b \n\t" \
-			"     nop \n\t" \
-			".set pop \n\t" 
+#if defined __CPU_i386 || defined __CPU_x86_64
 
+#include "atomic/atomic_x86.h"
 
-#define ATOMIC_FUNC_DECL(NAME, OP, RET_TYPE, RET_EXPR) \
-	inline static RET_TYPE atomic_##NAME (atomic_t *var) \
-	{ \
-		long ret, tmp; \
-		asm volatile( \
-			ATOMIC_ASM_OP(OP) \
-			: "=m"((var)->val), "=&r"(ret), "=&r"(tmp)  \
-			: "m"((var)->val) \
-			 \
-			); \
-		return RET_EXPR; \
-	}
+#elif defined __CPU_mips2 || defined __CPU_mips64 || \
+	  ( defined __CPU_mips && defined MIPS_HAS_LLSC )
 
+#include "atomic/atomic_mips2.h"
 
-/* same as above, but with CT in %3 */
-#define ATOMIC_FUNC_DECL_CT(NAME, OP, CT, RET_TYPE, RET_EXPR) \
-	inline static RET_TYPE atomic_##NAME (atomic_t *var) \
-	{ \
-		long ret, tmp; \
-		asm volatile( \
-			ATOMIC_ASM_OP(OP) \
-			: "=m"((var)->val), "=&r"(ret), "=&r"(tmp)  \
-			: "r"((CT)), "m"((var)->val) \
-			 \
-			); \
-		return RET_EXPR; \
-	}
+#elif defined __CPU_ppc || defined __CPU_ppc64
 
+#include "atomic/atomic_ppc.h"
 
-/* takes an extra param, i which goes in %3 */
-#define ATOMIC_FUNC_DECL1(NAME, OP, RET_TYPE, RET_EXPR) \
-	inline static RET_TYPE atomic_##NAME (atomic_t *var, long i) \
-	{ \
-		long ret, tmp; \
-		asm volatile( \
-			ATOMIC_ASM_OP(OP) \
-			: "=m"((var)->val), "=&r"(ret), "=&r"(tmp)  \
-			: "r"((i)), "m"((var)->val) \
-			 \
-			); \
-		return RET_EXPR; \
-	}
+#elif defined __CPU_sparc64
 
+#include "atomic/atomic_sparc64.h"
 
-ATOMIC_FUNC_DECL(inc,      "addiu %2, %1, 1", void, /* no return */ )
-ATOMIC_FUNC_DECL(inc_and_test, "addiu %2, %1, 1", long, (ret+1)==0 )
-
-ATOMIC_FUNC_DECL_CT(dec,   "subu %2, %1, %3", 1,  void, /* no return */ )
-ATOMIC_FUNC_DECL_CT(dec_and_test, "subu %2, %1, %3", 1, long, (ret-1)==0 )
-
-ATOMIC_FUNC_DECL1(and, "and %2, %1, %3", void, /* no return */ )
-ATOMIC_FUNC_DECL1(or,  "or  %2, %1, %3", void,  /* no return */ )
-
-
-/* with integrated membar */
-
-#define mb_atomic_set(v, i) \
-	do{ \
-		membar(); \
-		atomic_set(v, i); \
-	}while(0)
-
-
-
-inline static long mb_atomic_get(atomic_t* v)
-{
-	membar();
-	return atomic_get(v);
-}
-
-
-#define mb_atomic_inc(v) \
-	do{ \
-		membar(); \
-		atomic_inc(v); \
-	}while(0)
-
-#define mb_atomic_dec(v) \
-	do{ \
-		membar(); \
-		atomic_dec(v); \
-	}while(0)
-
-#define mb_atomic_or(v, m) \
-	do{ \
-		membar(); \
-		atomic_or(v, m); \
-	}while(0)
-
-#define mb_atomic_and(v, m) \
-	do{ \
-		membar(); \
-		atomic_and(v, m); \
-	}while(0)
-
-inline static int mb_atomic_inc_and_test(atomic_t* v)
-{
-	membar();
-	return atomic_inc_and_test(v);
-}
-
-inline static int mb_atomic_dec_and_test(atomic_t* v)
-{
-	membar();
-	return atomic_dec_and_test(v);
-}
-
+#elif defined __CPU_sparc
 
+#include "atomic/atomic_sparc.h"
 
 #endif /* __CPU_xxx  => no known cpu */
 
+#endif /* CC_GCC_LIKE_ASM */
 
-#ifndef HAVE_ASM_INLINE_ATOMIC_OPS
-
-#include "locking.h"
-
-#define ATOMIC_USE_LOCK
-
-extern gen_lock_t* _atomic_lock;
-
-
-#define atomic_lock    lock_get(_atomic_lock)
-#define atomic_unlock  lock_release(_atomic_lock)
-
-
-/* memory barriers 
- *  not a known cpu -> fall back lock/unlock: safe but costly  (it should 
- *  include a memory barrier effect) */
-#define membar() \
-	do{\
-		atomic_lock; \
-		atomic_unlock; \
-	} while(0)
-
-
-#define membar_write() membar()
-
-#define membar_read()  membar()
-
-
-/* atomic ops */
-
-#define atomic_inc(var) \
-	do{ \
-		atomic_lock; \
-		(var)->val++;\
-		atomic_unlock;\
-	}while(0)
-
-
-#define atomic_dec(var) \
-	do{ \
-		atomic_lock; \
-		(var)->val--; \
-		atomic_unlock; \
-	}while(0)
-
-
-#define atomic_and(var, i) \
-	do{ \
-		atomic_lock; \
-		(var)->val&=i; \
-		atomic_unlock; \
-	}while(0)
-
-#define atomic_or(var, i) \
-	do{ \
-		atomic_lock; \
-		(var)->val|=i; \
-		atomic_unlock; \
-	}while(0)
-
-
-
-/* returns true if result is 0 */
-inline static long atomic_inc_and_test(atomic_t* var)
-{
-	long ret;
-	
-	atomic_lock;
-	var->val++;
-	ret=var->val;
-	atomic_unlock;
-	
-	return (ret==0);
-}
-
-
-/* returns true if result is 0 */
-inline static long atomic_dec_and_test(atomic_t* var)
-{
-	long ret;
-	
-	atomic_lock;
-	var->val++;
-	ret=var->val;
-	atomic_unlock;
-	
-	return (ret==0);
-}
-
-
-/* memory barrier versions, the same as "normal" versions, except fot
- * the set/get
- * (the * atomic_lock/unlock part should act as a barrier)
- */
-
-#define mb_atomic_set(v, i) \
-	do{ \
-		membar(); \
-		atomic_set(v, i); \
-	}while(0)
 
-#define mb_atomic_get(v) \
-	do{ \
-		membar(); \
-		atomic_get(v); \
-	}while(0)
+#if  ! defined HAVE_ASM_INLINE_ATOMIC_OPS || ! defined HAVE_ASM_INLINE_MEMBAR
 
-#define mb_atomic_inc(v)	atomic_inc(v)
-#define mb_atomic_dec(v)	atomic_dec(v)
-#define mb_atomic_or(v, m)	atomic_or(v, m)
-#define mb_atomic_and(v, m)	atomic_and(v, m)
-#define mb_atomic_inc_and_test(v)	atomic_inc_and_test(v)
-#define mb_atomic_dec_and_test(v)	atomic_dec_and_test(v)
+#include "atomic/atomic_unknown.h"
 
 #endif /* if HAVE_ASM_INLINE_ATOMIC_OPS */
 

+ 46 - 0
atomic_ops_init.h

@@ -0,0 +1,46 @@
+/* 
+ * $Id$
+ * 
+ * Copyright (C) 2006 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ *    [email protected]
+ *
+ * ser is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+/*
+ * atomic_ops init functions
+ * (needed for lock intializing if no native asm locks are available
+ *  for the current arch./compiler combination, see atomic_ops.c)
+ */
+/* 
+ * History:
+ * --------
+ *  2006-03-30  created by andrei
+ */
+
+#ifndef __atomic_ops_init_h
+#define __atomic_ops_init_h
+
+/* init atomic ops */
+int init_atomic_ops();
+/* destroy atomic ops (e.g. frees the locks, if locks are used) */
+void destroy_atomic_ops();
+
+#endif

+ 4 - 0
main.c

@@ -128,6 +128,7 @@
 #include "usr_avp.h"
 #include "core_cmd.h"
 #include "flags.h"
+#include "atomic_ops_init.h"
 
 #include "stats.h"
 
@@ -390,6 +391,7 @@ void cleanup(show_status)
 	destroy_timer();
 	destroy_script_cb();
 	destroy_routes();
+	destroy_atomic_ops();
 #ifdef PKG_MALLOC
 	if (show_status){
 		LOG(memlog, "Memory status (pkg):\n");
@@ -1538,6 +1540,8 @@ try_again:
 	 * --andrei */
 	if (init_shm_mallocs()==-1)
 		goto error;
+	if (init_atomic_ops()==-1)
+		goto error;
 	/*init timer, before parsing the cfg!*/
 	if (init_timer()<0){
 		LOG(L_CRIT, "could not initialize timer, exiting...\n");

+ 57 - 21
test/atomic_test.c

@@ -3,29 +3,55 @@
  *  simple atomic ops testing program
  *  (no paralel stuff, just see if the opcodes are "legal")
  * 
- *  Compile with: gcc -D__CPU_i386 -O3 on x86 machines and
- *                gcc -mips2 -O2 -D__CPU_mips2  on mips machines.
+ *  Compile with: gcc -Wall -O3 -D__CPU_i386  on x86 machines
+ *                gcc -Wall -O3 -D__CPU_x86_64 on amd64 machines
+ *                gcc -mips2 -Wall -O2 -D__CPU_mips2  on mips machines
+ *                gcc -m64 -Wall -O2 -D__CPU_mips64 on mips64 machines
+ *                gcc -O3 -Wall -D__CPU_ppc on powerpc machines
+ *                gcc -m64 -O3 -Wall -D__CPU_ppc64 on powerpc machines
+ *                gcc -m64 -O3 -Wall -D__CPU_sparc64 -DSPARC64_MODE on 
+ *                                                   ultrasparc machines
  *  -- andrei
  *
  *  
  */
 
 #include <stdio.h>
+
+#define CC_GCC_LIKE_ASM
+
 #include "../atomic_ops.h"
 
+#ifdef ATOMIC_OPS_USE_LOCK 
+/* hack to make lock work */
+#include "../lock_ops.h"
+
+gen_lock_t* _atomic_lock;
 
+gen_lock_t dummy_lock;
+
+#endif
 
 int main(int argc, char** argv)
 {
 	int r;
 	atomic_t v;
+#ifdef ATOMIC_OPS_USE_LOCK
+	/* init the lock (emulate atomic_ops.c) */
+	_atomic_lock=&dummy_lock;
+	if (lock_init(_atomic_lock)==0){
+		fprintf(stderr, "ERROR: failed to initialize the lock\n");
+		goto error;
+	}
+#endif
+	
 #ifdef NOSMP
 	printf("no-smp mode\n");
 #else
 	printf("smp mode\n");
 #endif
 	
-	printf("\nstarting memory barrier opcode tests...\n");
+	printf("starting memory barrier opcode tests...\n");
 	membar();
 	printf(" membar() .............................. ok\n");
 	membar_write();
@@ -35,32 +61,42 @@ int main(int argc, char** argv)
 	
 	printf("\nstarting atomic ops basic tests...\n");
 	
-	atomic_set(&v, 1);
-	printf(" atomic_set, v should be 1 ............. %2ld\n", atomic_get(&v));
-	atomic_inc(&v);
-	printf(" atomic_inc, v should be 2 ............. %2ld\n", atomic_get(&v));
-	r=atomic_inc_and_test(&v);
-	printf(" atomic_inc_and_test, v should be  3 ... %2ld\n", atomic_get(&v));
+	mb_atomic_set(&v, 1);
+	printf(" atomic_set, v should be 1 ............. %2d\n", mb_atomic_get(&v));
+	mb_atomic_inc(&v);
+	printf(" atomic_inc, v should be 2 ............. %2d\n", mb_atomic_get(&v));
+	r=mb_atomic_inc_and_test(&v);
+	printf(" atomic_inc_and_test, v should be  3 ... %2d\n", mb_atomic_get(&v));
 	printf("                      r should be  0 ... %2d\n", r);
 	
-	atomic_dec(&v);
-	printf(" atomic_dec, v should be 2 ............. %2ld\n", atomic_get(&v));
-	r=atomic_dec_and_test(&v);
-	printf(" atomic_dec_and_test, v should be  1 ... %2ld\n", atomic_get(&v));
+	mb_atomic_dec(&v);
+	printf(" atomic_dec, v should be 2 ............. %2d\n", mb_atomic_get(&v));
+	r=mb_atomic_dec_and_test(&v);
+	printf(" atomic_dec_and_test, v should be  1 ... %2d\n", mb_atomic_get(&v));
 	printf("                      r should be  0 ... %2d\n", r);
-	r=atomic_dec_and_test(&v);
-	printf(" atomic_dec_and_test, v should be  0 ... %2ld\n", atomic_get(&v));
+	r=mb_atomic_dec_and_test(&v);
+	printf(" atomic_dec_and_test, v should be  0 ... %2d\n", mb_atomic_get(&v));
 	printf("                      r should be  1 ... %2d\n", r);
-	r=atomic_dec_and_test(&v);
-	printf(" atomic_dec_and_test, v should be -1 ... %2ld\n", atomic_get(&v));
+	r=mb_atomic_dec_and_test(&v);
+	printf(" atomic_dec_and_test, v should be -1 ... %2d\n", mb_atomic_get(&v));
 	printf("                      r should be  0 ... %2d\n", r);
 	
-	atomic_and(&v, 2);
-	printf(" atomic_and, v should be 2 ............. %2ld\n", atomic_get(&v));
+	mb_atomic_and(&v, 2);
+	printf(" atomic_and, v should be 2 ............. %2d\n", mb_atomic_get(&v));
 	
-	atomic_or(&v, 5);
-	printf(" atomic_or,  v should be 7 ............. %2ld\n", atomic_get(&v));
+	mb_atomic_or(&v, 5);
+	r=mb_atomic_get_and_set(&v, 0);
+	printf(" atomic_or,  v should be 7 ............. %2d\n", r);
+	printf(" atomic_get_and_set, v should be 0 ..... %2d\n", mb_atomic_get(&v));
+
 	
 	printf("\ndone.\n");
+#ifdef ATOMIC_OPS_USE_LOCK
+	lock_destroy(_atomic_lock);
+#endif
 	return 0;
+#ifdef ATOMIC_OPS_USE_LOCK
+error:
+	return -1;
+#endif
 }

+ 217 - 0
test/atomic_test2.c

@@ -0,0 +1,217 @@
+/*
+ *
+ *  simple atomic ops testing program
+ *  (no paralel stuff, just see if the opcodes are "legal")
+ *
+ *  Defines: TYPE - not defined => use atomic_t and the corresponding
+ *                  atomic functions
+ *                - long => use volatile long* and  the atomic_*_long functions
+ *                - int  => use volatile int* and the atomic_*_int functions
+ *           MEMBAR - if defined use mb_atomic_* instead of atomic_*
+ *           NOSMP - use non smp versions
+ *           NOASM - don't use asm inline version
+ *           __CPU_xxx - use __CPU_xxx code
+ *           SPARC64_MODE - compile for a sparc 64 in 64 bit mode (gcc -m64
+ *                          must be used on solaris in this case)
+ *  Example:  
+ *    gcc -Wall -O3 -D__CPU_i386 -DNOSMP -DMEMBAR -DTYPE=long atomic_test2.c
+ * 
+ *  Compile with: gcc -Wall -O3 -D__CPU_i386  ... on x86 machines
+ *                gcc -Wall -O3 -D__CPU_x86_64 ... on amd64 machines
+ *                gcc -mips2 -Wall -O2 -D__CPU_mips2  ... on mips machines
+ *                gcc -m64 -Wall -O2 -D__CPU_mips64 ... on mips64 machines
+ *                gcc -O3 -Wall -D__CPU_ppc ... on powerpc machines
+ *                gcc -m64 -O3 -Wall -D__CPU_ppc64 ... on powerpc machines
+ *                gcc -m64 -O3 -Wall -D__CPU_sparc64 -DSPARC64_MODE ... on 
+ *                                                   ultrasparc machines
+ *                gcc -mcpu=v9 -O3 -Wall -D__CPU_sparc64  ... for 32 bit code 
+ *                                                   (sparc32plus) on 
+ *                                                   ultrasparc machines
+ *                gcc -O3 -Wall -D__CPU_sparc ... on sparc v8 machines
+ *  -- andrei
+ *
+ *  
+ */
+
+#include <stdio.h>
+
+#ifndef NOASM
+#define CC_GCC_LIKE_ASM
+#endif
+
+#include "../atomic_ops.h"
+
+#ifdef ATOMIC_OPS_USE_LOCK 
+/* hack to make lock work */
+#include "../lock_ops.h"
+
+gen_lock_t* _atomic_lock;
+
+gen_lock_t dummy_lock;
+
+#endif
+
+
+
+#if defined MB || defined MEMBAR
+#undef MB
+#define MB mb_
+#define MEMBAR_STR "membar "
+#else
+#define MB  /* empty */
+#define MEMBAR_STR ""
+#endif
+
+#ifndef TYPE
+#define SUF
+#define ATOMIC_TYPE atomic_t
+#define VALUE_TYPE volatile int
+#define get_val(v)	(v->val)
+#else
+#define _SUF(T) _##T
+#define _SUF1(T) _SUF(T)
+#define SUF _SUF1(TYPE)
+#define ATOMIC_TYPE volatile TYPE
+#define VALUE_TYPE ATOMIC_TYPE
+#define get_val(v)	(*v)
+#endif
+
+
+#define _STR(S) #S
+#define STR(S) _STR(S)
+
+static char* flags=
+#ifdef NOASM
+	"no_inline_asm "
+#endif
+#ifdef NOSMP
+	"nosmp "
+#else
+	"smp "
+#endif
+	MEMBAR_STR
+#ifndef HAVE_ASM_INLINE_MEMBAR
+	"no_asm_membar(slow) "
+#endif
+#ifndef HAVE_ASM_INLINE_ATOMIC_OPS
+	"no_asm_atomic_ops "
+#endif
+#ifdef TYPE
+	STR(TYPE) " "
+#else
+	"atomic_t "
+#endif
+;
+
+
+
+/* macros for atomic_* functions */
+
+#define _AT_DECL(OP, P, S) \
+	P##atomic_##OP##S
+
+
+/* to make sure all the macro passed as params are expanded,
+ *  go through a 2 level deep macro decl. */
+#define _AT_DECL1(OP, P, S) _AT_DECL(OP, P, S)
+#define AT_DECL(OP) _AT_DECL1(OP, MB, SUF)
+
+
+#define at_set	AT_DECL(set)
+#define at_get	AT_DECL(get)
+
+#define at_inc	AT_DECL(inc)
+#define at_dec	AT_DECL(dec)
+#define at_inc_and_test	AT_DECL(inc_and_test)
+#define at_dec_and_test	AT_DECL(dec_and_test)
+#define at_and	AT_DECL(and)
+#define at_or	AT_DECL(or)
+#define at_get_and_set	AT_DECL(get_and_set)
+
+
+#define CHECK_ERR(txt, x, y) \
+	if (x!=y) { \
+		fprintf(stderr, "ERROR: line %d: %s failed: expected 0x%02x but got "\
+						"0x%02x.\n", \
+						__LINE__, #txt, (unsigned) x, (unsigned) y);\
+		goto error; \
+	}
+
+#define VERIFY(ops, y) \
+	ops ; \
+	CHECK_ERR( ops, get_val(v), y)
+
+
+int main(int argc, char** argv)
+{
+	ATOMIC_TYPE var;
+	VALUE_TYPE r;
+	
+	ATOMIC_TYPE* v;
+	
+	v=&var;
+	
+	
+#ifdef ATOMIC_OPS_USE_LOCK
+	/* init the lock (emulate atomic_ops.c) */
+	_atomic_lock=&dummy_lock;
+	if (lock_init(_atomic_lock)==0){
+		fprintf(stderr, "ERROR: failed to initialize the lock\n");
+		_atomic_lock=0;
+		goto error;
+	}
+#endif
+	
+	printf("%s\n", flags);
+	
+	printf("starting memory barrier opcode tests...\n");
+	membar();
+	printf(" membar() .............................. ok\n");
+	membar_write();
+	printf(" membar_write() ........................ ok\n");
+	membar_read();
+	printf(" membar_read() ......................... ok\n");
+	
+	printf("\nstarting atomic ops basic tests...\n");
+	
+	VERIFY(at_set(v, 1), 1);
+	printf(" atomic_set, v should be 1 ............. %2d\n", (int)at_get(v));
+	VERIFY(at_inc(v), 2);
+	printf(" atomic_inc, v should be 2 ............. %2d\n", (int)at_get(v));
+	VERIFY(r=at_inc_and_test(v), 3);
+	printf(" atomic_inc_and_test, v should be  3 ... %2d\n", (int)at_get(v));
+	printf("                      r should be  0 ... %2d\n", (int)r);
+	
+	VERIFY(at_dec(v), 2);
+	printf(" atomic_dec, v should be 2 ............. %2d\n", (int)at_get(v));
+	VERIFY(r=at_dec_and_test(v), 1);
+	printf(" atomic_dec_and_test, v should be  1 ... %2d\n", (int)at_get(v));
+	printf("                      r should be  0 ... %2d\n", (int)r);
+	VERIFY(r=at_dec_and_test(v), 0);
+	printf(" atomic_dec_and_test, v should be  0 ... %2d\n", (int)at_get(v));
+	printf("                      r should be  1 ... %2d\n", (int)r);
+	VERIFY(r=at_dec_and_test(v), -1);
+	printf(" atomic_dec_and_test, v should be -1 ... %2d\n", (int)at_get(v));
+	printf("                      r should be  0 ... %2d\n", (int)r);
+	
+	VERIFY(at_and(v, 2), 2);
+	printf(" atomic_and, v should be 2 ............. %2d\n", (int)at_get(v));
+	
+	VERIFY(at_or(v, 5), 7);
+	VERIFY(r=at_get_and_set(v, 0), 0);
+	printf(" atomic_or,  v should be 7 ............. %2d\n", (int)r);
+	printf(" atomic_get_and_set, v should be 0 ..... %2d\n", (int)at_get(v));
+
+	
+	printf("\ndone.\n");
+#ifdef ATOMIC_OPS_USE_LOCK
+	lock_destroy(_atomic_lock);
+#endif
+	return 0;
+error:
+#ifdef ATOMIC_OPS_USE_LOCK
+	if (_atomic_lock)
+		lock_destroy(_atomic_lock);
+#endif
+	return -1;
+}