[BACK]Return to lock.h CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / arch / x86 / include

Annotation of src/sys/arch/x86/include/lock.h, Revision 1.27

1.27    ! christos    1: /*     $NetBSD: lock.h,v 1.26 2012/10/11 11:12:21 apb Exp $    */
1.1       fvdl        2:
                      3: /*-
1.12      ad          4:  * Copyright (c) 2000, 2006 The NetBSD Foundation, Inc.
1.1       fvdl        5:  * All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to The NetBSD Foundation
1.12      ad          8:  * by Jason R. Thorpe and Andrew Doran.
1.1       fvdl        9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  *
                     19:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     20:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     21:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     22:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     23:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     24:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     25:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     26:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     27:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     28:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     29:  * POSSIBILITY OF SUCH DAMAGE.
                     30:  */
                     31:
                     32: /*
                     33:  * Machine-dependent spin lock operations.
                     34:  */
                     35:
1.9       yamt       36: #ifndef _X86_LOCK_H_
                     37: #define        _X86_LOCK_H_
1.1       fvdl       38:
1.25      pooka      39: #include <sys/param.h>
                     40:
1.15      skrll      41: static __inline int
                     42: __SIMPLELOCK_LOCKED_P(__cpu_simple_lock_t *__ptr)
                     43: {
                     44:        return *__ptr == __SIMPLELOCK_LOCKED;
                     45: }
                     46:
                     47: static __inline int
                     48: __SIMPLELOCK_UNLOCKED_P(__cpu_simple_lock_t *__ptr)
                     49: {
                     50:        return *__ptr == __SIMPLELOCK_UNLOCKED;
                     51: }
                     52:
1.16      skrll      53: static __inline void
                     54: __cpu_simple_lock_set(__cpu_simple_lock_t *__ptr)
                     55: {
                     56:
                     57:        *__ptr = __SIMPLELOCK_LOCKED;
                     58: }
                     59:
                     60: static __inline void
                     61: __cpu_simple_lock_clear(__cpu_simple_lock_t *__ptr)
                     62: {
                     63:
                     64:        *__ptr = __SIMPLELOCK_UNLOCKED;
                     65: }
                     66:
1.25      pooka      67: #ifdef _HARDKERNEL
1.27    ! christos   68: # include <machine/cpufunc.h>
        !            69: # define SPINLOCK_SPIN_HOOK    /* nothing */
        !            70: # ifdef SPINLOCK_BACKOFF_HOOK
        !            71: #  undef SPINLOCK_BACKOFF_HOOK
        !            72: # endif
        !            73: # define SPINLOCK_BACKOFF_HOOK x86_pause()
        !            74: # define SPINLOCK_INLINE
        !            75: #else /* !_HARDKERNEL */
        !            76: # define SPINLOCK_BODY
        !            77: # define SPINLOCK_INLINE static __inline __unused
        !            78: #endif /* _HARDKERNEL */
        !            79:
        !            80: SPINLOCK_INLINE void   __cpu_simple_lock_init(__cpu_simple_lock_t *);
        !            81: SPINLOCK_INLINE void   __cpu_simple_lock(__cpu_simple_lock_t *);
        !            82: SPINLOCK_INLINE int    __cpu_simple_lock_try(__cpu_simple_lock_t *);
        !            83: SPINLOCK_INLINE void   __cpu_simple_unlock(__cpu_simple_lock_t *);
1.20      ad         84:
1.27    ! christos   85: #ifdef SPINLOCK_BODY
        !            86: SPINLOCK_INLINE void
1.1       fvdl       87: __cpu_simple_lock_init(__cpu_simple_lock_t *lockp)
                     88: {
                     89:
                     90:        *lockp = __SIMPLELOCK_UNLOCKED;
1.7       yamt       91:        __insn_barrier();
1.1       fvdl       92: }
                     93:
