[BACK]Return to kern_rwlock.c CVS log [TXT][DIR] Up to [local] / sys / kern

Annotation of sys/kern/kern_rwlock.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: kern_rwlock.c,v 1.13 2007/05/13 04:52:32 tedu Exp $   */
                      2:
                      3: /*
                      4:  * Copyright (c) 2002, 2003 Artur Grabowski <art@openbsd.org>
                      5:  * All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  *
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. The name of the author may not be used to endorse or promote products
                     14:  *    derived from this software without specific prior written permission.
                     15:  *
                     16:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
                     17:  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
                     18:  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
                     19:  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
                     20:  * EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLUDING, BUT NOT LIMITED TO,
                     21:  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
                     22:  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
                     23:  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
                     24:  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
                     25:  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     26:  */
                     27:
                     28: #include <sys/param.h>
                     29: #include <sys/systm.h>
                     30: #include <sys/proc.h>
                     31: #include <sys/rwlock.h>
                     32: #include <sys/limits.h>
                     33:
                     34: #include <machine/lock.h>
                     35:
                     36: /* XXX - temporary measure until proc0 is properly aligned */
                     37: #define RW_PROC(p) (((long)p) & ~RWLOCK_MASK)
                     38:
                     39: /*
                     40:  * Magic wand for lock operations. Every operation checks if certain
                     41:  * flags are set and if they aren't, it increments the lock with some
                     42:  * value (that might need some computing in a few cases). If the operation
                     43:  * fails, we need to set certain flags while waiting for the lock.
                     44:  *
                     45:  * RW_WRITE    The lock must be completely empty. We increment it with
                     46:  *             RWLOCK_WRLOCK and the proc pointer of the holder.
                     47:  *             Sets RWLOCK_WAIT|RWLOCK_WRWANT while waiting.
                     48:  * RW_READ     RWLOCK_WRLOCK|RWLOCK_WRWANT may not be set. We increment
                     49:  *             with RWLOCK_READ_INCR. RWLOCK_WAIT while waiting.
                     50:  */
                     51: static const struct rwlock_op {
                     52:        unsigned long inc;
                     53:        unsigned long check;
                     54:        unsigned long wait_set;
                     55:        long proc_mult;
                     56:        int wait_prio;
                     57: } rw_ops[] = {
                     58:        {       /* RW_WRITE */
                     59:                RWLOCK_WRLOCK,
                     60:                ULONG_MAX,
                     61:                RWLOCK_WAIT | RWLOCK_WRWANT,
                     62:                1,
                     63:                PLOCK - 4
                     64:        },
                     65:        {       /* RW_READ */
                     66:                RWLOCK_READ_INCR,
                     67:                RWLOCK_WRLOCK,
                     68:                RWLOCK_WAIT,
                     69:                0,
                     70:                PLOCK
                     71:        },
                     72:        {       /* RW_DOWNGRADE */
                     73:                RWLOCK_READ_INCR - RWLOCK_WRLOCK,
                     74:                0,
                     75:                0,
                     76:                -1,
                     77:                PLOCK
                     78:        },
                     79: };
                     80:
                     81: #ifndef __HAVE_MD_RWLOCK
                     82: /*
                     83:  * Simple cases that should be in MD code and atomic.
                     84:  */
                     85: void
                     86: rw_enter_read(struct rwlock *rwl)
                     87: {
                     88:        unsigned long owner = rwl->rwl_owner;
                     89:
                     90:        if (__predict_false((owner & RWLOCK_WRLOCK) ||
                     91:            rw_cas(&rwl->rwl_owner, owner, owner + RWLOCK_READ_INCR)))
                     92:                rw_enter(rwl, RW_READ);
                     93: }
                     94:
                     95: void
                     96: rw_enter_write(struct rwlock *rwl)
                     97: {
                     98:        struct proc *p = curproc;
                     99:
                    100:        if (__predict_false(rw_cas(&rwl->rwl_owner, 0,
                    101:            RW_PROC(p) | RWLOCK_WRLOCK)))
                    102:                rw_enter(rwl, RW_WRITE);
                    103: }
                    104:
                    105: void
                    106: rw_exit_read(struct rwlock *rwl)
                    107: {
                    108:        unsigned long owner = rwl->rwl_owner;
                    109:
                    110:        if (__predict_false((owner & RWLOCK_WAIT) ||
                    111:            rw_cas(&rwl->rwl_owner, owner, owner - RWLOCK_READ_INCR)))
                    112:                rw_exit(rwl);
                    113: }
                    114:
                    115: void
                    116: rw_exit_write(struct rwlock *rwl)
                    117: {
                    118:        unsigned long owner = rwl->rwl_owner;
                    119:
                    120:        if (__predict_false((owner & RWLOCK_WAIT) ||
                    121:            rw_cas(&rwl->rwl_owner, owner, 0)))
                    122:                rw_exit(rwl);
                    123: }
                    124:
                    125: #ifndef rw_cas
                    126: int
                    127: rw_cas(volatile unsigned long *p, unsigned long o, unsigned long n)
                    128: {
                    129:        if (*p != o)
                    130:                return (1);
                    131:        *p = n;
                    132:
                    133:        return (0);
                    134: }
                    135: #endif
                    136:
                    137: #endif
                    138:
                    139: #ifdef DIAGNOSTIC
                    140: /*
                    141:  * Put the diagnostic functions here to keep the main code free
                    142:  * from ifdef clutter.
                    143:  */
                    144: static void
                    145: rw_enter_diag(struct rwlock *rwl, int flags)
                    146: {
                    147:        switch (flags & RW_OPMASK) {
                    148:        case RW_WRITE:
                    149:        case RW_READ:
                    150:                if (RW_PROC(curproc) == RW_PROC(rwl->rwl_owner))
                    151:                        panic("rw_enter: %s locking against myself",
                    152:                            rwl->rwl_name);
                    153:                break;
                    154:        case RW_DOWNGRADE:
                    155:                /*
                    156:                 * If we're downgrading, we must hold the write lock.
                    157:                 */
                    158:                if ((rwl->rwl_owner & RWLOCK_WRLOCK) == 0)
                    159:                        panic("rw_enter: %s downgrade of non-write lock",
                    160:                            rwl->rwl_name);
                    161:                if (RW_PROC(curproc) != RW_PROC(rwl->rwl_owner))
                    162:                        panic("rw_enter: %s downgrade, not holder",
                    163:                            rwl->rwl_name);
                    164:                break;
                    165:
                    166:        default:
                    167:                panic("rw_enter: unknown op 0x%x", flags);
                    168:        }
                    169: }
                    170:
                    171: #else
                    172: #define rw_enter_diag(r, f)
                    173: #endif
                    174:
                    175: void
                    176: rw_init(struct rwlock *rwl, const char *name)
                    177: {
                    178:        rwl->rwl_owner = 0;
                    179:        rwl->rwl_name = name;
                    180: }
                    181:
                    182: int
                    183: rw_enter(struct rwlock *rwl, int flags)
                    184: {
                    185:        const struct rwlock_op *op;
                    186:        struct sleep_state sls;
                    187:        unsigned long inc, o;
                    188:        int error;
                    189:
                    190:        op = &rw_ops[flags & RW_OPMASK];
                    191:
                    192:        inc = op->inc + RW_PROC(curproc) * op->proc_mult;
                    193: retry:
                    194:        while (__predict_false(((o = rwl->rwl_owner) & op->check) != 0)) {
                    195:                unsigned long set = o | op->wait_set;
                    196:                int do_sleep;
                    197:
                    198:                rw_enter_diag(rwl, flags);
                    199:
                    200:                if (flags & RW_NOSLEEP)
                    201:                        return (EBUSY);
                    202:
                    203:                sleep_setup(&sls, rwl, op->wait_prio, rwl->rwl_name);
                    204:                if (flags & RW_INTR)
                    205:                        sleep_setup_signal(&sls, op->wait_prio | PCATCH);
                    206:
                    207:                do_sleep = !rw_cas(&rwl->rwl_owner, o, set);
                    208:
                    209:                sleep_finish(&sls, do_sleep);
                    210:                if ((flags & RW_INTR) &&
                    211:                    (error = sleep_finish_signal(&sls)) != 0)
                    212:                        return (error);
                    213:                if (flags & RW_SLEEPFAIL)
                    214:                        return (EAGAIN);
                    215:        }
                    216:
                    217:        if (__predict_false(rw_cas(&rwl->rwl_owner, o, o + inc)))
                    218:                goto retry;
                    219:
                    220:        /*
                    221:         * If old lock had RWLOCK_WAIT and RWLOCK_WRLOCK set, it means we
                    222:         * downgraded a write lock and had possible read waiter, wake them
                    223:         * to let them retry the lock.
                    224:         */
                    225:        if (__predict_false((o & (RWLOCK_WRLOCK|RWLOCK_WAIT)) ==
                    226:            (RWLOCK_WRLOCK|RWLOCK_WAIT)))
                    227:                wakeup(rwl);
                    228:
                    229:        return (0);
                    230: }
                    231:
                    232: void
                    233: rw_exit(struct rwlock *rwl)
                    234: {
                    235:        unsigned long owner = rwl->rwl_owner;
                    236:        int wrlock = owner & RWLOCK_WRLOCK;
                    237:        unsigned long set;
                    238:
                    239:        do {
                    240:                owner = rwl->rwl_owner;
                    241:                if (wrlock)
                    242:                        set = 0;
                    243:                else
                    244:                        set = (owner - RWLOCK_READ_INCR) &
                    245:                                ~(RWLOCK_WAIT|RWLOCK_WRWANT);
                    246:        } while (rw_cas(&rwl->rwl_owner, owner, set));
                    247:
                    248:        if (owner & RWLOCK_WAIT)
                    249:                wakeup(rwl);
                    250: }

CVSweb