atomic_alpha.h

Go to the documentation of this file.
00001 /* 
00002  * Copyright (C) 2006 iptelorg GmbH
00003  *
00004  * Permission to use, copy, modify, and distribute this software for any
00005  * purpose with or without fee is hereby granted, provided that the above
00006  * copyright notice and this permission notice appear in all copies.
00007  *
00008  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
00009  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00010  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
00011  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00012  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00013  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
00014  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00015  */
00016 
00030 /* 
00031  * History:
00032  * --------
00033  *  2006-03-31  created by andrei
00034  *  2007-05-10  added atomic_add & atomic_cmpxchg (andrei)
00035  *  2007-05-29  added membar_depends(), membar_*_atomic_op and
00036  *                membar_*_atomic_setget (andrei)
00037  */
00038 
00039 
00040 #ifndef _atomic_alpha_h
00041 #define _atomic_alpha_h
00042 
00043 #define HAVE_ASM_INLINE_ATOMIC_OPS
00044 #define HAVE_ASM_INLINE_MEMBAR
00045 
00046 #warning alpha atomic code was not tested, please report problems to \
00047                 serdev@iptel.org or andrei@iptel.org
00048 
00049 #ifdef NOSMP
00050 #define membar() asm volatile ("" : : : "memory") /* gcc do not cache barrier*/
00051 #define membar_read()  membar()
00052 #define membar_write() membar()
00053 #define membar_depends()  do {} while(0) /* really empty, not even a cc bar. */
00054 /* lock barriers: empty, not needed for NOSMP; the lock/unlock should already
00055  * contain gcc barriers*/
00056 #define membar_enter_lock() do {} while(0)
00057 #define membar_leave_lock() do {} while(0)
00058 /* membars after or before atomic_ops or atomic_setget -> use these or
00059  *  mb_<atomic_op_name>() if you need a memory barrier in one of these
00060  *  situations (on some archs where the atomic operations imply memory
00061  *   barriers is better to use atomic_op_x(); membar_atomic_op() then
00062  *    atomic_op_x(); membar()) */
00063 #define membar_atomic_op()                              membar()
00064 #define membar_atomic_setget()                  membar()
00065 #define membar_write_atomic_op()                membar_write()
00066 #define membar_write_atomic_setget()    membar_write()
00067 #define membar_read_atomic_op()                 membar_read()
00068 #define membar_read_atomic_setget()             membar_read()
00069 
00070 #else
00071 
00072 #define membar()                asm volatile ("    mb \n\t" : : : "memory" ) 
00073 #define membar_read()   membar()
00074 #define membar_write()  asm volatile ("    wmb \n\t" : : : "memory" )
00075 #define membar_depends()        asm volatile ("mb \n\t" : : : "memory" )
00076 #define membar_enter_lock() asm volatile("mb \n\t" : : : "memory")
00077 #define membar_leave_lock() asm volatile("mb \n\t" : : : "memory")
00078 
00079 /* membars after or before atomic_ops or atomic_setget -> use these or
00080  *  mb_<atomic_op_name>() if you need a memory barrier in one of these
00081  *  situations (on some archs where the atomic operations imply memory
00082  *   barriers is better to use atomic_op_x(); membar_atomic_op() then
00083  *    atomic_op_x(); membar()) */
00084 #define membar_atomic_op()                              membar()
00085 #define membar_atomic_setget()                  membar()
00086 #define membar_write_atomic_op()                membar_write()
00087 #define membar_write_atomic_setget()    membar_write()
00088 #define membar_read_atomic_op()                 membar_read()
00089 #define membar_read_atomic_setget()             membar_read()
00090 #endif /* NOSMP */
00091 
00092 
00093 
00094 /* main asm block 
00095  * if store failes, jump _forward_ (optimization, because back jumps are
00096  *  always predicted to happen on alpha )*/
00097 #define ATOMIC_ASM_OP00_int(op) \
00098                         "1:   ldl_l %0, %2 \n\t" \
00099                         "     " op "\n\t" \
00100                         "     stl_c %0, %2 \n\t" \
00101                         "     beq %0, 2f \n\t" \
00102                         ".subsection 2 \n\t" \
00103                         "2:   br 1b \n\t" \
00104                         ".previous \n\t"
00105 
00106 /* as above, but output in %1 instead of %0 (%0 is not clobbered) */
00107 #define ATOMIC_ASM_OP01_int(op) \
00108                         "1:   ldl_l %0, %3 \n\t" \
00109                         "     " op "\n\t" \
00110                         "     stl_c %1, %3 \n\t" \
00111                         "     beq %1, 2f \n\t" \
00112                         ".subsection 2 \n\t" \
00113                         "2:   br 1b \n\t" \
00114                         ".previous \n\t"
00115 
00116 #define ATOMIC_ASM_OP00_long(op) \
00117                         "1:   ldq_l %0, %2 \n\t" \
00118                         "     " op "\n\t" \
00119                         "     stq_c %0, %2 \n\t" \
00120                         "     beq %0, 2f \n\t" \
00121                         ".subsection 2 \n\t" \
00122                         "2:   br 1b \n\t" \
00123                         ".previous \n\t"
00124 
00125 /* as above, but output in %1 instead of %0 (%0 is not clobbered) */
00126 #define ATOMIC_ASM_OP01_long(op) \
00127                         "1:   ldq_l %0, %3 \n\t" \
00128                         "     " op "\n\t" \
00129                         "     stq_c %1, %3 \n\t" \
00130                         "     beq %1, 2f \n\t" \
00131                         ".subsection 2 \n\t" \
00132                         "2:   br 1b \n\t" \
00133                         ".previous \n\t"
00134 
00135 
00136 
00137 /* input in %0, output in %0 */
00138 #define ATOMIC_FUNC_DECL0_0(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
00139         inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var) \
00140         { \
00141                 P_TYPE ret; \
00142                 asm volatile( \
00143                         ATOMIC_ASM_OP00_##P_TYPE(OP) : "=&r"(ret), "=m"(*var) : "m"(*var) \
00144                         ); \
00145                 return RET_EXPR; \
00146         }
00147 
00148 
00149 #if defined __GNUC__ &&  __GNUC__ < 3 && __GNUC_MINOR__ < 9
00150 #define ATOMIC_FUNC_DECL01_1(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
00151         inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
00152                                                                                                                 P_TYPE v ) \
00153         { \
00154                 P_TYPE ret; \
00155                 asm volatile( \
00156                         ATOMIC_ASM_OP01_##P_TYPE(OP) \
00157                         : "=&r"(ret), "=r"(v), "=m"(*var)  : "m"(*var), "1"(v) \
00158                         ); \
00159                 return RET_EXPR; \
00160         }
00161 #else
00162 /* input in %0, and %1 (param), output in %1,  %0 goes in ret */
00163 #define ATOMIC_FUNC_DECL01_1(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
00164         inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
00165                                                                                                                 P_TYPE v ) \
00166         { \
00167                 P_TYPE ret; \
00168                 asm volatile( \
00169                         ATOMIC_ASM_OP01_##P_TYPE(OP) \
00170                         : "=&r"(ret), "+r"(v), "=m"(*var)  : "m"(*var) \
00171                         ); \
00172                 return RET_EXPR; \
00173         }
00174 #endif /* gcc && gcc version < 2.9 */
00175 
00176 /* input in %0, output in %1, %0 goes in ret */
00177 #define ATOMIC_FUNC_DECL0_1(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
00178         inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var) \
00179         { \
00180                 P_TYPE ret, tmp; \
00181                 asm volatile( \
00182                         ATOMIC_ASM_OP01_##P_TYPE(OP) \
00183                         : "=&r"(ret), "=&r"(tmp), "=m"(*var)  : "m"(*var) \
00184                         ); \
00185                 return RET_EXPR; \
00186         }
00187 
00188 
00189 /* input in %0 and %3 (param), output in %0 */
00190 #define ATOMIC_FUNC_DECL03_0(NAME, OP, P_TYPE, RET_TYPE, RET_EXPR) \
00191         inline static RET_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
00192                                                                                                                 P_TYPE v) \
00193         { \
00194                 P_TYPE ret; \
00195                 asm volatile( \
00196                         ATOMIC_ASM_OP00_##P_TYPE(OP) \
00197                         : "=&r"(ret), "=m"(*var)  : "m"(*var), "r"(v) \
00198                         ); \
00199                 return RET_EXPR; \
00200         }
00201 
00202 /* input in %0 and %3 (param), output in %0 */
00203 /* cmpxchg var in %1, old in %0, new_v in %
00204  * makes the xchg if old==*var
00205  * returns initial *var (so if ret==old => new_v was written into var)*/
00206 #define ATOMIC_CMPXCHG_DECL(NAME,  P_TYPE) \
00207         inline static P_TYPE atomic_##NAME##_##P_TYPE (volatile P_TYPE *var, \
00208                                                                                                                 P_TYPE old, \
00209                                                                                                                 P_TYPE new_v) \
00210         { \
00211                 P_TYPE ret; \
00212                 P_TYPE tmp; \
00213                 asm volatile( \
00214                         ATOMIC_ASM_OP01_##P_TYPE("subq  %0, %5, %2 \n\t bne %2, 3f")\
00215                         "3:    \n\t" \
00216                         : "=&r"(ret), "=&r"(new_v), "=r"(tmp), "=m"(*var)  :\
00217                                 "m"(*var), "r"(old), "1"(new_v) :"cc" \
00218                         ); \
00219                 return ret; \
00220         }
00221 
00222 
00223 ATOMIC_FUNC_DECL0_0(inc, "addl %0, 1, %0", int, void, /* no return */ )
00224 ATOMIC_FUNC_DECL0_0(dec, "subl %0, 1, %0", int, void, /* no return */ )
00225 ATOMIC_FUNC_DECL03_0(and, "and %0, %3, %0", int, void, /* no return */ )
00226 ATOMIC_FUNC_DECL03_0(or,  "bis %0, %3, %0", int, void, /* no return */ )
00227 ATOMIC_FUNC_DECL0_1(inc_and_test, "addl %0, 1, %1", int, int, (ret+1)==0 )
00228 ATOMIC_FUNC_DECL0_1(dec_and_test, "subl %0, 1, %1", int, int, (ret-1)==0 )
00229 ATOMIC_FUNC_DECL01_1(get_and_set, "" /* nothing needed */, int, int, ret )
00230 ATOMIC_CMPXCHG_DECL(cmpxchg, int )
00231 ATOMIC_FUNC_DECL01_1(add, "addl %1, %0, %1", int, int, ret+v)
00232 
00233 ATOMIC_FUNC_DECL0_0(inc, "addq %0, 1, %0", long, void, /* no return */ )
00234 ATOMIC_FUNC_DECL0_0(dec, "subq %0, 1, %0", long, void, /* no return */ )
00235 ATOMIC_FUNC_DECL03_0(and, "and %0, %3, %0", long, void, /* no return */ )
00236 ATOMIC_FUNC_DECL03_0(or,  "bis %0, %3, %0", long, void, /* no return */ )
00237 ATOMIC_FUNC_DECL0_1(inc_and_test, "addq %0, 1, %1", long, long, (ret+1)==0 )
00238 ATOMIC_FUNC_DECL0_1(dec_and_test, "subq %0, 1, %1", long, long, (ret-1)==0 )
00239 ATOMIC_FUNC_DECL01_1(get_and_set, "" /* nothing needed */, long, long, ret )
00240 ATOMIC_CMPXCHG_DECL(cmpxchg, long )
00241 ATOMIC_FUNC_DECL01_1(add, "addq %1, %0, %1", long, long, ret+v)
00242 
00243 
00244 #define atomic_inc(var) atomic_inc_int(&(var)->val)
00245 #define atomic_dec(var) atomic_dec_int(&(var)->val)
00246 #define atomic_and(var, mask) atomic_and_int(&(var)->val, (mask))
00247 #define atomic_or(var, mask)  atomic_or_int(&(var)->val, (mask))
00248 #define atomic_dec_and_test(var) atomic_dec_and_test_int(&(var)->val)
00249 #define atomic_inc_and_test(var) atomic_inc_and_test_int(&(var)->val)
00250 #define atomic_get_and_set(var, i) atomic_get_and_set_int(&(var)->val, i)
00251 #define atomic_cmpxchg(var, old, new_v) \
00252                 atomic_cmpxchg_int(&(var)->val, old, new_v)
00253 #define atomic_add(var, v) atomic_add_int(&(var)->val, (v))
00254 
00255 
00256 /* with integrated membar */
00257 
00258 #define mb_atomic_set_int(v, i) \
00259         do{ \
00260                 membar(); \
00261                 atomic_set_int(v, i); \
00262         }while(0)
00263 
00264 
00265 
00266 inline static int mb_atomic_get_int(volatile int* v)
00267 {
00268         membar();
00269         return atomic_get_int(v);
00270 }
00271 
00272 
00273 #define mb_atomic_inc_int(v) \
00274         do{ \
00275                 membar(); \
00276                 atomic_inc_int(v); \
00277         }while(0)
00278 
00279 #define mb_atomic_dec_int(v) \
00280         do{ \
00281                 membar(); \
00282                 atomic_dec_int(v); \
00283         }while(0)
00284 
00285 #define mb_atomic_or_int(v, m) \
00286         do{ \
00287                 membar(); \
00288                 atomic_or_int(v, m); \
00289         }while(0)
00290 
00291 #define mb_atomic_and_int(v, m) \
00292         do{ \
00293                 membar(); \
00294                 atomic_and_int(v, m); \
00295         }while(0)
00296 
00297 inline static int mb_atomic_inc_and_test_int(volatile int* v)
00298 {
00299         membar();
00300         return atomic_inc_and_test_int(v);
00301 }
00302 
00303 inline static int mb_atomic_dec_and_test_int(volatile int* v)
00304 {
00305         membar();
00306         return atomic_dec_and_test_int(v);
00307 }
00308 
00309 
00310 inline static int mb_atomic_get_and_set_int(volatile int* v, int i)
00311 {
00312         membar();
00313         return atomic_get_and_set_int(v, i);
00314 }
00315 
00316 inline static int mb_atomic_cmpxchg_int(volatile int* v, int o, int n)
00317 {
00318         membar();
00319         return atomic_cmpxchg_int(v, o, n);
00320 }
00321 
00322 inline static int mb_atomic_add_int(volatile int* v, int i)
00323 {
00324         membar();
00325         return atomic_add_int(v, i);
00326 }
00327 
00328 
00329 
00330 #define mb_atomic_set_long(v, i) \
00331         do{ \
00332                 membar(); \
00333                 atomic_set_long(v, i); \
00334         }while(0)
00335 
00336 
00337 
00338 inline static long mb_atomic_get_long(volatile long* v)
00339 {
00340         membar();
00341         return atomic_get_long(v);
00342 }
00343 
00344 
00345 #define mb_atomic_inc_long(v) \
00346         do{ \
00347                 membar(); \
00348                 atomic_inc_long(v); \
00349         }while(0)
00350 
00351 
00352 #define mb_atomic_dec_long(v) \
00353         do{ \
00354                 membar(); \
00355                 atomic_dec_long(v); \
00356         }while(0)
00357 
00358 #define mb_atomic_or_long(v, m) \
00359         do{ \
00360                 membar(); \
00361                 atomic_or_long(v, m); \
00362         }while(0)
00363 
00364 #define mb_atomic_and_long(v, m) \
00365         do{ \
00366                 membar(); \
00367                 atomic_and_long(v, m); \
00368         }while(0)
00369 
00370 inline static long mb_atomic_inc_and_test_long(volatile long* v)
00371 {
00372         membar();
00373         return atomic_inc_and_test_long(v);
00374 }
00375 
00376 inline static long mb_atomic_dec_and_test_long(volatile long* v)
00377 {
00378         membar();
00379         return atomic_dec_and_test_long(v);
00380 }
00381 
00382 
00383 inline static long mb_atomic_get_and_set_long(volatile long* v, long l)
00384 {
00385         membar();
00386         return atomic_get_and_set_long(v, l);
00387 }
00388 
00389 
00390 inline static long mb_atomic_cmpxchg_long(volatile long* v, long o, long n)
00391 {
00392         membar();
00393         return atomic_cmpxchg_long(v, o, n);
00394 }
00395 
00396 inline static long mb_atomic_add_long(volatile long* v, long i)
00397 {
00398         membar();
00399         return atomic_add_long(v, i);
00400 }
00401 
00402 
00403 #define mb_atomic_inc(var) mb_atomic_inc_int(&(var)->val)
00404 #define mb_atomic_dec(var) mb_atomic_dec_int(&(var)->val)
00405 #define mb_atomic_and(var, mask) mb_atomic_and_int(&(var)->val, (mask))
00406 #define mb_atomic_or(var, mask)  mb_atomic_or_int(&(var)->val, (mask))
00407 #define mb_atomic_dec_and_test(var) mb_atomic_dec_and_test_int(&(var)->val)
00408 #define mb_atomic_inc_and_test(var) mb_atomic_inc_and_test_int(&(var)->val)
00409 #define mb_atomic_get(var)      mb_atomic_get_int(&(var)->val)
00410 #define mb_atomic_set(var, i)   mb_atomic_set_int(&(var)->val, i)
00411 #define mb_atomic_get_and_set(var, i) mb_atomic_get_and_set_int(&(var)->val, i)
00412 #define mb_atomic_cmpxchg(var, o, n) mb_atomic_cmpxchg_int(&(var)->val, o, n)
00413 #define mb_atomic_add(var, i) mb_atomic_add_int(&(var)->val, i)
00414 
00415 
00416 #endif