1.27    ! christos   94: SPINLOCK_INLINE int
1.20      ad         95: __cpu_simple_lock_try(__cpu_simple_lock_t *lockp)
1.1       fvdl       96: {
1.20      ad         97:        uint8_t val;
1.1       fvdl       98:
1.20      ad         99:        val = __SIMPLELOCK_LOCKED;
                    100:        __asm volatile ("xchgb %0,(%2)" :
1.26      apb       101:            "=qQ" (val)
1.20      ad        102:            :"0" (val), "r" (lockp));
1.7       yamt      103:        __insn_barrier();
1.20      ad        104:        return val == __SIMPLELOCK_UNLOCKED;
1.1       fvdl      105: }
                    106:
1.27    ! christos  107: SPINLOCK_INLINE void
1.20      ad        108: __cpu_simple_lock(__cpu_simple_lock_t *lockp)
1.1       fvdl      109: {
                    110:
1.20      ad        111:        while (!__cpu_simple_lock_try(lockp))
                    112:                /* nothing */;
1.7       yamt      113:        __insn_barrier();
1.1       fvdl      114: }
                    115:
1.12      ad        116: /*
                    117:  * Note on x86 memory ordering
                    118:  *
                    119:  * When releasing a lock we must ensure that no stores or loads from within
                    120:  * the critical section are re-ordered by the CPU to occur outside of it:
                    121:  * they must have completed and be visible to other processors once the lock
                    122:  * has been released.
                    123:  *
                    124:  * NetBSD usually runs with the kernel mapped (via MTRR) in a WB (write
                    125:  * back) memory region.  In that case, memory ordering on x86 platforms
                    126:  * looks like this:
                    127:  *
                    128:  * i386                All loads/stores occur in instruction sequence.
                    129:  *
                    130:  * i486                All loads/stores occur in instruction sequence.  In
                    131:  * Pentium     exceptional circumstances, loads can be re-ordered around
                    132:  *             stores, but for the purposes of releasing a lock it does
                    133:  *             not matter.  Stores may not be immediately visible to other
                    134:  *             processors as they can be buffered.  However, since the
                    135:  *             stores are buffered in order the lock release will always be
                    136:  *             the last operation in the critical section that becomes
                    137:  *             visible to other CPUs.
                    138:  *
                    139:  * Pentium Pro The "Intel 64 and IA-32 Architectures Software Developer's
                    140:  * onwards     Manual" volume 3A (order number 248966) says that (1) "Reads
                    141:  *             can be carried out speculatively and in any order" and (2)
                    142:  *             "Reads can pass buffered stores, but the processor is
                    143:  *             self-consistent.".  This would be a problem for the below,
                    144:  *             and would mandate a locked instruction cycle or load fence
                    145:  *             before releasing the simple lock.
                    146:  *
                    147:  *             The "Intel Pentium 4 Processor Optimization" guide (order
                    148:  *             number 253668-022US) says: "Loads can be moved before stores
                    149:  *             that occurred earlier in the program if they are not
                    150:  *             predicted to load from the same linear address.".  This is
                    151:  *             not a problem since the only loads that can be re-ordered
                    152:  *             take place once the lock has been released via a store.
                    153:  *
                    154:  *             The above two documents seem to contradict each other,
                    155:  *             however with the exception of early steppings of the Pentium
                    156:  *             Pro, the second document is closer to the truth: a store
                    157:  *             will always act as a load fence for all loads that precede
                    158:  *             the store in instruction order.
                    159:  *
                    160:  *             Again, note that stores can be buffered and will not always
                    161:  *             become immediately visible to other CPUs: they are however
                    162:  *             buffered in order.
                    163:  *
                    164:  * AMD64       Stores occur in order and are buffered.  Loads can be
                    165:  *             reordered, however stores act as load fences, meaning that
                    166:  *             loads can not be reordered around stores.
                    167:  */
1.27    ! christos  168: SPINLOCK_INLINE void
1.1       fvdl      169: __cpu_simple_unlock(__cpu_simple_lock_t *lockp)
                    170: {
                    171:
1.7       yamt      172:        __insn_barrier();
1.1       fvdl      173:        *lockp = __SIMPLELOCK_UNLOCKED;
                    174: }
                    175:
1.27    ! christos  176: #endif /* SPINLOCK_BODY */
1.1       fvdl      177:
1.9       yamt      178: #endif /* _X86_LOCK_H_ */

CVSweb <webmaster@jp.NetBSD.org>