atomic_test2.c

00001 /*
00002  *
00003  *  simple atomic ops testing program
00004  *  (no paralel stuff, just see if the opcodes are "legal")
00005  *
00006  *  Defines: TYPE - not defined => use atomic_t and the corresponding
00007  *                  atomic functions
00008  *                - long => use volatile long* and  the atomic_*_long functions
00009  *                - int  => use volatile int* and the atomic_*_int functions
00010  *           MEMBAR - if defined use mb_atomic_* instead of atomic_*
00011  *           NOSMP - use non smp versions
00012  *           NOASM - don't use asm inline version
00013  *           __CPU_xxx - use __CPU_xxx code
00014  *           SPARC64_MODE - compile for a sparc 64 in 64 bit mode (gcc -m64
00015  *                          must be used on solaris in this case)
00016  *  Example:  
00017  *    gcc -Wall -O3 -D__CPU_i386 -DNOSMP -DMEMBAR -DTYPE=long atomic_test2.c
00018  * 
00019  *  Compile with: gcc -Wall -O3 -D__CPU_i386  ... on x86 machines
00020  *                gcc -Wall -O3 -D__CPU_x86_64 ... on amd64 machines
00021  *                gcc -mips2 -Wall -O2 -D__CPU_mips2  ... on mips machines
00022  *                gcc -m64 -Wall -O2 -D__CPU_mips64 ... on mips64 machines
00023  *                gcc -O3 -Wall -D__CPU_ppc ... on powerpc machines
00024  *                gcc -m64 -O3 -Wall -D__CPU_ppc64 ... on powerpc machines
00025  *                gcc -m64 -O3 -Wall -D__CPU_sparc64 -DSPARC64_MODE ... on 
00026  *                                                   ultrasparc machines
00027  *                gcc -mcpu=v9 -O3 -Wall -D__CPU_sparc64  ... for 32 bit code 
00028  *                                                   (sparc32plus) on 
00029  *                                                   ultrasparc machines
00030  *                gcc -O3 -Wall -D__CPU_sparc ... on sparc v8 machines
00031  *  -- andrei
00032  *
00033  *  
00034  */
00035 
00036 #include <stdio.h>
00037 
00038 #ifndef NOASM
00039 #define CC_GCC_LIKE_ASM
00040 #endif
00041 
00042 #include "../atomic_ops.h"
00043 
00044 #if defined ATOMIC_OPS_USE_LOCK  || defined MEMBAR_USES_LOCK || \
00045         defined ATOMIC_OPS_USE_LOCK_SET
00046 /* hack to make lock work */
00047 #include "../lock_ops.h"
00048 #endif
00049 
00050 #ifdef MEMBAR_USES_LOCK
00051 gen_lock_t* __membar_lock=0; /* init in atomic_ops.c */
00052 gen_lock_t dummy_membar_lock;
00053 #endif
00054 
00055 #ifdef ATOMIC_OPS_USE_LOCK_SET
00056 gen_lock_set_t* _atomic_lock_set=0;
00057 gen_lock_set_t dummy_atomic_lock_set;
00058 gen_lock_t locks_array[_ATOMIC_LS_SIZE];
00059 #elif defined ATOMIC_OPS_USE_LOCK
00060 gen_lock_t* _atomic_lock=0;
00061 gen_lock_t dummy_atomic_lock;
00062 #endif /* ATOMIC_OPS_USE_LOCK / _SET */
00063 
00064 
00065 
00066 
00067 #if defined MB || defined MEMBAR
00068 #undef MB
00069 #define MB mb_
00070 #define MEMBAR_STR "membar "
00071 #else
00072 #define MB  /* empty */
00073 #define MEMBAR_STR ""
00074 #endif
00075 
00076 #ifndef TYPE
00077 #define SUF
00078 #define ATOMIC_TYPE atomic_t
00079 #define VALUE_TYPE volatile int
00080 #define get_val(v)      (v->val)
00081 #else
00082 #define _SUF(T) _##T
00083 #define _SUF1(T) _SUF(T)
00084 #define SUF _SUF1(TYPE)
00085 #define ATOMIC_TYPE volatile TYPE
00086 #define VALUE_TYPE ATOMIC_TYPE
00087 #define get_val(v)      (*v)
00088 #endif
00089 
00090 
00091 #define _STR(S) #S
00092 #define STR(S) _STR(S)
00093 
00094 static char* flags=
00095 #ifdef NOASM
00096         "no_inline_asm "
00097 #endif
00098 #ifdef NOSMP
00099         "nosmp "
00100 #else
00101         "smp "
00102 #endif
00103         MEMBAR_STR
00104 #ifndef HAVE_ASM_INLINE_MEMBAR
00105         "no_asm_membar(slow) "
00106 #endif
00107 #ifndef HAVE_ASM_INLINE_ATOMIC_OPS
00108         "no_asm_atomic_ops"
00109 #ifdef ATOMIC_OPS_USE_LOCK_SET
00110         ":use_lock_set"
00111 #elif defined ATOMIC_OPS_USE_LOCK
00112         ":use_lock"
00113 #endif
00114         " "
00115 #endif
00116 #ifdef TYPE
00117         STR(TYPE) " "
00118 #else
00119         "atomic_t "
00120 #endif
00121 ;
00122 
00123 
00124 
00125 /* macros for atomic_* functions */
00126 
00127 #define _AT_DECL(OP, P, S) \
00128         P##atomic_##OP##S
00129 
00130 
00131 /* to make sure all the macro passed as params are expanded,
00132  *  go through a 2 level deep macro decl. */
00133 #define _AT_DECL1(OP, P, S) _AT_DECL(OP, P, S)
00134 #define AT_DECL(OP) _AT_DECL1(OP, MB, SUF)
00135 
00136 
00137 #define at_set  AT_DECL(set)
00138 #define at_get  AT_DECL(get)
00139 
00140 #define at_inc  AT_DECL(inc)
00141 #define at_dec  AT_DECL(dec)
00142 #define at_inc_and_test AT_DECL(inc_and_test)
00143 #define at_dec_and_test AT_DECL(dec_and_test)
00144 #define at_and  AT_DECL(and)
00145 #define at_or   AT_DECL(or)
00146 #define at_get_and_set  AT_DECL(get_and_set)
00147 #define at_cmpxchg      AT_DECL(cmpxchg)
00148 #define at_add  AT_DECL(add)
00149 
00150 
00151 #define CHECK_ERR(txt, x, y) \
00152         if (x!=y) { \
00153                 fprintf(stderr, "ERROR: line %d: %s failed: expected 0x%02x but got "\
00154                                                 "0x%02x.\n", \
00155                                                 __LINE__, #txt, (unsigned) x, (unsigned) y);\
00156                 goto error; \
00157         }
00158 
00159 #define VERIFY(ops, y) \
00160         ops ; \
00161         CHECK_ERR( ops, y, get_val(v))
00162 
00163 
00164 int main(int argc, char** argv)
00165 {
00166         ATOMIC_TYPE var;
00167         VALUE_TYPE r;
00168         
00169         ATOMIC_TYPE* v;
00170         
00171         v=&var;
00172         
00173         
00174 #ifdef MEMBAR_USES_LOCK
00175         __membar_lock=&dummy_membar_lock;
00176         if (lock_init(__membar_lock)==0){
00177                 fprintf(stderr, "ERROR: failed to initialize membar_lock\n");
00178                 __membar_lock=0;
00179                 goto error;
00180         }
00181         _membar_lock; /* start with the lock "taken" so that we can safely use
00182                                          unlock/lock sequences on it later */
00183 #endif
00184 #ifdef ATOMIC_OPS_USE_LOCK_SET
00185         /* init the lock (emulate atomic_ops.c) */
00186         dummy_atomic_lock_set.locks=&locks_array[0];
00187         _atomic_lock_set=&dummy_atomic_lock_set;
00188         if (lock_set_init(_atomic_lock_set)==0){
00189                 fprintf(stderr, "ERROR: failed to initialize atomic_lock\n");
00190                 _atomic_lock_set=0;
00191                 goto error;
00192         }
00193 #elif defined ATOMIC_OPS_USE_LOCK
00194         /* init the lock (emulate atomic_ops.c) */
00195         _atomic_lock=&dummy_atomic_lock;
00196         if (lock_init(_atomic_lock)==0){
00197                 fprintf(stderr, "ERROR: failed to initialize atomic_lock\n");
00198                 _atomic_lock=0;
00199                 goto error;
00200         }
00201 #endif
00202         
00203         printf("%s\n", flags);
00204         
00205         printf("starting memory barrier opcode tests...\n");
00206         membar();
00207         printf(" membar() .............................. ok\n");
00208         membar_write();
00209         printf(" membar_write() ........................ ok\n");
00210         membar_read();
00211         printf(" membar_read() ......................... ok\n");
00212         membar_depends();
00213         printf(" membar_depends() ...................... ok\n");
00214         membar_enter_lock();
00215         printf(" membar_enter_lock() ................... ok\n");
00216         membar_leave_lock();
00217         printf(" membar_leave_lock() ................... ok\n");
00218         membar_atomic_op();
00219         printf(" membar_atomic_op() .................... ok\n");
00220         membar_atomic_setget();
00221         printf(" membar_atomic_setget() ................ ok\n");
00222         membar_read_atomic_op();
00223         printf(" membar_read_atomic_op() ............... ok\n");
00224         membar_read_atomic_setget();
00225         printf(" membar_read_atomic_setget() ........... ok\n");
00226         membar_write_atomic_op();
00227         printf(" membar_write_atomic_op() .............. ok\n");
00228         membar_write_atomic_setget();
00229         printf(" membar_write_atomic_setget() .......... ok\n");
00230         
00231         printf("\nstarting atomic ops basic tests...\n");
00232         
00233         VERIFY(at_set(v, 1), 1);
00234         printf(" atomic_set, v should be 1 ............. %2d\n", (int)at_get(v));
00235         VERIFY(at_inc(v), 2);
00236         printf(" atomic_inc, v should be 2 ............. %2d\n", (int)at_get(v));
00237         VERIFY(r=at_inc_and_test(v), 3);
00238         printf(" atomic_inc_and_test, v should be  3 ... %2d\n", (int)at_get(v));
00239         printf("                      r should be  0 ... %2d\n", (int)r);
00240         
00241         VERIFY(at_dec(v), 2);
00242         printf(" atomic_dec, v should be 2 ............. %2d\n", (int)at_get(v));
00243         VERIFY(r=at_dec_and_test(v), 1);
00244         printf(" atomic_dec_and_test, v should be  1 ... %2d\n", (int)at_get(v));
00245         printf("                      r should be  0 ... %2d\n", (int)r);
00246         VERIFY(r=at_dec_and_test(v), 0);
00247         printf(" atomic_dec_and_test, v should be  0 ... %2d\n", (int)at_get(v));
00248         printf("                      r should be  1 ... %2d\n", (int)r);
00249         VERIFY(r=at_dec_and_test(v), -1);
00250         printf(" atomic_dec_and_test, v should be -1 ... %2d\n", (int)at_get(v));
00251         printf("                      r should be  0 ... %2d\n", (int)r);
00252         
00253         VERIFY(at_and(v, 2), 2);
00254         printf(" atomic_and, v should be 2 ............. %2d\n", (int)at_get(v));
00255         
00256         VERIFY(at_or(v, 5), 7);
00257         printf(" atomic_or,  v should be 7 ............. %2d\n", (int)at_get(v));
00258         VERIFY(r=at_get_and_set(v, 0), 0);
00259         printf(" atomic_get_and_set, v should be 0 ..... %2d\n", (int)at_get(v));
00260         VERIFY(r=at_cmpxchg(v, 0, 7), 7);
00261         CHECK_ERR(cmpxchg, r, 0);
00262         printf(" atomic_cmpxchg, v should be 7 ......... %2d\n", (int)at_get(v));
00263         printf("                 r should be 0 ......... %2d\n", (int)r);
00264         VERIFY(r=at_cmpxchg(v, 2, 3), 7);
00265         CHECK_ERR(cmpxchg, r, 7);
00266         printf(" atomic_cmpxchg (fail), v should be 7 .. %2d\n", (int)at_get(v));
00267         printf("                        r should be 7 .. %2d\n", (int)r);
00268         VERIFY(r=at_add(v, 2), 9);
00269         CHECK_ERR(atomic_add, r, 9);
00270         printf(" atomic_add, v should be 9 ............. %2d\n", (int)at_get(v));
00271         printf("             r should be 9 ............. %2d\n", (int)r);
00272         VERIFY(r=at_add(v, -10), -1);
00273         CHECK_ERR(atomic_add, r, -1);
00274         printf(" atomic_add, v should be -1 ............ %2d\n", (int)at_get(v));
00275         printf("             r should be -1 ............ %2d\n", (int)r);
00276 
00277         
00278         printf("\ndone.\n");
00279 #ifdef MEMBAR_USES_LOCK
00280         lock_destroy(__membar_lock);
00281 #endif
00282 #ifdef ATOMIC_OPS_USE_LOCK_SET
00283         lock_set_destroy(_atomic_lock_set);
00284 #elif defined ATOMIC_OPS_USE_LOCK
00285         lock_destroy(_atomic_lock);
00286 #endif
00287         return 0;
00288 error:
00289 #ifdef MEMBAR_USES_LOCK
00290         if (__membar_lock)
00291                 lock_destroy(__membar_lock);
00292 #endif
00293 #ifdef ATOMIC_OPS_USE_LOCK_SET
00294         if (_atomic_lock_set)
00295                 lock_set_destroy(_atomic_lock_set);
00296 #elif defined ATOMIC_OPS_USE_LOCK
00297         if (_atomic_lock)
00298                 lock_destroy(_atomic_lock);
00299 #endif
00300         return -1;
00301 }