atomic.h

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2005, 2007, 2008  Internet Systems Consortium, Inc. ("ISC")
00003  *
00004  * Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH
00009  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00010  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00011  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00012  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00013  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00014  * PERFORMANCE OF THIS SOFTWARE.
00015  */
00016 
00017 /* $Id: atomic.h,v 1.10 2008/01/24 23:47:00 tbox Exp $ */
00018 
00019 #ifndef ISC_ATOMIC_H
00020 #define ISC_ATOMIC_H 1
00021 
00022 #include <isc/platform.h>
00023 #include <isc/types.h>
00024 
00025 #ifdef ISC_PLATFORM_USEGCCASM
00026 /*
00027  * This routine atomically increments the value stored in 'p' by 'val', and
00028  * returns the previous value.
00029  */
00030 static __inline__ isc_int32_t
00031 isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) {
00032         isc_int32_t prev = val;
00033 
00034         __asm__ volatile(
00035 #ifdef ISC_PLATFORM_USETHREADS
00036                 "lock;"
00037 #endif
00038                 "xadd %0, %1"
00039                 :"=q"(prev)
00040                 :"m"(*p), "0"(prev)
00041                 :"memory", "cc");
00042 
00043         return (prev);
00044 }
00045 
00046 #ifdef ISC_PLATFORM_HAVEXADDQ
00047 static __inline__ isc_int64_t
00048 isc_atomic_xaddq(isc_int64_t *p, isc_int64_t val) {
00049         isc_int64_t prev = val;
00050 
00051         __asm__ volatile(
00052 #ifdef ISC_PLATFORM_USETHREADS
00053             "lock;"
00054 #endif
00055             "xaddq %0, %1"
00056             :"=q"(prev)
00057             :"m"(*p), "0"(prev)
00058             :"memory", "cc");
00059 
00060         return (prev);
00061 }
00062 #endif /* ISC_PLATFORM_HAVEXADDQ */
00063 
00064 /*
00065  * This routine atomically stores the value 'val' in 'p'.
00066  */
00067 static __inline__ void
00068 isc_atomic_store(isc_int32_t *p, isc_int32_t val) {
00069         __asm__ volatile(
00070 #ifdef ISC_PLATFORM_USETHREADS
00071                 /*
00072                  * xchg should automatically lock memory, but we add it
00073                  * explicitly just in case (it at least doesn't harm)
00074                  */
00075                 "lock;"
00076 #endif
00077 
00078                 "xchgl %1, %0"
00079                 :
00080                 : "r"(val), "m"(*p)
00081                 : "memory");
00082 }
00083 
00084 /*
00085  * This routine atomically replaces the value in 'p' with 'val', if the
00086  * original value is equal to 'cmpval'.  The original value is returned in any
00087  * case.
00088  */
00089 static __inline__ isc_int32_t
00090 isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) {
00091         __asm__ volatile(
00092 #ifdef ISC_PLATFORM_USETHREADS
00093                 "lock;"
00094 #endif
00095                 "cmpxchgl %1, %2"
00096                 : "=a"(cmpval)
00097                 : "r"(val), "m"(*p), "a"(cmpval)
00098                 : "memory");
00099 
00100         return (cmpval);
00101 }
00102 
00103 #elif defined(ISC_PLATFORM_USESTDASM)
00104 /*
00105  * The followings are "generic" assembly code which implements the same
00106  * functionality in case the gcc extension cannot be used.  It should be
00107  * better to avoid inlining below, since we directly refer to specific
00108  * positions of the stack frame, which would not actually point to the
00109  * intended address in the embedded mnemonic.
00110  */
00111 #include <isc/util.h>           /* for 'UNUSED' macro */
00112 
00113 static isc_int32_t
00114 isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) {
00115         UNUSED(p);
00116         UNUSED(val);
00117 
00118         __asm (
00119                 "movl 8(%ebp), %ecx\n"
00120                 "movl 12(%ebp), %edx\n"
00121 #ifdef ISC_PLATFORM_USETHREADS
00122                 "lock;"
00123 #endif
00124                 "xadd %edx, (%ecx)\n"
00125 
00126                 /*
00127                  * set the return value directly in the register so that we
00128                  * can avoid guessing the correct position in the stack for a
00129                  * local variable.
00130                  */
00131                 "movl %edx, %eax"
00132                 );
00133 }
00134 
00135 static void
00136 isc_atomic_store(isc_int32_t *p, isc_int32_t val) {
00137         UNUSED(p);
00138         UNUSED(val);
00139 
00140         __asm (
00141                 "movl 8(%ebp), %ecx\n"
00142                 "movl 12(%ebp), %edx\n"
00143 #ifdef ISC_PLATFORM_USETHREADS
00144                 "lock;"
00145 #endif
00146                 "xchgl (%ecx), %edx\n"
00147                 );
00148 }
00149 
00150 static isc_int32_t
00151 isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) {
00152         UNUSED(p);
00153         UNUSED(cmpval);
00154         UNUSED(val);
00155 
00156         __asm (
00157                 "movl 8(%ebp), %ecx\n"
00158                 "movl 12(%ebp), %eax\n" /* must be %eax for cmpxchgl */
00159                 "movl 16(%ebp), %edx\n"
00160 #ifdef ISC_PLATFORM_USETHREADS
00161                 "lock;"
00162 #endif
00163 
00164                 /*
00165                  * If (%ecx) == %eax then (%ecx) := %edx.
00166                  % %eax is set to old (%ecx), which will be the return value.
00167                  */
00168                 "cmpxchgl %edx, (%ecx)"
00169                 );
00170 }
00171 #else /* !ISC_PLATFORM_USEGCCASM && !ISC_PLATFORM_USESTDASM */
00172 
00173 #error "unsupported compiler.  disable atomic ops by --disable-atomic"
00174 
00175 #endif
00176 #endif /* ISC_ATOMIC_H */

Generated on Tue Apr 28 17:41:03 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha