Main Page | Class List | Directories | File List | Class Members | File Members

pike_cpulib.h

Go to the documentation of this file.
00001 /*
00002 || This file is part of Pike. For copyright information see COPYRIGHT.
00003 || Pike is distributed under GPL, LGPL and MPL. See the file COPYING
00004 || for more information.
00005 || $Id: pike_cpulib.h,v 1.12 2004/06/02 00:08:12 nilsson Exp $
00006 */
00007 
00008 #ifndef PIKE_CPULIB_H
00009 #define PIKE_CPULIB_H
00010 
00011 /* FIXME: Should we have an #ifdef PIKE_RUN_UNLOCKED here? -Hubbe
00012  * Good side: No problems compiling unless --run-unlocked is used
00013  * Bad side: Can't use these things for other purposes..
00014  */
00015 /* Since the memlock stuff doesn't work yet, I disable the code for now.
00016  *      /grubba
00017  */
00018 #ifdef PIKE_RUN_UNLOCKED
00019 
00020 #define pike_atomic_fool_gcc(x) (*(volatile struct { int a[100]; } *)x)
00021 
00022 
00023 /* These will work on any cpu, but should only be used as a
00024  * last resort. We must also define PIKE_NEED_MEMLOCK if we
00025  * use these. /Hubbe
00026  */
00027 #define BEGIN_MEMORY_LOCK(ADDR) do { \
00028     PIKE_MUTEX_T *pike_mem_mutex=pike_memory_locks+ \
00029         ((unsigned long)(ADDR))%PIKE_MEM_HASH; \
00030     mt_lock(pike_mem_mutex)
00031 
00032 #define END_MEMORY_LOCK()  \
00033     mt_unlock(pike_mem_mutex);  \
00034   }while(0)
00035 
00036 #define pike_memlock(ADDR) do{                          \
00037     PIKE_MUTEX_T *pike_mem_mutex=pike_memory_locks+     \
00038         ((unsigned long)(ADDR))%PIKE_MEM_HASH;          \
00039     mt_lock(pike_mem_mutex)                             \
00040 }while(0)
00041 
00042 #define pike_unmemlock(ADDR) do{                        \
00043     PIKE_MUTEX_T *pike_mem_mutex=pike_memory_locks+     \
00044         ((unsigned long)(ADDR))%PIKE_MEM_HASH;          \
00045     mt_unlock(pike_mem_mutex)                           \
00046 }while(0)
00047 
00048 #define PIKE_NEED_MEMLOCK
00049 
00050 /* Autoconf this? */
00051 #if defined(__i386__) && defined(__GNUC__)
00052 
00053 /*
00054  * ia32 general purpose registers
00055  * "a" = %eax, "b" = %edx, "c" = %ecx, "d" = %edx
00056  * "S" = %esi, "D" = %edi, "B" = %ebp
00057  */
00058 
00059 
00060 #define PIKE_HAS_INC32
00061 static INLINE void pike_atomic_inc32(volatile INT32 *v)
00062 {
00063   __asm__ __volatile__("lock ; incl %0"
00064                        :"=m" (pike_atomic_fool_gcc(v))
00065                        :"m" (pike_atomic_fool_gcc(v))
00066                        :"cc");
00067 }
00068 
00069 
00070 #define PIKE_HAS_DEC_AND_TEST32
00071 static INLINE int pike_atomic_dec_and_test32(INT32 *v)
00072 {
00073   unsigned char c;
00074 
00075   __asm__ __volatile__("lock ; decl %0; setne %1"
00076                        :"=m" (pike_atomic_fool_gcc(v)), "=qm" (c)
00077                        :"m" (pike_atomic_fool_gcc(v))
00078                        :"cc");
00079   return c;
00080 }
00081 
00082 #define PIKE_HAS_COMPARE_AND_SWAP32
00083 static INLINE int
00084 pike_atomic_compare_and_swap32 (INT32 *p, INT32 oldval, INT32 newval)
00085 {
00086   char ret;
00087   INT32 readval;
00088 
00089   __asm__ __volatile__ ("lock; cmpxchgl %3, %1; sete %0"
00090                         : "=q" (ret), "=m" (*p), "=a" (readval)
00091                         : "r" (newval), "m" (*p), "a" (oldval)
00092                         : "cc", "memory");
00093   return ret;
00094 }
00095 
00096 
00097 /* NOT USED */
00098 #define PIKE_HAS_COMPARE_AND_SWAP64
00099 static INLINE int
00100 pike_atomic_compare_and_swap64 (INT64 *p, INT64 oldval, INT64 newval)
00101 {
00102   char ret;
00103 #define HIGH(X) ((INT32 *)&(X))[1]
00104 #define LOW(X) ((INT32 *)&(X))[0]
00105 
00106 #if 1
00107   INT32 t1, t2, t3;
00108 /*fprintf(stderr,"cas64(%p(%llx),%llx,%llx) << %d\n",p,*p,oldval,newval,ret);*/
00109 #if 0
00110   __asm__ __volatile__ (
00111     "xchgl %%ebx, %%edi ;"
00112     "lock; cmpxchg8b (%%esi); sete %%al;"
00113     "movl  %%edi, %%ebx; "
00114     "movb  %%al, %0 "
00115     :"=q" (ret),
00116      "=a" (t1),"=d" (t2),"=D" (t3)
00117     :"S" (p),
00118      "1" (LOW(oldval)), "2" (HIGH(oldval)),
00119      "3" (LOW(newval)), "c" (HIGH(newval))
00120     :"cc", "memory");
00121 #else
00122   __asm__ __volatile__ (
00123     "xchgl %%ebx, %%edi ;"
00124     "lock; cmpxchg8b (%%esi); sete %%al;"
00125     "movl  %%edi, %%ebx; "
00126     "movb  %%al, %0 "
00127     :"=q" (ret),
00128      "=a" (t1),"=d" (t2),"=D" (t3)
00129     :"S" (p),
00130      "a" (LOW(oldval)), "d" (HIGH(oldval)),
00131      "D" (LOW(newval)), "c" (HIGH(newval))
00132     :"cc", "memory");
00133 #endif
00134 /*fprintf(stderr,"cas64(%p(%llx),%llx,%llx) => %d\n",p,*p,oldval,newval,ret);*/
00135 #else
00136   INT32 readval;
00137   /* this doesn't work because GCC use %ebp for PIC code */
00138   __asm__ __volatile__ ("lock; cmpxchg8b (%1); sete %0"
00139                         :"=q" (ret), "=m" (*p)
00140                         :"r" (newval), "m" (*p),
00141                          "a" (LOW(oldval)),"d" (HIGH(oldval)),
00142                          "b" (LOW(newval)),"c" (HIGH(newval))
00143                         : "cc", "memory");
00144 #endif
00145   return ret;
00146 }
00147 
00148 #endif /* __i386__ && __GNUC__ */
00149 
00150 #if defined(__ia64__) && defined(__GNUC__)
00151 
00152 #define PIKE_HAS_COMPARE_AND_SWAP32
00153 
00154 static INLINE int
00155 pike_atomic_compare_and_swap32 (INT32 *p, INT32 oldval, INT32 newval)
00156 {
00157   INT32 ret;
00158 
00159   __asm__ __volatile__ ("mov ar.ccv = %1;\n"
00160                         "\t;;\n"
00161                         "\tcmpxchg4.rel.nta %0 = [%2], %3, ar.ccv"
00162                         : "=r" (ret)
00163                         : "r" (oldval), "r" (p), "r" (newval)
00164                         : "memory", "ar.ccv");
00165   return ret == oldval;
00166 }
00167 
00168 #endif /* __ia64__ && __GNUC__ */
00169 
00170 #if defined(_M_IA64)
00171 
00172 #define PIKE_HAS_COMPARE_AND_SWAP32
00173 
00174 static INLINE int
00175 pike_atomic_compare_and_swap32 (INT32 *p, INT32 oldval, INT32 newval)
00176 {
00177   return _InterlockedCompareExchange(p, newval, oldval) == oldval;
00178 }
00179 
00180 #endif /* _M_IA64 */
00181 
00182 #if defined(__sparc_v9__) && defined(__GNUC__)
00183 
00184 #define PIKE_HAS_COMPARE_AND_SWAP32
00185 
00186 static INLINE int
00187 pike_atomic_compare_and_swap32 (INT32 *p, INT32 oldval, INT32 newval)
00188 {
00189   __asm__ __volatile__ ("membar #LoadStore\n"
00190                         "cas [%2], %3, %0"
00191                         : "=r" (newval)
00192                         : "0" (newval), "r" (p), "r" (oldval)
00193                         : "memory");
00194   return newval == oldval;
00195 }
00196 
00197 #endif /* __sparc_v9__ && __GNUC__ */
00198 
00199 #if defined(__m68k__) && defined(__GNUC__)
00200 
00201 
00202 #define PIKE_HAS_COMPARE_AND_SWAP32
00203 
00204 static INLINE int
00205 pike_atomic_compare_and_swap32 (INT32 *p, INT32 oldval, INT32 newval)
00206 {
00207   INT32 cmpval = oldval;
00208 
00209   /* if (oldval == *p) {
00210    *   *p = newval;
00211    * } else {
00212    *   oldval = *p;
00213    * }
00214    */
00215   __asm__ __volatile__ ("casl %0, %3, %1;"
00216                         : "=d" (oldval), "=m", (*p)
00217                         : "0" (oldval), "d" (newval), "0" (p)
00218                         : "memory");
00219   return oldval == cmpval;
00220 }
00221 
00222 #endif /* __m68k__ && __GNUC__ */
00223 
00224 
00225 
00226 /*
00227  * These functions are used if we don't have
00228  * compare-and-swap instructions available
00229  */
00230 #ifndef PIKE_HAS_COMPARE_AND_SWAP32
00231 
00232 #define PIKE_HAS_COMPARE_AND_SWAP32
00233 #undef PIKE_NEED_MEMLOCK
00234 #define PIKE_NEED_MEMLOCK
00235 
00236 #include "threads.h"
00237 
00238 static INLINE int
00239 pike_atomic_compare_and_swap32 (INT32 *p, INT32 oldval, INT32 newval)
00240 {
00241   int ret;
00242   BEGIN_MEMORY_LOCK(p);
00243   if(ret == (*p == oldval)) *p=newval;
00244   END_MEMORY_LOCK();
00245   return ret;
00246 }
00247 
00248 
00249 #ifndef PIKE_HAS_INC32
00250 #define PIKE_HAS_INC32
00251 static INLINE void pike_atomic_inc32(INT32 *ref)
00252 {
00253   BEGIN_MEMORY_LOCK(p);
00254   ref++;
00255   END_MEMORY_LOCK();
00256 }
00257 #endif /* PIKE_HAS_INC32 */
00258 
00259 #ifndef PIKE_HAS_DEC_AND_TEST32
00260 #define PIKE_HAS_DEC_AND_TEST32
00261 static INLINE int pike_atomic_dec_and_test32(INT32 *ref)
00262 {
00263   INT32 ret;
00264   BEGIN_MEMORY_LOCK(p);
00265   ret=--ref;
00266   END_MEMORY_LOCK();
00267   return ret;
00268 }
00269 #endif /*  PIKE_HAS_DEC_AND_TEST32 */
00270 
00271 
00272 
00273 #ifndef PIKE_HAS_SWAP32
00274 #define PIKE_HAS_SWAP32
00275 static INLINE INT32 pike_atomic_swap32(INT32 *addr, INT32 newval)
00276 {
00277   INT32 ret;
00278   BEGIN_MEMORY_LOCK(p);
00279   ret=*addr;
00280   *addr=newval;
00281   END_MEMORY_LOCK();
00282   return ret;
00283 }
00284 #endif
00285 
00286 #endif /* PIKE_HAS_COMPARE_AND_SWAP32 */
00287 
00288 #if !defined(PIKE_HAS_COMPARE_AND_SWAP64) && defined(INT64)
00289 
00290 #define PIKE_HAS_COMPARE_AND_SWAP64
00291 #undef PIKE_NEED_MEMLOCK
00292 #define PIKE_NEED_MEMLOCK
00293 
00294 #include "threads.h"
00295 
00296 static INLINE int
00297 pike_atomic_compare_and_swap64 (INT64 *p, INT64 oldval, INT64 newval)
00298 {
00299   int ret;
00300   BEGIN_MEMORY_LOCK(p);
00301   if(ret == (*p == oldval)) *p=newval;
00302   END_MEMORY_LOCK();
00303   return ret;
00304 }
00305 
00306 
00307 #ifndef PIKE_HAS_SWAP64
00308 #define PIKE_HAS_SWAP64
00309 static INLINE INT64 pike_atomic_swap64(INT64 *addr, INT64 newval)
00310 {
00311   INT64 ret;
00312   BEGIN_MEMORY_LOCK(p);
00313   ret=*addr;
00314   *addr=newval;
00315   END_MEMORY_LOCK();
00316   return ret;
00317 }
00318 #endif
00319 
00320 
00321 #ifndef PIKE_HAS_SET64
00322 #define PIKE_HAS_SET64
00323 static INLINE void pike_atomic_set64(INT64 *addr, INT64 newval)
00324 {
00325   BEGIN_MEMORY_LOCK(p);
00326   *addr=newval;
00327   END_MEMORY_LOCK();
00328 }
00329 #endif
00330 
00331 #ifndef PIKE_HAS_GET64
00332 #define PIKE_HAS_GET64
00333 static INLINE INT64 pike_atomic_get64(INT64 *addr)
00334 {
00335   INT64 ret;
00336   BEGIN_MEMORY_LOCK(p);
00337   ret=*addr;
00338   END_MEMORY_LOCK();
00339   return ret;
00340 }
00341 #endif
00342 
00343 
00344 #endif /* PIKE_HAS_COMPARE_AND_SWAP64 */
00345 
00346 
00347 
00348 /* These functions are used if we have
00349  * compare-and-swap, but not the rest of
00350  * the atomic functions
00351  */
00352 
00353 #if defined(PIKE_HAS_COMPARE_AND_SWAP32) && !defined(PIKE_HAS_INC32)
00354 #define PIKE_HAS_INC32
00355 static INLINE void pike_atomic_inc32(INT32 *ref)
00356 {
00357   INT32 oldrefs;
00358   do 
00359     oldrefs=*ref;
00360   while(! pike_atomic_compare_and_swap32(ref, oldrefs, oldrefs+1));
00361 }
00362 #endif
00363 
00364 
00365 #if defined(PIKE_HAS_COMPARE_AND_SWAP32) && !defined(PIKE_HAS_DEC_AND_TEST32)
00366 #define PIKE_HAS_DEC_AND_TEST32
00367 static INLINE int pike_atomic_dec_and_test32(INT32 *ref)
00368 {
00369   INT32 oldrefs;
00370   do 
00371     oldrefs=*ref;
00372   while(! pike_atomic_compare_and_swap32(ref, oldrefs, oldrefs-1));
00373   return oldrefs-1;
00374 }
00375 #endif
00376 
00377 
00378 #if defined(PIKE_HAS_COMPARE_AND_SWAP32) && !defined(PIKE_HAS_SWAP32)
00379 #define PIKE_HAS_SWAP32
00380 static INLINE INT32 pike_atomic_swap32(INT32 *addr, INT32 newval)
00381 {
00382   INT32 ret;
00383   do
00384   {
00385     ret=*addr;
00386   }while(!pike_atomic_compare_and_swap32(addr, ret, newval));
00387   return ret;
00388 }
00389 #endif
00390 
00391 
00392 #if defined(PIKE_HAS_COMPARE_AND_SWAP64) && !defined(PIKE_HAS_SWAP64)
00393 #define PIKE_HAS_SWAP64
00394 static INLINE INT64 pike_atomic_swap64(INT64 *addr, INT64 newval)
00395 {
00396   INT64 ret;
00397   do
00398   {
00399     ret=*addr;
00400   }while(!pike_atomic_compare_and_swap64(addr, ret, newval));
00401   return ret;
00402 }
00403 #endif
00404 
00405 
00406 
00407 #if defined(PIKE_HAS_SWAP64) && !defined(PIKE_HAS_SET64)
00408 #define PIKE_HAS_SET64
00409 static INLINE void pike_atomic_set64(INT64 *addr, INT64 newval)
00410 {
00411   pike_atomic_swap64(addr, newval);
00412 }
00413 #endif
00414 
00415 #if defined(PIKE_HAS_COMPARE_AND_SWAP64) && !defined(PIKE_HAS_GET64)
00416 #define PIKE_HAS_GET64
00417 static INLINE INT64 pike_atomic_get64(INT64 *addr)
00418 {
00419   INT64 ret;
00420   do
00421   {
00422     ret=*addr;
00423   }while(!pike_atomic_compare_and_swap64(addr, ret, ret));
00424   return ret;
00425 }
00426 #endif
00427 
00428 /* End emulating functions */
00429 
00430 #endif /* PIKE_RUN_UNLOCKED */
00431 
00432 #ifdef PIKE_NEED_MEMLOCK
00433 extern void init_pike_cpulib(void);
00434 #else
00435 #define init_pike_cpulib()
00436 #endif
00437 
00438 #endif /* PIKE_CPULIB_H */

Generated on Fri Jul 22 23:44:26 2005 for Pike by  doxygen 1.3.9.1