diff options
Diffstat (limited to 'usr/src')
-rw-r--r-- | usr/src/head/synch.h | 16 | ||||
-rw-r--r-- | usr/src/lib/libc/amd64/threads/amd64.il | 18 | ||||
-rw-r--r-- | usr/src/lib/libc/i386/threads/i386.il | 22 | ||||
-rw-r--r-- | usr/src/lib/libc/inc/thr_inlines.h | 62 | ||||
-rw-r--r-- | usr/src/lib/libc/inc/thr_uberdata.h | 37 | ||||
-rw-r--r-- | usr/src/lib/libc/port/gen/atexit.c | 17 | ||||
-rw-r--r-- | usr/src/lib/libc/port/sys/lwp_rwlock.c | 35 | ||||
-rw-r--r-- | usr/src/lib/libc/port/threads/assfail.c | 49 | ||||
-rw-r--r-- | usr/src/lib/libc/port/threads/rwlock.c | 785 | ||||
-rw-r--r-- | usr/src/lib/libc/port/threads/sigaction.c | 27 | ||||
-rw-r--r-- | usr/src/lib/libc/port/threads/synch.c | 182 | ||||
-rw-r--r-- | usr/src/lib/libc/sparc/Makefile | 2 | ||||
-rw-r--r-- | usr/src/lib/libc/sparc/threads/sparc.il | 28 | ||||
-rw-r--r-- | usr/src/lib/libc/sparcv9/threads/sparcv9.il | 28 | ||||
-rw-r--r-- | usr/src/lib/libc_db/common/thread_db.c | 92 | ||||
-rw-r--r-- | usr/src/uts/common/sys/synch.h | 16 | ||||
-rw-r--r-- | usr/src/uts/common/syscall/lwp_sobj.c | 80 | ||||
-rw-r--r-- | usr/src/uts/intel/sys/synch32.h | 17 | ||||
-rw-r--r-- | usr/src/uts/sparc/sys/synch32.h | 17 |
19 files changed, 847 insertions, 683 deletions
diff --git a/usr/src/head/synch.h b/usr/src/head/synch.h index 8d825d55a8..629570a646 100644 --- a/usr/src/head/synch.h +++ b/usr/src/head/synch.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -19,8 +18,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -81,12 +81,12 @@ typedef lwp_cond_t cond_t; * Because we have to deal with C++, we cannot redefine this one as that one. */ typedef struct _rwlock { - int32_t readers; /* -1 == writer else # of readers */ + int32_t readers; /* rwstate word */ uint16_t type; uint16_t magic; - mutex_t mutex; /* used to indicate ownership */ - cond_t readercv; /* unused */ - cond_t writercv; /* unused */ + mutex_t mutex; /* used with process-shared rwlocks */ + cond_t readercv; /* used only to indicate ownership */ + cond_t writercv; /* used only to indicate ownership */ } rwlock_t; #ifdef __STDC__ diff --git a/usr/src/lib/libc/amd64/threads/amd64.il b/usr/src/lib/libc/amd64/threads/amd64.il index 92b55caaad..c0b81e0c4b 100644 --- a/usr/src/lib/libc/amd64/threads/amd64.il +++ b/usr/src/lib/libc/amd64/threads/amd64.il @@ -46,27 +46,37 @@ xchgb %al, (%rdi) .end - .inline cas32, 0 + .inline atomic_cas_32, 0 movl %esi, %eax lock cmpxchgl %edx, (%rdi) .end - .inline swap32, 0 + .inline atomic_swap_32, 0 movl %esi, %eax xchgl (%rdi), %eax .end - .inline incr32, 0 + .inline atomic_inc_32, 0 lock incl (%rdi) .end - .inline decr32, 0 + .inline atomic_dec_32, 0 lock decl (%rdi) .end + .inline atomic_and_32, 0 + lock + andl %esi, (%rdi) + .end + + .inline atomic_or_32, 0 + lock + orl %esi, (%rdi) + .end + .inline ht_pause, 0 rep / "rep nop" is equivalent to "pause" nop diff --git a/usr/src/lib/libc/i386/threads/i386.il b/usr/src/lib/libc/i386/threads/i386.il index e37be525e2..9ce94d452a 100644 --- a/usr/src/lib/libc/i386/threads/i386.il +++ b/usr/src/lib/libc/i386/threads/i386.il @@ -48,7 +48,7 @@ xchgb %al, (%ecx) .end - .inline cas32, 0 + .inline atomic_cas_32, 0 movl 0(%esp), %edx movl 4(%esp), %eax movl 8(%esp), %ecx @@ -56,24 +56,38 @@ cmpxchgl %ecx, (%edx) .end - .inline swap32, 0 + .inline atomic_swap_32, 0 movl 0(%esp), %ecx movl 4(%esp), %eax xchgl (%ecx), %eax .end - .inline incr32, 0 + .inline atomic_inc_32, 0 movl 0(%esp), %eax lock incl (%eax) .end - .inline decr32, 0 + .inline atomic_dec_32, 0 movl 0(%esp), %eax lock decl (%eax) .end + .inline atomic_and_32, 0 + movl 0(%esp), %ecx + movl 4(%esp), %eax + lock + andl %eax, (%ecx) + .end + + .inline atomic_or_32, 0 + movl 0(%esp), %ecx + movl 4(%esp), %eax + lock + orl %eax, (%ecx) + .end + .inline ht_pause, 0 rep / "rep nop" is equivalent to "pause" nop diff --git a/usr/src/lib/libc/inc/thr_inlines.h b/usr/src/lib/libc/inc/thr_inlines.h index 4e2f469488..55bd645428 100644 --- a/usr/src/lib/libc/inc/thr_inlines.h +++ b/usr/src/lib/libc/inc/thr_inlines.h @@ -147,7 +147,7 @@ set_lock_byte(volatile uint8_t *__lockp) } extern __inline__ uint32_t -swap32(volatile uint32_t *__memory, uint32_t __value) +atomic_swap_32(volatile uint32_t *__memory, uint32_t __value) { #if defined(__x86) __asm__ __volatile__( @@ -174,7 +174,7 @@ swap32(volatile uint32_t *__memory, uint32_t __value) } extern __inline__ uint32_t -cas32(volatile uint32_t *__memory, uint32_t __cmp, uint32_t __newvalue) +atomic_cas_32(volatile uint32_t *__memory, uint32_t __cmp, uint32_t __newvalue) { uint32_t __oldvalue; #if defined(__x86) @@ -185,7 +185,7 @@ cas32(volatile uint32_t *__memory, uint32_t __cmp, uint32_t __newvalue) #elif defined(__sparc) __asm__ __volatile__( "cas [%2], %3, %1" - : "=m" (*__memory), "+r" (__oldvalue) + : "=m" (*__memory), "=&r" (__oldvalue) : "r" (__memory), "r" (__cmp), "1" (__newvalue)); #else #error "port me" @@ -194,7 +194,7 @@ cas32(volatile uint32_t *__memory, uint32_t __cmp, uint32_t __newvalue) } extern __inline__ void -incr32(volatile uint32_t *__memory) +atomic_inc_32(volatile uint32_t *__memory) { #if defined(__x86) __asm__ __volatile__( @@ -219,7 +219,7 @@ incr32(volatile uint32_t *__memory) } extern __inline__ void -decr32(volatile uint32_t *__memory) +atomic_dec_32(volatile uint32_t *__memory) { #if defined(__x86) __asm__ __volatile__( @@ -243,6 +243,58 @@ decr32(volatile uint32_t *__memory) #endif } +extern __inline__ void +atomic_and_32(volatile uint32_t *__memory, uint32_t __bits) +{ +#if defined(__x86) + __asm__ __volatile__( + "lock; andl %1, %0" + : "+m" (*__memory) + : "r" (__bits)); +#elif defined(__sparc) + uint32_t __tmp1, __tmp2; + __asm__ __volatile__( + "ld [%3], %0\n\t" + "1:\n\t" + "and %0, %4, %1\n\t" + "cas [%3], %0, %1\n\t" + "cmp %0, %1\n\t" + "bne,a,pn %%icc, 1b\n\t" + " mov %1, %0" + : "=&r" (__tmp1), "=&r" (__tmp2), "=m" (*__memory) + : "r" (__memory), "r" (__bits) + : "cc"); +#else +#error "port me" +#endif +} + +extern __inline__ void +atomic_or_32(volatile uint32_t *__memory, uint32_t __bits) +{ +#if defined(__x86) + __asm__ __volatile__( + "lock; orl %1, %0" + : "+m" (*__memory) + : "r" (__bits)); +#elif defined(__sparc) + uint32_t __tmp1, __tmp2; + __asm__ __volatile__( + "ld [%3], %0\n\t" + "1:\n\t" + "or %0, %4, %1\n\t" + "cas [%3], %0, %1\n\t" + "cmp %0, %1\n\t" + "bne,a,pn %%icc, 1b\n\t" + " mov %1, %0" + : "=&r" (__tmp1), "=&r" (__tmp2), "=m" (*__memory) + : "r" (__memory), "r" (__bits) + : "cc"); +#else +#error "port me" +#endif +} + #if defined(__sparc) /* only needed on sparc */ extern __inline__ ulong_t diff --git a/usr/src/lib/libc/inc/thr_uberdata.h b/usr/src/lib/libc/inc/thr_uberdata.h index 4b00040fcf..7dbe4d7aab 100644 --- a/usr/src/lib/libc/inc/thr_uberdata.h +++ b/usr/src/lib/libc/inc/thr_uberdata.h @@ -378,6 +378,8 @@ extern void queue_unlock(queue_head_t *); extern void enqueue(queue_head_t *, struct ulwp *, void *, int); extern struct ulwp *dequeue(queue_head_t *, void *, int *); extern struct ulwp *queue_waiter(queue_head_t *, void *); +extern struct ulwp *queue_unlink(queue_head_t *, + struct ulwp **, struct ulwp *); extern uint8_t dequeue_self(queue_head_t *, void *); extern void unsleep_self(void); extern void spin_lock_set(mutex_t *); @@ -662,21 +664,21 @@ typedef struct { /* - * siguaction members have 64-byte size and alignment. - * We know that sizeof (struct sigaction) is 32 bytes for - * both _ILP32 and _LP64, so we put the padding in the middle. + * siguaction members have 128-byte size and 64-byte alignment. + * We know that sizeof (struct sigaction) is 32 bytes for both + * _ILP32 and _LP64 and that sizeof (rwlock_t) is 64 bytes. */ typedef struct { - mutex_t sig_lock; - char sig_pad[64 - (sizeof (mutex_t) + sizeof (struct sigaction))]; + rwlock_t sig_lock; struct sigaction sig_uaction; + char sig_pad[128 - sizeof (rwlock_t) - sizeof (struct sigaction)]; } siguaction_t; #ifdef _SYSCALL32 typedef struct { - mutex_t sig_lock; - char sig_pad[64 - (sizeof (mutex_t) + sizeof (struct sigaction32))]; + rwlock_t sig_lock; struct sigaction32 sig_uaction; + char sig_pad[128 - sizeof (rwlock_t) - sizeof (struct sigaction32)]; } siguaction32_t; #endif /* _SYSCALL32 */ @@ -1080,6 +1082,14 @@ extern void _flush_windows(void); #endif extern void set_curthread(void *); +/* + * Utility function used by cond_broadcast() and rw_unlock() + * when waking up many threads (more than MAXLWPS) all at once. + */ +#define MAXLWPS 128 /* max remembered lwpids before overflow */ +#define NEWLWPS 2048 /* max remembered lwpids at first overflow */ +extern lwpid_t *alloc_lwpids(lwpid_t *, int *, int *); + /* enter a critical section */ #define enter_critical(self) (self->ul_critical++) @@ -1152,6 +1162,9 @@ extern void _lwp_start(void); extern void _lwp_terminate(void); extern void lmutex_lock(mutex_t *); extern void lmutex_unlock(mutex_t *); +extern void lrw_rdlock(rwlock_t *); +extern void lrw_wrlock(rwlock_t *); +extern void lrw_unlock(rwlock_t *); extern void sig_mutex_lock(mutex_t *); extern void sig_mutex_unlock(mutex_t *); extern int sig_mutex_trylock(mutex_t *); @@ -1361,10 +1374,12 @@ extern int _private_lwp_mutex_unlock(mutex_t *); * inlines */ extern int set_lock_byte(volatile uint8_t *); -extern uint32_t swap32(volatile uint32_t *, uint32_t); -extern uint32_t cas32(volatile uint32_t *, uint32_t, uint32_t); -extern void incr32(volatile uint32_t *); -extern void decr32(volatile uint32_t *); +extern uint32_t atomic_swap_32(volatile uint32_t *, uint32_t); +extern uint32_t atomic_cas_32(volatile uint32_t *, uint32_t, uint32_t); +extern void atomic_inc_32(volatile uint32_t *); +extern void atomic_dec_32(volatile uint32_t *); +extern void atomic_and_32(volatile uint32_t *, uint32_t); +extern void atomic_or_32(volatile uint32_t *, uint32_t); #if defined(__sparc) extern ulong_t caller(void); extern ulong_t getfp(void); diff --git a/usr/src/lib/libc/port/gen/atexit.c b/usr/src/lib/libc/port/gen/atexit.c index 2104eefea3..b4dc369c5f 100644 --- a/usr/src/lib/libc/port/gen/atexit.c +++ b/usr/src/lib/libc/port/gen/atexit.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -21,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -159,7 +158,7 @@ _preexec_sig_unload(Lc_addr_range_t range[], uint_t count) { uberdata_t *udp = curthread->ul_uberdata; int sig; - mutex_t *mp; + rwlock_t *rwlp; struct sigaction *sap; struct sigaction oact; void (*handler)(); @@ -170,10 +169,10 @@ again: handler = sap->sa_handler; if (handler != SIG_DFL && handler != SIG_IGN && in_range(handler, range, count)) { - mp = &udp->siguaction[sig].sig_lock; - lmutex_lock(mp); + rwlp = &udp->siguaction[sig].sig_lock; + lrw_wrlock(rwlp); if (handler != sap->sa_handler) { - lmutex_unlock(mp); + lrw_unlock(rwlp); goto again; } sap->sa_handler = SIG_DFL; @@ -183,7 +182,7 @@ again: oact.sa_handler != SIG_DFL && oact.sa_handler != SIG_IGN) (void) __sigaction(sig, sap, NULL); - lmutex_unlock(mp); + lrw_unlock(rwlp); } } } diff --git a/usr/src/lib/libc/port/sys/lwp_rwlock.c b/usr/src/lib/libc/port/sys/lwp_rwlock.c index d164cc948b..c91e60c7fa 100644 --- a/usr/src/lib/libc/port/sys/lwp_rwlock.c +++ b/usr/src/lib/libc/port/sys/lwp_rwlock.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -19,8 +18,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -41,27 +41,19 @@ int __lwp_rwlock_rdlock(rwlock_t *rwl, timespec_t *tsp) { - int rval; - - do { - rval = syscall(SYS_lwp_rwlock_sys, - SUBSYS_lwp_rwlock_rdlock, rwl, tsp); - } while (rval == -1 && errno == EINTR); - - return (rval == -1 ? errno : 0); + if (syscall(SYS_lwp_rwlock_sys, + SUBSYS_lwp_rwlock_rdlock, rwl, tsp) == -1) + return (errno); + return (0); } int __lwp_rwlock_wrlock(rwlock_t *rwl, timespec_t *tsp) { - int rval; - - do { - rval = syscall(SYS_lwp_rwlock_sys, - SUBSYS_lwp_rwlock_wrlock, rwl, tsp); - } while (rval == -1 && errno == EINTR); - - return (rval == -1 ? errno : 0); + if (syscall(SYS_lwp_rwlock_sys, + SUBSYS_lwp_rwlock_wrlock, rwl, tsp) == -1) + return (errno); + return (0); } int @@ -85,7 +77,8 @@ __lwp_rwlock_trywrlock(rwlock_t *rwl) int __lwp_rwlock_unlock(rwlock_t *rwl) { - if (syscall(SYS_lwp_rwlock_sys, SUBSYS_lwp_rwlock_unlock, rwl) == -1) + if (syscall(SYS_lwp_rwlock_sys, + SUBSYS_lwp_rwlock_unlock, rwl) == -1) return (errno); return (0); } diff --git a/usr/src/lib/libc/port/threads/assfail.c b/usr/src/lib/libc/port/threads/assfail.c index 989a36923a..0ffd9a3219 100644 --- a/usr/src/lib/libc/port/threads/assfail.c +++ b/usr/src/lib/libc/port/threads/assfail.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -248,11 +248,13 @@ rwlock_error(const rwlock_t *rp, const char *who, const char *msg) { /* take a snapshot of the rwlock before it changes (we hope) */ rwlock_t rcopy = *rp; + uint32_t rwstate; char buf[800]; uberdata_t *udp; ulwp_t *self; lwpid_t lwpid; pid_t pid; + int process; /* avoid recursion deadlock */ if ((self = __curthread()) != NULL) { @@ -272,6 +274,9 @@ rwlock_error(const rwlock_t *rp, const char *who, const char *msg) pid = _private_getpid(); } + rwstate = (uint32_t)rcopy.rwlock_readers; + process = (rcopy.rwlock_type & USYNC_PROCESS); + (void) strcpy(buf, "\n*** _THREAD_ERROR_DETECTION: lock usage error detected ***\n"); (void) strcat(buf, who); @@ -283,43 +288,29 @@ rwlock_error(const rwlock_t *rp, const char *who, const char *msg) ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf)); (void) strcat(buf, " thread-id "); ultos((uint64_t)lwpid, 10, buf + strlen(buf)); - if (rcopy.rwlock_type & USYNC_PROCESS) { - uint32_t *rwstate = (uint32_t *)&rcopy.rwlock_readers; - + if (process) { (void) strcat(buf, " in process "); ultos((uint64_t)pid, 10, buf + strlen(buf)); - - if (*rwstate & URW_WRITE_LOCKED) { - (void) strcat(buf, "\nthe lock writer owner is "); - ultos((uint64_t)rcopy.rwlock_owner, 16, - buf + strlen(buf)); + } + if (rwstate & URW_WRITE_LOCKED) { + (void) strcat(buf, "\nthe writer lock owner is "); + ultos((uint64_t)rcopy.rwlock_owner, 16, + buf + strlen(buf)); + if (process) { (void) strcat(buf, " in process "); ultos((uint64_t)rcopy.rwlock_ownerpid, 10, buf + strlen(buf)); - } else if (*rwstate & URW_READERS_MASK) { - (void) strcat(buf, "\nthe lock is owned by "); - ultos((uint64_t)(*rwstate & URW_READERS_MASK), 10, - buf + strlen(buf)); - (void) strcat(buf, " readers"); - } else - (void) strcat(buf, "\nthe lock is unowned"); - - if (*rwstate & URW_HAS_WAITERS) { - (void) strcat(buf, "\nand appears to have waiters"); - if (*rwstate & URW_WRITE_WANTED) - (void) strcat(buf, - " (including at least one writer)"); } - } else if (rcopy.rwlock_readers < 0) { - (void) strcat(buf, "\nthe lock writer owner is "); - ultos((uint64_t)rcopy.rwlock_mowner, 16, buf + strlen(buf)); - } else if (rcopy.rwlock_readers > 0) { - (void) strcat(buf, "\nthe lock is owned by "); - ultos((uint64_t)rcopy.rwlock_readers, 10, buf + strlen(buf)); - (void) strcat(buf, "readers"); + } else if (rwstate & URW_READERS_MASK) { + (void) strcat(buf, "\nthe reader lock is held by "); + ultos((uint64_t)(rwstate & URW_READERS_MASK), 10, + buf + strlen(buf)); + (void) strcat(buf, " readers"); } else { (void) strcat(buf, "\nthe lock is unowned"); } + if (rwstate & URW_HAS_WAITERS) + (void) strcat(buf, "\nand the lock appears to have waiters"); (void) strcat(buf, "\n\n"); (void) _write(2, buf, strlen(buf)); if (udp->uberflags.uf_thread_error_detection >= 2) diff --git a/usr/src/lib/libc/port/threads/rwlock.c b/usr/src/lib/libc/port/threads/rwlock.c index 3e04c82601..408f74489e 100644 --- a/usr/src/lib/libc/port/threads/rwlock.c +++ b/usr/src/lib/libc/port/threads/rwlock.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -19,8 +18,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -28,7 +28,6 @@ #include "lint.h" #include "thr_uberdata.h" - #include <sys/sdt.h> #define TRY_FLAG 0x10 @@ -39,8 +38,15 @@ #define NLOCKS 4 /* initial number of readlock_t structs allocated */ +#define ASSERT_CONSISTENT_STATE(readers) \ + ASSERT(!((readers) & URW_WRITE_LOCKED) || \ + ((readers) & ~URW_HAS_WAITERS) == URW_WRITE_LOCKED) + /* * Find/allocate an entry for rwlp in our array of rwlocks held for reading. + * We must be deferring signals for this to be safe. + * Else if we are returning an entry with ul_rdlocks == 0, + * it could be reassigned behind our back in a signal handler. */ static readlock_t * rwl_entry(rwlock_t *rwlp) @@ -50,6 +56,9 @@ rwl_entry(rwlock_t *rwlp) readlock_t *readlockp; uint_t nlocks; + /* we must be deferring signals */ + ASSERT((self->ul_critical + self->ul_sigdefer) != 0); + if ((nlocks = self->ul_rdlocks) != 0) readlockp = self->ul_readlock.array; else { @@ -131,35 +140,40 @@ rwl_free(ulwp_t *ulwp) int _rw_read_held(rwlock_t *rwlp) { - ulwp_t *self; + volatile uint32_t *rwstate = (volatile uint32_t *)&rwlp->rwlock_readers; + uint32_t readers; + ulwp_t *self = curthread; readlock_t *readlockp; uint_t nlocks; + int rval = 0; - /* quick answer */ - if (rwlp->rwlock_type == USYNC_PROCESS) { - if (!((uint32_t)rwlp->rwlock_readers & URW_READERS_MASK)) - return (0); - } else if (rwlp->rwlock_readers <= 0) { - return (0); - } + no_preempt(self); - /* - * The lock is held for reading by some thread. - * Search our array of rwlocks held for reading for a match. - */ - self = curthread; - if ((nlocks = self->ul_rdlocks) != 0) - readlockp = self->ul_readlock.array; - else { - nlocks = 1; - readlockp = &self->ul_readlock.single; + readers = *rwstate; + ASSERT_CONSISTENT_STATE(readers); + if (!(readers & URW_WRITE_LOCKED) && + (readers & URW_READERS_MASK) != 0) { + /* + * The lock is held for reading by some thread. + * Search our array of rwlocks held for reading for a match. + */ + if ((nlocks = self->ul_rdlocks) != 0) + readlockp = self->ul_readlock.array; + else { + nlocks = 1; + readlockp = &self->ul_readlock.single; + } + for (; nlocks; nlocks--, readlockp++) { + if (readlockp->rd_rwlock == rwlp) { + if (readlockp->rd_count) + rval = 1; + break; + } + } } - for (; nlocks; nlocks--, readlockp++) - if (readlockp->rd_rwlock == rwlp) - return (readlockp->rd_count? 1 : 0); - - return (0); + preempt(self); + return (rval); } /* @@ -171,16 +185,22 @@ _rw_read_held(rwlock_t *rwlp) int _rw_write_held(rwlock_t *rwlp) { + volatile uint32_t *rwstate = (volatile uint32_t *)&rwlp->rwlock_readers; + uint32_t readers; ulwp_t *self = curthread; - uberdata_t *udp = self->ul_uberdata; + int rval; + + no_preempt(self); - if (rwlp->rwlock_type == USYNC_PROCESS) - return (((uint32_t)rwlp->rwlock_readers & URW_WRITE_LOCKED) && - (rwlp->rwlock_ownerpid == udp->pid) && - (rwlp->rwlock_owner == (uintptr_t)self)); + readers = *rwstate; + ASSERT_CONSISTENT_STATE(readers); + rval = ((readers & URW_WRITE_LOCKED) && + rwlp->rwlock_owner == (uintptr_t)self && + (rwlp->rwlock_type == USYNC_THREAD || + rwlp->rwlock_ownerpid == self->ul_uberdata->pid)); - /* USYNC_THREAD */ - return (rwlp->rwlock_readers == -1 && mutex_is_held(&rwlp->mutex)); + preempt(self); + return (rval); } #pragma weak rwlock_init = __rwlock_init @@ -195,19 +215,15 @@ __rwlock_init(rwlock_t *rwlp, int type, void *arg) * Once reinitialized, we can no longer be holding a read or write lock. * We can do nothing about other threads that are holding read locks. */ - if (rw_read_is_held(rwlp)) - rwl_entry(rwlp)->rd_count = 0; + sigoff(curthread); + rwl_entry(rwlp)->rd_count = 0; + sigon(curthread); (void) _memset(rwlp, 0, sizeof (*rwlp)); rwlp->rwlock_type = (uint16_t)type; rwlp->rwlock_magic = RWL_MAGIC; - rwlp->rwlock_readers = 0; rwlp->mutex.mutex_type = (uint8_t)type; rwlp->mutex.mutex_flag = LOCK_INITED; rwlp->mutex.mutex_magic = MUTEX_MAGIC; - rwlp->readercv.cond_type = (uint16_t)type; - rwlp->readercv.cond_magic = COND_MAGIC; - rwlp->writercv.cond_type = (uint16_t)type; - rwlp->writercv.cond_magic = COND_MAGIC; return (0); } @@ -222,59 +238,191 @@ __rwlock_destroy(rwlock_t *rwlp) * Once destroyed, we can no longer be holding a read or write lock. * We can do nothing about other threads that are holding read locks. */ - if (rw_read_is_held(rwlp)) - rwl_entry(rwlp)->rd_count = 0; + sigoff(curthread); + rwl_entry(rwlp)->rd_count = 0; + sigon(curthread); rwlp->rwlock_magic = 0; tdb_sync_obj_deregister(rwlp); return (0); } /* - * Wake up the next thread sleeping on the rwlock queue and then + * Attempt to acquire a readers lock. Return true on success. + */ +static int +read_lock_try(rwlock_t *rwlp, int ignore_waiters_flag) +{ + volatile uint32_t *rwstate = (volatile uint32_t *)&rwlp->rwlock_readers; + uint32_t mask = ignore_waiters_flag? + URW_WRITE_LOCKED : (URW_HAS_WAITERS | URW_WRITE_LOCKED); + uint32_t readers; + ulwp_t *self = curthread; + + no_preempt(self); + while (((readers = *rwstate) & mask) == 0) { + if (atomic_cas_32(rwstate, readers, readers + 1) == readers) { + preempt(self); + return (1); + } + } + preempt(self); + return (0); +} + +/* + * Attempt to release a reader lock. Return true on success. + */ +static int +read_unlock_try(rwlock_t *rwlp) +{ + volatile uint32_t *rwstate = (volatile uint32_t *)&rwlp->rwlock_readers; + uint32_t readers; + ulwp_t *self = curthread; + + no_preempt(self); + while (((readers = *rwstate) & URW_HAS_WAITERS) == 0) { + if (atomic_cas_32(rwstate, readers, readers - 1) == readers) { + preempt(self); + return (1); + } + } + preempt(self); + return (0); +} + +/* + * Attempt to acquire a writer lock. Return true on success. + */ +static int +write_lock_try(rwlock_t *rwlp, int ignore_waiters_flag) +{ + volatile uint32_t *rwstate = (volatile uint32_t *)&rwlp->rwlock_readers; + uint32_t mask = ignore_waiters_flag? + (URW_WRITE_LOCKED | URW_READERS_MASK) : + (URW_HAS_WAITERS | URW_WRITE_LOCKED | URW_READERS_MASK); + ulwp_t *self = curthread; + uint32_t readers; + + no_preempt(self); + while (((readers = *rwstate) & mask) == 0) { + if (atomic_cas_32(rwstate, readers, readers | URW_WRITE_LOCKED) + == readers) { + preempt(self); + return (1); + } + } + preempt(self); + return (0); +} + +/* + * Attempt to release a writer lock. Return true on success. + */ +static int +write_unlock_try(rwlock_t *rwlp) +{ + volatile uint32_t *rwstate = (volatile uint32_t *)&rwlp->rwlock_readers; + uint32_t readers; + ulwp_t *self = curthread; + + no_preempt(self); + while (((readers = *rwstate) & URW_HAS_WAITERS) == 0) { + if (atomic_cas_32(rwstate, readers, 0) == readers) { + preempt(self); + return (1); + } + } + preempt(self); + return (0); +} + +/* + * Wake up thread(s) sleeping on the rwlock queue and then * drop the queue lock. Return non-zero if we wake up someone. - * - * This is called whenever a thread releases the lock and whenever a - * thread successfully or unsuccessfully attempts to acquire the lock. - * (Basically, whenever the state of the queue might have changed.) - * - * We wake up at most one thread. If there are more threads to be - * awakened, the next one will be waked up by the thread we wake up. - * This ensures that queued threads will acquire the lock in priority - * order and that queued writers will take precedence over queued - * readers of the same priority. + * This is called when a thread releases a lock that appears to have waiters. */ static int rw_queue_release(queue_head_t *qp, rwlock_t *rwlp) { + volatile uint32_t *rwstate = (volatile uint32_t *)&rwlp->rwlock_readers; + uint32_t readers; + uint32_t writers; + int nlwpid = 0; + int maxlwps = MAXLWPS; + ulwp_t *self; + ulwp_t **ulwpp; ulwp_t *ulwp; - int more; + ulwp_t *prev = NULL; + lwpid_t buffer[MAXLWPS]; + lwpid_t *lwpid = buffer; - if (rwlp->rwlock_readers >= 0 && rwlp->rwlock_mwaiters) { - /* - * The lock is free or at least is available to readers - * and there are (or might be) waiters on the queue. - */ - if (rwlp->rwlock_readers != 0 && - (ulwp = queue_waiter(qp, rwlp)) == NULL) - rwlp->rwlock_mwaiters = 0; - else if (rwlp->rwlock_readers == 0 || !ulwp->ul_writer) { - if ((ulwp = dequeue(qp, rwlp, &more)) == NULL) - rwlp->rwlock_mwaiters = 0; - else { - ulwp_t *self = curthread; - lwpid_t lwpid = ulwp->ul_lwpid; - - rwlp->rwlock_mwaiters = (more? 1 : 0); - no_preempt(self); - queue_unlock(qp); - (void) __lwp_unpark(lwpid); - preempt(self); - return (1); - } + readers = *rwstate; + ASSERT_CONSISTENT_STATE(readers); + if (!(readers & URW_HAS_WAITERS)) { + queue_unlock(qp); + return (0); + } + readers &= URW_READERS_MASK; + writers = 0; + + /* + * Walk the list of waiters and prepare to wake up as + * many readers as we encounter before encountering + * a writer. If the first thread on the list is a + * writer, stop there and wake it up. + * + * We keep track of lwpids that are to be unparked in lwpid[]. + * __lwp_unpark_all() is called to unpark all of them after + * they have been removed from the sleep queue and the sleep + * queue lock has been dropped. If we run out of space in our + * on-stack buffer, we need to allocate more but we can't call + * lmalloc() because we are holding a queue lock when the overflow + * occurs and lmalloc() acquires a lock. We can't use alloca() + * either because the application may have allocated a small + * stack and we don't want to overrun the stack. So we call + * alloc_lwpids() to allocate a bigger buffer using the mmap() + * system call directly since that path acquires no locks. + */ + ulwpp = &qp->qh_head; + while ((ulwp = *ulwpp) != NULL) { + if (ulwp->ul_wchan != rwlp) { + prev = ulwp; + ulwpp = &ulwp->ul_link; + continue; + } + if (ulwp->ul_writer) { + if (writers != 0 || readers != 0) + break; + /* one writer to wake */ + writers++; + } else { + if (writers != 0) + break; + /* at least one reader to wake */ + readers++; + if (nlwpid == maxlwps) + lwpid = alloc_lwpids(lwpid, &nlwpid, &maxlwps); } + (void) queue_unlink(qp, ulwpp, prev); + lwpid[nlwpid++] = ulwp->ul_lwpid; } - queue_unlock(qp); - return (0); + if (ulwp == NULL) + atomic_and_32(rwstate, ~URW_HAS_WAITERS); + if (nlwpid == 0) { + queue_unlock(qp); + } else { + self = curthread; + no_preempt(self); + queue_unlock(qp); + if (nlwpid == 1) + (void) __lwp_unpark(lwpid[0]); + else + (void) __lwp_unpark_all(lwpid, nlwpid); + preempt(self); + } + if (lwpid != buffer) + (void) _private_munmap(lwpid, maxlwps * sizeof (lwpid_t)); + return (nlwpid != 0); } /* @@ -290,11 +438,12 @@ rw_queue_release(queue_head_t *qp, rwlock_t *rwlp) int shared_rwlock_lock(rwlock_t *rwlp, timespec_t *tsp, int rd_wr) { - uint32_t *rwstate = (uint32_t *)&rwlp->readers; - ulwp_t *self = curthread; - uberdata_t *udp = self->ul_uberdata; + volatile uint32_t *rwstate = (volatile uint32_t *)&rwlp->rwlock_readers; + mutex_t *mp = &rwlp->mutex; + /* LINTED set but not used */ + uint32_t readers; int try_flag; - int error = 0; + int error; try_flag = (rd_wr & TRY_FLAG); rd_wr &= ~TRY_FLAG; @@ -305,140 +454,56 @@ shared_rwlock_lock(rwlock_t *rwlp, timespec_t *tsp, int rd_wr) } do { - if ((error = _private_mutex_lock(&rwlp->mutex)) != 0) + if (try_flag && (*rwstate & URW_WRITE_LOCKED)) { + error = EBUSY; + break; + } + if ((error = _private_mutex_lock(mp)) != 0) break; - if (rd_wr == READ_LOCK) { - /* - * We are a reader. - */ - - if ((*rwstate & ~URW_READERS_MASK) == 0) { - (*rwstate)++; - (void) _private_mutex_unlock(&rwlp->mutex); - } else if (try_flag) { - if (*rwstate & URW_WRITE_LOCKED) { - error = EBUSY; - (void) _private_mutex_unlock( - &rwlp->mutex); - } else { - /* - * We have a higher priority than any - * queued waiters, or the waiters bit - * may be inaccurate. Only the kernel - * knows for sure. - */ - rwlp->rwlock_mowner = 0; - rwlp->rwlock_mownerpid = 0; - error = __lwp_rwlock_tryrdlock(rwlp); - } - } else { - rwlp->rwlock_mowner = 0; - rwlp->rwlock_mownerpid = 0; - error = __lwp_rwlock_rdlock(rwlp, tsp); + if (read_lock_try(rwlp, 0)) { + (void) _private_mutex_unlock(mp); + break; } } else { - /* - * We are a writer. - */ - - if (*rwstate == 0) { - *rwstate = URW_WRITE_LOCKED; - (void) _private_mutex_unlock(&rwlp->mutex); - } else if (try_flag) { - if (*rwstate & URW_WRITE_LOCKED) { - error = EBUSY; - (void) _private_mutex_unlock( - &rwlp->mutex); - } else { - /* - * The waiters bit may be inaccurate. - * Only the kernel knows for sure. - */ - rwlp->rwlock_mowner = 0; - rwlp->rwlock_mownerpid = 0; - error = __lwp_rwlock_trywrlock(rwlp); - } - } else { - rwlp->rwlock_mowner = 0; - rwlp->rwlock_mownerpid = 0; - error = __lwp_rwlock_wrlock(rwlp, tsp); + if (write_lock_try(rwlp, 0)) { + (void) _private_mutex_unlock(mp); + break; } } - } while (error == EAGAIN); - - if (error == 0) { - if (rd_wr == WRITE_LOCK) { - rwlp->rwlock_owner = (uintptr_t)self; - rwlp->rwlock_ownerpid = udp->pid; - } - if (!try_flag) { - DTRACE_PROBE3(plockstat, rw__blocked, rwlp, rd_wr, 1); - } - DTRACE_PROBE2(plockstat, rw__acquire, rwlp, rd_wr); - } else if (!try_flag) { - DTRACE_PROBE3(plockstat, rw__blocked, rwlp, rd_wr, 0); - DTRACE_PROBE3(plockstat, rw__error, rwlp, rd_wr, error); - } - return (error); -} - -/* - * Code for unlock of process-shared (USYNC_PROCESS) rwlocks. - * - * Note: if the lock appears to have waiters we call __lwp_rwlock_unlock() - * holding the mutex. This returns with the mutex still held (for us to - * release). - */ -int -shared_rwlock_unlock(rwlock_t *rwlp, int *waked) -{ - uint32_t *rwstate = (uint32_t *)&rwlp->readers; - int error = 0; - - if ((error = _private_mutex_lock(&rwlp->mutex)) != 0) - return (error); - - /* Reset flag used to suggest caller yields. */ - *waked = 0; - - /* Our right to unlock was checked in __rw_unlock(). */ - if (*rwstate & URW_WRITE_LOCKED) { - rwlp->rwlock_owner = 0; - rwlp->rwlock_ownerpid = 0; - } - - if ((*rwstate & ~URW_READERS_MASK) == 0) { - /* Simple multiple readers, no waiters case. */ - if (*rwstate > 0) - (*rwstate)--; - } else if (!(*rwstate & URW_HAS_WAITERS)) { - /* Simple no waiters case (i.e. was write locked). */ - *rwstate = 0; - } else { + atomic_or_32(rwstate, URW_HAS_WAITERS); + readers = *rwstate; + ASSERT_CONSISTENT_STATE(readers); /* - * We appear to have waiters so we must call into the kernel. - * If there are waiters a full handoff will occur (rwstate - * will be updated, and one or more threads will be awoken). + * The calls to __lwp_rwlock_*() below will release the mutex, + * so we need a dtrace probe here. */ - error = __lwp_rwlock_unlock(rwlp); - - /* Suggest caller yields. */ - *waked = 1; - } - - (void) _private_mutex_unlock(&rwlp->mutex); + mp->mutex_owner = 0; + DTRACE_PROBE2(plockstat, mutex__release, mp, 0); + /* + * The waiters bit may be inaccurate. + * Only the kernel knows for sure. + */ + if (rd_wr == READ_LOCK) { + if (try_flag) + error = __lwp_rwlock_tryrdlock(rwlp); + else + error = __lwp_rwlock_rdlock(rwlp, tsp); + } else { + if (try_flag) + error = __lwp_rwlock_trywrlock(rwlp); + else + error = __lwp_rwlock_wrlock(rwlp, tsp); + } + } while (error == EAGAIN || error == EINTR); - if (error) { - DTRACE_PROBE3(plockstat, rw__error, rwlp, 0, error); - } else { - DTRACE_PROBE2(plockstat, rw__release, rwlp, READ_LOCK); + if (!try_flag) { + DTRACE_PROBE3(plockstat, rw__blocked, rwlp, rd_wr, error == 0); } return (error); } - /* * Common code for rdlock, timedrdlock, wrlock, timedwrlock, tryrdlock, * and trywrlock for process-private (USYNC_THREAD) rwlocks. @@ -446,6 +511,8 @@ shared_rwlock_unlock(rwlock_t *rwlp, int *waked) int rwlock_lock(rwlock_t *rwlp, timespec_t *tsp, int rd_wr) { + volatile uint32_t *rwstate = (volatile uint32_t *)&rwlp->rwlock_readers; + uint32_t readers; ulwp_t *self = curthread; queue_head_t *qp; ulwp_t *ulwp; @@ -456,60 +523,29 @@ rwlock_lock(rwlock_t *rwlp, timespec_t *tsp, int rd_wr) rd_wr &= ~TRY_FLAG; ASSERT(rd_wr == READ_LOCK || rd_wr == WRITE_LOCK); - /* - * Optimize for the case of having only a single thread. - * (Most likely a traditional single-threaded application.) - * We don't need the protection of queue_lock() in this case. - * We need to defer signals, however (the other form of concurrency). - */ - if (!self->ul_uberdata->uberflags.uf_mt) { - sigoff(self); - if (rwlp->rwlock_readers < 0 || - (rd_wr == WRITE_LOCK && rwlp->rwlock_readers != 0)) { - sigon(self); - if (try_flag) - return (EBUSY); - /* - * Sombody other than ourself owns the lock. (If we - * owned the lock, either for reading or writing, we - * would already have returned EDEADLK in our caller.) - * This can happen only in the child of fork1() when - * some now-defunct thread was holding the lock when - * the fork1() was executed by the current thread. - * In this case, we just fall into the long way - * to block, either forever or with a timeout. - */ - ASSERT(MUTEX_OWNER(&rwlp->mutex) != self); - } else { - if (rd_wr == READ_LOCK) - rwlp->rwlock_readers++; - else { - rwlp->rwlock_readers = -1; - rwlp->rwlock_mlockw = LOCKSET; - rwlp->rwlock_mowner = (uintptr_t)self; - } - sigon(self); - DTRACE_PROBE2(plockstat, rw__acquire, rwlp, rd_wr); - return (0); - } - } - if (!try_flag) { DTRACE_PROBE2(plockstat, rw__block, rwlp, rd_wr); } - /* - * Do it the long way. - */ qp = queue_lock(rwlp, MX); +retry: while (error == 0) { - if (rwlp->rwlock_readers < 0 || - (rd_wr == WRITE_LOCK && rwlp->rwlock_readers != 0)) + if (rd_wr == READ_LOCK) { + if (read_lock_try(rwlp, 0)) + goto out; + } else { + if (write_lock_try(rwlp, 0)) + goto out; + } + atomic_or_32(rwstate, URW_HAS_WAITERS); + readers = *rwstate; + ASSERT_CONSISTENT_STATE(readers); + if ((readers & URW_WRITE_LOCKED) || + (rd_wr == WRITE_LOCK && + (readers & URW_READERS_MASK) != 0)) /* EMPTY */; /* somebody holds the lock */ - else if (!rwlp->rwlock_mwaiters) - break; /* no queued waiters */ else if ((ulwp = queue_waiter(qp, rwlp)) == NULL) { - rwlp->rwlock_mwaiters = 0; + atomic_and_32(rwstate, ~URW_HAS_WAITERS); break; /* no queued waiters */ } else { int our_pri = real_priority(self); @@ -547,7 +583,6 @@ rwlock_lock(rwlock_t *rwlp, timespec_t *tsp, int rd_wr) */ self->ul_writer = rd_wr; /* *must* be 0 or 1 */ enqueue(qp, self, rwlp, MX); - rwlp->rwlock_mwaiters = 1; set_parking_flag(self, 1); queue_unlock(qp); if ((error = __lwp_park(tsp, 0)) == EINTR) @@ -555,29 +590,26 @@ rwlock_lock(rwlock_t *rwlp, timespec_t *tsp, int rd_wr) self->ul_writer = 0; set_parking_flag(self, 0); qp = queue_lock(rwlp, MX); - if (self->ul_sleepq) /* timeout or spurious wakeup */ - rwlp->rwlock_mwaiters = dequeue_self(qp, rwlp); + if (self->ul_sleepq && dequeue_self(qp, rwlp) == 0) + atomic_and_32(rwstate, ~URW_HAS_WAITERS); } if (error == 0) { - if (rd_wr == READ_LOCK) - rwlp->rwlock_readers++; - else { - rwlp->rwlock_readers = -1; - /* make it look like we acquired the embedded mutex */ - rwlp->rwlock_mlockw = LOCKSET; - rwlp->rwlock_mowner = (uintptr_t)self; - } - if (!try_flag) { - DTRACE_PROBE3(plockstat, rw__blocked, rwlp, rd_wr, 1); + if (rd_wr == READ_LOCK) { + if (!read_lock_try(rwlp, 1)) + goto retry; + } else { + if (!write_lock_try(rwlp, 1)) + goto retry; } - DTRACE_PROBE2(plockstat, rw__acquire, rwlp, rd_wr); - } else if (!try_flag) { - DTRACE_PROBE3(plockstat, rw__blocked, rwlp, rd_wr, 0); - DTRACE_PROBE3(plockstat, rw__error, rwlp, rd_wr, error); } - (void) rw_queue_release(qp, rwlp); +out: + queue_unlock(qp); + + if (!try_flag) { + DTRACE_PROBE3(plockstat, rw__blocked, rwlp, rd_wr, error == 0); + } return (error); } @@ -595,14 +627,19 @@ rw_rdlock_impl(rwlock_t *rwlp, timespec_t *tsp) * If we already hold a readers lock on this rwlock, * just increment our reference count and return. */ + sigoff(self); readlockp = rwl_entry(rwlp); if (readlockp->rd_count != 0) { - if (readlockp->rd_count == READ_LOCK_MAX) - return (EAGAIN); - readlockp->rd_count++; - DTRACE_PROBE2(plockstat, rw__acquire, rwlp, READ_LOCK); - return (0); + if (readlockp->rd_count == READ_LOCK_MAX) { + sigon(self); + error = EAGAIN; + goto out; + } + sigon(self); + error = 0; + goto out; } + sigon(self); /* * If we hold the writer lock, bail out. @@ -611,18 +648,27 @@ rw_rdlock_impl(rwlock_t *rwlp, timespec_t *tsp) if (self->ul_error_detection) rwlock_error(rwlp, "rwlock_rdlock", "calling thread owns the writer lock"); - return (EDEADLK); + error = EDEADLK; + goto out; } - if (rwlp->rwlock_type == USYNC_PROCESS) /* kernel-level */ + if (read_lock_try(rwlp, 0)) + error = 0; + else if (rwlp->rwlock_type == USYNC_PROCESS) /* kernel-level */ error = shared_rwlock_lock(rwlp, tsp, READ_LOCK); else /* user-level */ error = rwlock_lock(rwlp, tsp, READ_LOCK); +out: if (error == 0) { - readlockp->rd_count = 1; + sigoff(self); + rwl_entry(rwlp)->rd_count++; + sigon(self); if (rwsp) tdb_incr(rwsp->rw_rdlock); + DTRACE_PROBE2(plockstat, rw__acquire, rwlp, READ_LOCK); + } else { + DTRACE_PROBE3(plockstat, rw__error, rwlp, READ_LOCK, error); } return (error); @@ -691,7 +737,8 @@ rw_wrlock_impl(rwlock_t *rwlp, timespec_t *tsp) if (self->ul_error_detection) rwlock_error(rwlp, "rwlock_wrlock", "calling thread owns the readers lock"); - return (EDEADLK); + error = EDEADLK; + goto out; } /* @@ -701,20 +748,30 @@ rw_wrlock_impl(rwlock_t *rwlp, timespec_t *tsp) if (self->ul_error_detection) rwlock_error(rwlp, "rwlock_wrlock", "calling thread owns the writer lock"); - return (EDEADLK); + error = EDEADLK; + goto out; } - if (rwlp->rwlock_type == USYNC_PROCESS) { /* kernel-level */ + if (write_lock_try(rwlp, 0)) + error = 0; + else if (rwlp->rwlock_type == USYNC_PROCESS) /* kernel-level */ error = shared_rwlock_lock(rwlp, tsp, WRITE_LOCK); - } else { /* user-level */ + else /* user-level */ error = rwlock_lock(rwlp, tsp, WRITE_LOCK); - } - if (error == 0 && rwsp) { - tdb_incr(rwsp->rw_wrlock); - rwsp->rw_wrlock_begin_hold = gethrtime(); +out: + if (error == 0) { + rwlp->rwlock_owner = (uintptr_t)self; + if (rwlp->rwlock_type == USYNC_PROCESS) + rwlp->rwlock_ownerpid = udp->pid; + if (rwsp) { + tdb_incr(rwsp->rw_wrlock); + rwsp->rw_wrlock_begin_hold = gethrtime(); + } + DTRACE_PROBE2(plockstat, rw__acquire, rwlp, WRITE_LOCK); + } else { + DTRACE_PROBE3(plockstat, rw__error, rwlp, WRITE_LOCK, error); } - return (error); } @@ -788,24 +845,41 @@ __rw_tryrdlock(rwlock_t *rwlp) * If we already hold a readers lock on this rwlock, * just increment our reference count and return. */ + sigoff(self); readlockp = rwl_entry(rwlp); if (readlockp->rd_count != 0) { - if (readlockp->rd_count == READ_LOCK_MAX) - return (EAGAIN); - readlockp->rd_count++; - DTRACE_PROBE2(plockstat, rw__acquire, rwlp, READ_LOCK); - return (0); + if (readlockp->rd_count == READ_LOCK_MAX) { + sigon(self); + error = EAGAIN; + goto out; + } + sigon(self); + error = 0; + goto out; } + sigon(self); - if (rwlp->rwlock_type == USYNC_PROCESS) /* kernel-level */ + if (read_lock_try(rwlp, 0)) + error = 0; + else if (rwlp->rwlock_type == USYNC_PROCESS) /* kernel-level */ error = shared_rwlock_lock(rwlp, NULL, READ_LOCK_TRY); else /* user-level */ error = rwlock_lock(rwlp, NULL, READ_LOCK_TRY); - if (error == 0) - readlockp->rd_count = 1; - else if (rwsp) - tdb_incr(rwsp->rw_rdlock_try_fail); +out: + if (error == 0) { + sigoff(self); + rwl_entry(rwlp)->rd_count++; + sigon(self); + DTRACE_PROBE2(plockstat, rw__acquire, rwlp, READ_LOCK); + } else { + if (rwsp) + tdb_incr(rwsp->rw_rdlock_try_fail); + if (error != EBUSY) { + DTRACE_PROBE3(plockstat, rw__error, rwlp, READ_LOCK, + error); + } + } return (error); } @@ -822,21 +896,32 @@ __rw_trywrlock(rwlock_t *rwlp) tdb_rwlock_stats_t *rwsp = RWLOCK_STATS(rwlp, udp); int error; - ASSERT(!curthread->ul_critical || curthread->ul_bindflags); + ASSERT(!self->ul_critical || self->ul_bindflags); if (rwsp) tdb_incr(rwsp->rw_wrlock_try); - if (rwlp->rwlock_type == USYNC_PROCESS) { /* kernel-level */ + if (write_lock_try(rwlp, 0)) + error = 0; + else if (rwlp->rwlock_type == USYNC_PROCESS) /* kernel-level */ error = shared_rwlock_lock(rwlp, NULL, WRITE_LOCK_TRY); - } else { /* user-level */ + else /* user-level */ error = rwlock_lock(rwlp, NULL, WRITE_LOCK_TRY); - } - if (rwsp) { - if (error) - tdb_incr(rwsp->rw_wrlock_try_fail); - else + + if (error == 0) { + rwlp->rwlock_owner = (uintptr_t)self; + if (rwlp->rwlock_type == USYNC_PROCESS) + rwlp->rwlock_ownerpid = udp->pid; + if (rwsp) rwsp->rw_wrlock_begin_hold = gethrtime(); + DTRACE_PROBE2(plockstat, rw__acquire, rwlp, WRITE_LOCK); + } else { + if (rwsp) + tdb_incr(rwsp->rw_wrlock_try_fail); + if (error != EBUSY) { + DTRACE_PROBE3(plockstat, rw__error, rwlp, WRITE_LOCK, + error); + } } return (error); } @@ -848,23 +933,26 @@ __rw_trywrlock(rwlock_t *rwlp) int __rw_unlock(rwlock_t *rwlp) { + volatile uint32_t *rwstate = (volatile uint32_t *)&rwlp->rwlock_readers; + uint32_t readers; ulwp_t *self = curthread; uberdata_t *udp = self->ul_uberdata; tdb_rwlock_stats_t *rwsp; - int32_t lock_count; - int waked; - - /* fetch the lock count once; it may change underfoot */ - lock_count = rwlp->rwlock_readers; - if (rwlp->rwlock_type == USYNC_PROCESS) { - /* munge it from rwstate */ - if (lock_count & URW_WRITE_LOCKED) - lock_count = -1; - else - lock_count &= URW_READERS_MASK; + queue_head_t *qp; + int rd_wr; + int waked = 0; + + readers = *rwstate; + ASSERT_CONSISTENT_STATE(readers); + if (readers & URW_WRITE_LOCKED) { + rd_wr = WRITE_LOCK; + readers = 0; + } else { + rd_wr = READ_LOCK; + readers &= URW_READERS_MASK; } - if (lock_count < 0) { + if (rd_wr == WRITE_LOCK) { /* * Since the writer lock is held, we'd better be * holding it, else we cannot legitimately be here. @@ -882,12 +970,18 @@ __rw_unlock(rwlock_t *rwlp) gethrtime() - rwsp->rw_wrlock_begin_hold; rwsp->rw_wrlock_begin_hold = 0; } - } else if (lock_count > 0) { + rwlp->rwlock_owner = 0; + rwlp->rwlock_ownerpid = 0; + } else if (readers > 0) { /* * A readers lock is held; if we don't hold one, bail out. */ - readlock_t *readlockp = rwl_entry(rwlp); + readlock_t *readlockp; + + sigoff(self); + readlockp = rwl_entry(rwlp); if (readlockp->rd_count == 0) { + sigon(self); if (self->ul_error_detection) rwlock_error(rwlp, "rwlock_unlock", "readers lock held, " @@ -899,9 +993,10 @@ __rw_unlock(rwlock_t *rwlp) * just decrement our reference count and return. */ if (--readlockp->rd_count != 0) { - DTRACE_PROBE2(plockstat, rw__release, rwlp, READ_LOCK); - return (0); + sigon(self); + goto out; } + sigon(self); } else { /* * This is a usage error. @@ -912,45 +1007,27 @@ __rw_unlock(rwlock_t *rwlp) return (EPERM); } - if (rwlp->rwlock_type == USYNC_PROCESS) { /* kernel-level */ - (void) shared_rwlock_unlock(rwlp, &waked); - } else if (!udp->uberflags.uf_mt) { /* single threaded */ - /* - * In the case of having only a single thread, we don't - * need the protection of queue_lock() (this parallels - * the optimization made in rwlock_lock(), above). - * As in rwlock_lock(), we need to defer signals. - */ - sigoff(self); - if (rwlp->rwlock_readers > 0) { - rwlp->rwlock_readers--; - DTRACE_PROBE2(plockstat, rw__release, rwlp, READ_LOCK); - } else { - rwlp->rwlock_readers = 0; - /* make it look like we released the embedded mutex */ - rwlp->rwlock_mowner = 0; - rwlp->rwlock_mlockw = LOCKCLEAR; - DTRACE_PROBE2(plockstat, rw__release, rwlp, WRITE_LOCK); - } - sigon(self); - waked = 0; - } else { /* multithreaded */ - queue_head_t *qp; - + if (rd_wr == WRITE_LOCK && write_unlock_try(rwlp)) { + /* EMPTY */; + } else if (rd_wr == READ_LOCK && read_unlock_try(rwlp)) { + /* EMPTY */; + } else if (rwlp->rwlock_type == USYNC_PROCESS) { + (void) _private_mutex_lock(&rwlp->mutex); + (void) __lwp_rwlock_unlock(rwlp); + (void) _private_mutex_unlock(&rwlp->mutex); + waked = 1; + } else { qp = queue_lock(rwlp, MX); - if (rwlp->rwlock_readers > 0) { - rwlp->rwlock_readers--; - DTRACE_PROBE2(plockstat, rw__release, rwlp, READ_LOCK); - } else { - rwlp->rwlock_readers = 0; - /* make it look like we released the embedded mutex */ - rwlp->rwlock_mowner = 0; - rwlp->rwlock_mlockw = LOCKCLEAR; - DTRACE_PROBE2(plockstat, rw__release, rwlp, WRITE_LOCK); - } + if (rd_wr == READ_LOCK) + atomic_dec_32(rwstate); + else + atomic_and_32(rwstate, ~URW_WRITE_LOCKED); waked = rw_queue_release(qp, rwlp); } +out: + DTRACE_PROBE2(plockstat, rw__release, rwlp, rd_wr); + /* * Yield to the thread we just waked up, just in case we might * be about to grab the rwlock again immediately upon return. diff --git a/usr/src/lib/libc/port/threads/sigaction.c b/usr/src/lib/libc/port/threads/sigaction.c index 529530f2af..3d8f747100 100644 --- a/usr/src/lib/libc/port/threads/sigaction.c +++ b/usr/src/lib/libc/port/threads/sigaction.c @@ -83,6 +83,9 @@ call_user_handler(int sig, siginfo_t *sip, ucontext_t *ucp) * while holding the sig's sig_lock for the least possible time. * We must acquire the sig's sig_lock because some thread running * in sigaction() might be establishing a new signal handler. + * The code in sigaction() acquires the writer lock; here + * we acquire the readers lock to ehance concurrency in the + * face of heavy signal traffic, such as generated by java. * * Locking exceptions: * No locking for a child of vfork(). @@ -103,12 +106,12 @@ call_user_handler(int sig, siginfo_t *sip, ucontext_t *ucp) /* we wish this assignment could be atomic */ (void) _private_memcpy(&uact, (void *)sap, sizeof (uact)); } else { - mutex_t *mp = &udp->siguaction[sig].sig_lock; - lmutex_lock(mp); + rwlock_t *rwlp = &udp->siguaction[sig].sig_lock; + lrw_rdlock(rwlp); (void) _private_memcpy(&uact, (void *)sap, sizeof (uact)); if (sig == SIGCANCEL && (sap->sa_flags & SA_RESETHAND)) sap->sa_sigaction = SIG_DFL; - lmutex_unlock(mp); + lrw_unlock(rwlp); } /* @@ -324,7 +327,7 @@ _libc_sigaction(int sig, const struct sigaction *nact, struct sigaction *oact) } if (!self->ul_vfork) - lmutex_lock(&udp->siguaction[sig].sig_lock); + lrw_wrlock(&udp->siguaction[sig].sig_lock); oaction = udp->siguaction[sig].sig_uaction; @@ -401,7 +404,7 @@ _libc_sigaction(int sig, const struct sigaction *nact, struct sigaction *oact) } if (!self->ul_vfork) - lmutex_unlock(&udp->siguaction[sig].sig_lock); + lrw_unlock(&udp->siguaction[sig].sig_lock); return (rv); } @@ -633,7 +636,7 @@ _sigprocmask(int how, const sigset_t *set, sigset_t *oset) /* * Called at library initialization to set up signal handling. - * All we really do is initialize the sig_lock mutexes. + * All we really do is initialize the sig_lock rwlocks. * All signal handlers are either SIG_DFL or SIG_IGN on exec(). * However, if any signal handlers were established on alternate * link maps before the primary link map has been initialized, @@ -645,10 +648,14 @@ signal_init() uberdata_t *udp = curthread->ul_uberdata; struct sigaction *sap; struct sigaction act; + rwlock_t *rwlp; int sig; for (sig = 0; sig < NSIG; sig++) { - udp->siguaction[sig].sig_lock.mutex_magic = MUTEX_MAGIC; + rwlp = &udp->siguaction[sig].sig_lock; + rwlp->rwlock_magic = RWL_MAGIC; + rwlp->mutex.mutex_flag = LOCK_INITED; + rwlp->mutex.mutex_magic = MUTEX_MAGIC; sap = &udp->siguaction[sig].sig_uaction; if (sap->sa_sigaction != SIG_DFL && sap->sa_sigaction != SIG_IGN && @@ -694,13 +701,13 @@ void setup_cancelsig(int sig) { uberdata_t *udp = curthread->ul_uberdata; - mutex_t *mp = &udp->siguaction[sig].sig_lock; + rwlock_t *rwlp = &udp->siguaction[sig].sig_lock; struct sigaction act; ASSERT(sig == SIGCANCEL || sig == SIGAIOCANCEL); - lmutex_lock(mp); + lrw_rdlock(rwlp); act = udp->siguaction[sig].sig_uaction; - lmutex_unlock(mp); + lrw_unlock(rwlp); if (act.sa_sigaction == SIG_DFL || act.sa_sigaction == SIG_IGN) act.sa_flags = SA_SIGINFO; diff --git a/usr/src/lib/libc/port/threads/synch.c b/usr/src/lib/libc/port/threads/synch.c index 9c6e918620..ec9fabc226 100644 --- a/usr/src/lib/libc/port/threads/synch.c +++ b/usr/src/lib/libc/port/threads/synch.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -292,7 +292,7 @@ spin_lock_clear(mutex_t *mp) ulwp_t *self = curthread; mp->mutex_owner = 0; - if (swap32(&mp->mutex_lockword, 0) & WAITERMASK) { + if (atomic_swap_32(&mp->mutex_lockword, 0) & WAITERMASK) { (void) ___lwp_mutex_wakeup(mp); if (self->ul_spin_lock_wakeup != UINT_MAX) self->ul_spin_lock_wakeup++; @@ -569,18 +569,10 @@ queue_slot(queue_head_t *qp, void *wchan, int *more, ulwp_t **prevp) } ulwp_t * -dequeue(queue_head_t *qp, void *wchan, int *more) +queue_unlink(queue_head_t *qp, ulwp_t **ulwpp, ulwp_t *prev) { - ulwp_t **ulwpp; ulwp_t *ulwp; - ulwp_t *prev; - - if ((ulwpp = queue_slot(qp, wchan, more, &prev)) == NULL) - return (NULL); - /* - * Dequeue the waiter. - */ ulwp = *ulwpp; *ulwpp = ulwp->ul_link; ulwp->ul_link = NULL; @@ -593,6 +585,17 @@ dequeue(queue_head_t *qp, void *wchan, int *more) return (ulwp); } +ulwp_t * +dequeue(queue_head_t *qp, void *wchan, int *more) +{ + ulwp_t **ulwpp; + ulwp_t *prev; + + if ((ulwpp = queue_slot(qp, wchan, more, &prev)) == NULL) + return (NULL); + return (queue_unlink(qp, ulwpp, prev)); +} + /* * Return a pointer to the highest priority thread sleeping on wchan. */ @@ -623,16 +626,10 @@ dequeue_self(queue_head_t *qp, void *wchan) prev = ulwp, ulwpp = &ulwp->ul_link) { if (ulwp == self) { /* dequeue ourself */ - *ulwpp = self->ul_link; - if (qp->qh_tail == self) - qp->qh_tail = prev; - qp->qh_qlen--; ASSERT(self->ul_wchan == wchan); + (void) queue_unlink(qp, ulwpp, prev); self->ul_cvmutex = NULL; - self->ul_sleepq = NULL; - self->ul_wchan = NULL; self->ul_cv_wake = 0; - self->ul_link = NULL; found = 1; break; } @@ -670,7 +667,6 @@ unsleep_self(void) * to recursion. Just manipulate self->ul_critical directly. */ self->ul_critical++; - self->ul_writer = 0; while (self->ul_sleepq != NULL) { qp = queue_lock(self->ul_wchan, self->ul_qtype); /* @@ -679,8 +675,10 @@ unsleep_self(void) * If so, just loop around and try again. * dequeue_self() clears self->ul_sleepq. */ - if (qp == self->ul_sleepq) + if (qp == self->ul_sleepq) { (void) dequeue_self(qp, self->ul_wchan); + self->ul_writer = 0; + } queue_unlock(qp); } self->ul_critical--; @@ -969,11 +967,11 @@ mutex_trylock_adaptive(mutex_t *mp) * programs will not suffer in any case. */ enter_critical(self); /* protects ul_schedctl */ - incr32(&mp->mutex_spinners); + atomic_inc_32(&mp->mutex_spinners); for (count = 0; count < max; count++) { if (*lockp == 0 && set_lock_byte(lockp) == 0) { *ownerp = (uintptr_t)self; - decr32(&mp->mutex_spinners); + atomic_dec_32(&mp->mutex_spinners); exit_critical(self); DTRACE_PROBE2(plockstat, mutex__spun, 1, count); DTRACE_PROBE3(plockstat, mutex__acquire, mp, 0, count); @@ -1003,7 +1001,7 @@ mutex_trylock_adaptive(mutex_t *mp) scp->sc_state != SC_ONPROC)) break; } - decr32(&mp->mutex_spinners); + atomic_dec_32(&mp->mutex_spinners); exit_critical(self); DTRACE_PROBE2(plockstat, mutex__spun, 0, count); @@ -1173,8 +1171,8 @@ mutex_unlock_queue(mutex_t *mp) if (!(*lockw & WAITERMASK)) { /* no waiter exists right now */ mp->mutex_owner = 0; DTRACE_PROBE2(plockstat, mutex__release, mp, 0); - if (!(swap32(lockw, 0) & WAITERMASK)) /* still no waiters */ - return (0); + if (!(atomic_swap_32(lockw, 0) & WAITERMASK)) + return (0); /* still no waiters */ no_preempt(self); /* ensure a prompt wakeup */ lwpid = mutex_wakeup(mp); } else { @@ -1183,7 +1181,8 @@ mutex_unlock_queue(mutex_t *mp) spinp = (volatile uint32_t *)&mp->mutex_spinners; mp->mutex_owner = 0; DTRACE_PROBE2(plockstat, mutex__release, mp, 0); - (void) swap32(lockw, WAITER); /* clear lock, retain waiter */ + /* clear lock, retain waiter */ + (void) atomic_swap_32(lockw, WAITER); /* * We spin here fewer times than mutex_trylock_adaptive(). @@ -1249,14 +1248,14 @@ mutex_unlock_process(mutex_t *mp) DTRACE_PROBE2(plockstat, mutex__release, mp, 0); if (count == 0) { /* clear lock, test waiter */ - if (!(swap32(&mp->mutex_lockword, 0) & WAITERMASK)) { + if (!(atomic_swap_32(&mp->mutex_lockword, 0) & WAITERMASK)) { /* no waiters now */ preempt(self); return; } } else { /* clear lock, retain waiter */ - (void) swap32(&mp->mutex_lockword, WAITER); + (void) atomic_swap_32(&mp->mutex_lockword, WAITER); lockp = (volatile uint8_t *)&mp->mutex_lockw; while (--count >= 0) { if (*lockp != 0) { @@ -1945,7 +1944,7 @@ mutex_unlock_internal(mutex_t *mp) } else if (mtype & USYNC_PROCESS_ROBUST) { error = ___lwp_mutex_unlock(mp); } else { - if (swap32(&mp->mutex_lockword, 0) & WAITERMASK) + if (atomic_swap_32(&mp->mutex_lockword, 0) & WAITERMASK) (void) ___lwp_mutex_wakeup(mp); error = 0; } @@ -1961,7 +1960,8 @@ mutex_unlock_internal(mutex_t *mp) mp->mutex_owner = 0; mp->mutex_ownerpid = 0; DTRACE_PROBE2(plockstat, mutex__release, mp, 0); - if (swap32(&mp->mutex_lockword, 0) & WAITERMASK) { + if (atomic_swap_32(&mp->mutex_lockword, 0) & + WAITERMASK) { no_preempt(self); (void) ___lwp_mutex_wakeup(mp); preempt(self); @@ -2038,7 +2038,7 @@ fast_unlock: /* no waiter exists right now */ mp->mutex_owner = 0; DTRACE_PROBE2(plockstat, mutex__release, mp, 0); - if (swap32(&mp->mutex_lockword, 0) & + if (atomic_swap_32(&mp->mutex_lockword, 0) & WAITERMASK) { /* a waiter suddenly appeared */ no_preempt(self); @@ -2088,7 +2088,7 @@ fast_unlock: mp->mutex_owner = 0; mp->mutex_ownerpid = 0; DTRACE_PROBE2(plockstat, mutex__release, mp, 0); - if (swap32(&mp->mutex_lockword, 0) & + if (atomic_swap_32(&mp->mutex_lockword, 0) & WAITERMASK) { no_preempt(self); (void) ___lwp_mutex_wakeup(mp); @@ -2408,7 +2408,7 @@ _pthread_spin_unlock(pthread_spinlock_t *lock) mp->mutex_owner = 0; mp->mutex_ownerpid = 0; DTRACE_PROBE2(plockstat, mutex__release, mp, 0); - (void) swap32(&mp->mutex_lockword, 0); + (void) atomic_swap_32(&mp->mutex_lockword, 0); preempt(self); return (0); } @@ -3035,8 +3035,53 @@ cond_signal_internal(cond_t *cvp) return (error); } -#define MAXLWPS 128 /* max remembered lwpids before overflow */ -#define NEWLWPS 2048 /* max remembered lwpids at first overflow */ +/* + * Utility function called from cond_broadcast() and rw_queue_release() + * to (re)allocate a big buffer to hold the lwpids of all the threads + * to be set running after they are removed from their sleep queues. + * Since we are holding a queue lock, we cannot call any function + * that might acquire a lock. mmap(), munmap() and lwp_unpark_all() + * are simple system calls and are safe in this regard. + */ +lwpid_t * +alloc_lwpids(lwpid_t *lwpid, int *nlwpid_ptr, int *maxlwps_ptr) +{ + /* + * Allocate NEWLWPS ids on the first overflow. + * Double the allocation each time after that. + */ + int nlwpid = *nlwpid_ptr; + int maxlwps = *maxlwps_ptr; + int first_allocation; + int newlwps; + void *vaddr; + + ASSERT(nlwpid == maxlwps); + + first_allocation = (maxlwps == MAXLWPS); + newlwps = first_allocation? NEWLWPS : 2 * maxlwps; + vaddr = _private_mmap(NULL, newlwps * sizeof (lwpid_t), + PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, (off_t)0); + + if (vaddr == MAP_FAILED) { + /* + * Let's hope this never happens. + * If it does, then we have a terrible + * thundering herd on our hands. + */ + (void) __lwp_unpark_all(lwpid, nlwpid); + *nlwpid_ptr = 0; + } else { + (void) _memcpy(vaddr, lwpid, maxlwps * sizeof (lwpid_t)); + if (!first_allocation) + (void) _private_munmap(lwpid, + maxlwps * sizeof (lwpid_t)); + lwpid = vaddr; + *maxlwps_ptr = newlwps; + } + + return (lwpid); +} #pragma weak pthread_cond_broadcast = cond_broadcast_internal #pragma weak _pthread_cond_broadcast = cond_broadcast_internal @@ -3051,16 +3096,15 @@ cond_broadcast_internal(cond_t *cvp) int error = 0; queue_head_t *qp; mutex_t *mp; - queue_head_t *mqp; mutex_t *mp_cache = NULL; - queue_head_t *mqp_cache = NULL; + queue_head_t *mqp = NULL; ulwp_t **ulwpp; ulwp_t *ulwp; ulwp_t *prev = NULL; - lwpid_t buffer[MAXLWPS]; - lwpid_t *lwpid = buffer; int nlwpid = 0; int maxlwps = MAXLWPS; + lwpid_t buffer[MAXLWPS]; + lwpid_t *lwpid = buffer; if (csp) tdb_incr(csp->cond_broadcast); @@ -3085,89 +3129,61 @@ cond_broadcast_internal(cond_t *cvp) * on-stack buffer, we need to allocate more but we can't call * lmalloc() because we are holding a queue lock when the overflow * occurs and lmalloc() acquires a lock. We can't use alloca() - * either because the application may have allocated a small stack - * and we don't want to overrun the stack. So we use the mmap() + * either because the application may have allocated a small + * stack and we don't want to overrun the stack. So we call + * alloc_lwpids() to allocate a bigger buffer using the mmap() * system call directly since that path acquires no locks. */ qp = queue_lock(cvp, CV); cvp->cond_waiters_user = 0; ulwpp = &qp->qh_head; while ((ulwp = *ulwpp) != NULL) { - if (ulwp->ul_wchan != cvp) { prev = ulwp; ulwpp = &ulwp->ul_link; continue; } - *ulwpp = ulwp->ul_link; if (qp->qh_tail == ulwp) qp->qh_tail = prev; qp->qh_qlen--; ulwp->ul_link = NULL; - mp = ulwp->ul_cvmutex; /* his mutex */ ulwp->ul_cvmutex = NULL; ASSERT(mp != NULL); - if (ulwp->ul_cv_wake || !MUTEX_OWNED(mp, self)) { ulwp->ul_sleepq = NULL; ulwp->ul_wchan = NULL; ulwp->ul_cv_wake = 0; - if (nlwpid == maxlwps) { - /* - * Allocate NEWLWPS ids on the first overflow. - * Double the allocation each time after that. - */ - int newlwps = (lwpid == buffer)? NEWLWPS : - 2 * maxlwps; - void *vaddr = _private_mmap(NULL, - newlwps * sizeof (lwpid_t), - PROT_READ|PROT_WRITE, - MAP_PRIVATE|MAP_ANON, -1, (off_t)0); - if (vaddr == MAP_FAILED) { - /* - * Let's hope this never happens. - * If it does, then we have a terrible - * thundering herd on our hands. - */ - (void) __lwp_unpark_all(lwpid, nlwpid); - nlwpid = 0; - } else { - (void) _memcpy(vaddr, lwpid, - maxlwps * sizeof (lwpid_t)); - if (lwpid != buffer) - (void) _private_munmap(lwpid, - maxlwps * sizeof (lwpid_t)); - lwpid = vaddr; - maxlwps = newlwps; - } - } + if (nlwpid == maxlwps) + lwpid = alloc_lwpids(lwpid, &nlwpid, &maxlwps); lwpid[nlwpid++] = ulwp->ul_lwpid; } else { if (mp != mp_cache) { - if (mqp_cache != NULL) - queue_unlock(mqp_cache); - mqp_cache = queue_lock(mp, MX); mp_cache = mp; + if (mqp != NULL) + queue_unlock(mqp); + mqp = queue_lock(mp, MX); } - mqp = mqp_cache; enqueue(mqp, ulwp, mp, MX); mp->mutex_waiters = 1; } } - if (mqp_cache != NULL) - queue_unlock(mqp_cache); - queue_unlock(qp); - if (nlwpid) { + if (mqp != NULL) + queue_unlock(mqp); + if (nlwpid == 0) { + queue_unlock(qp); + } else { + no_preempt(self); + queue_unlock(qp); if (nlwpid == 1) (void) __lwp_unpark(lwpid[0]); else (void) __lwp_unpark_all(lwpid, nlwpid); + preempt(self); } if (lwpid != buffer) (void) _private_munmap(lwpid, maxlwps * sizeof (lwpid_t)); - return (error); } diff --git a/usr/src/lib/libc/sparc/Makefile b/usr/src/lib/libc/sparc/Makefile index 61472f35b6..63e8e88ea4 100644 --- a/usr/src/lib/libc/sparc/Makefile +++ b/usr/src/lib/libc/sparc/Makefile @@ -1111,7 +1111,7 @@ TIL= \ $(TIL:%=pics/%) := CFLAGS += $(LIBCBASE)/threads/sparc.il # special kludge for inlines with 'cas': -pics/synch.o pics/lwp.o := sparc_CFLAGS += -_gcc=-Wa,-xarch=v8plus +pics/rwlock.o pics/synch.o pics/lwp.o := sparc_CFLAGS += -_gcc=-Wa,-xarch=v8plus # Files in port/fp subdirectory that need base.il inline template IL= \ diff --git a/usr/src/lib/libc/sparc/threads/sparc.il b/usr/src/lib/libc/sparc/threads/sparc.il index c3f81e69b3..57d351ae6d 100644 --- a/usr/src/lib/libc/sparc/threads/sparc.il +++ b/usr/src/lib/libc/sparc/threads/sparc.il @@ -55,12 +55,12 @@ * 32-bit applications that use %g5 as an invariant register. */ - .inline cas32, 0 + .inline atomic_cas_32, 0 .word 0xd5e21009 ! cas [%o0], %o1, %o2 mov %o2, %o0 .end - .inline swap32, 0 + .inline atomic_swap_32, 0 ld [%o0], %o2 1: mov %o1, %o3 @@ -71,7 +71,7 @@ mov %o3, %o0 .end - .inline incr32, 0 + .inline atomic_inc_32, 0 ld [%o0], %o2 1: add %o2, 1, %o3 @@ -81,7 +81,7 @@ mov %o3, %o2 .end - .inline decr32, 0 + .inline atomic_dec_32, 0 ld [%o0], %o2 1: sub %o2, 1, %o3 @@ -91,6 +91,26 @@ mov %o3, %o2 .end + .inline atomic_and_32, 0 + ld [%o0], %o2 +1: + and %o2, %o1, %o3 + .word 0xd7e2100a ! cas [%o0], %o2, %o3 + cmp %o2, %o3 + bne,a 1b + mov %o3, %o2 + .end + + .inline atomic_or_32, 0 + ld [%o0], %o2 +1: + or %o2, %o1, %o3 + .word 0xd7e2100a ! cas [%o0], %o2, %o3 + cmp %o2, %o3 + bne,a 1b + mov %o3, %o2 + .end + .inline caller, 0 mov %i7, %o0 .end diff --git a/usr/src/lib/libc/sparcv9/threads/sparcv9.il b/usr/src/lib/libc/sparcv9/threads/sparcv9.il index f84623f93c..4f1d543f6c 100644 --- a/usr/src/lib/libc/sparcv9/threads/sparcv9.il +++ b/usr/src/lib/libc/sparcv9/threads/sparcv9.il @@ -52,12 +52,12 @@ membar #LoadLoad .end - .inline cas32, 0 + .inline atomic_cas_32, 0 cas [%o0], %o1, %o2 mov %o2, %o0 .end - .inline swap32, 0 + .inline atomic_swap_32, 0 ld [%o0], %o2 1: mov %o1, %o3 @@ -68,7 +68,7 @@ mov %o3, %o0 .end - .inline incr32, 0 + .inline atomic_inc_32, 0 ld [%o0], %o2 1: add %o2, 1, %o3 @@ -78,7 +78,7 @@ mov %o3, %o2 .end - .inline decr32, 0 + .inline atomic_dec_32, 0 ld [%o0], %o2 1: sub %o2, 1, %o3 @@ -88,6 +88,26 @@ mov %o3, %o2 .end + .inline atomic_and_32, 0 + ld [%o0], %o2 +1: + and %o2, %o1, %o3 + cas [%o0], %o2, %o3 + cmp %o2, %o3 + bne,a,pn %icc, 1b + mov %o3, %o2 + .end + + .inline atomic_or_32, 0 + ld [%o0], %o2 +1: + or %o2, %o1, %o3 + cas [%o0], %o2, %o3 + cmp %o2, %o3 + bne,a,pn %icc, 1b + mov %o3, %o2 + .end + .inline caller, 0 mov %i7, %o0 .end diff --git a/usr/src/lib/libc_db/common/thread_db.c b/usr/src/lib/libc_db/common/thread_db.c index 7759b68a20..9c10183772 100644 --- a/usr/src/lib/libc_db/common/thread_db.c +++ b/usr/src/lib/libc_db/common/thread_db.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -19,8 +18,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -2556,42 +2556,35 @@ sync_get_info_common(const td_synchandle_t *sh_p, struct ps_prochandle *ph_p, si_p->si_data = (psaddr_t)generic_so.semaphore.count; break; case RWL_MAGIC: + { + uint32_t rwstate; + if (trunc && ps_pdread(ph_p, sh_p->sh_unique, &generic_so.rwlock, sizeof (generic_so.rwlock)) != PS_OK) return (TD_DBERR); si_p->si_type = TD_SYNC_RWLOCK; si_p->si_shared_type = generic_so.rwlock.rwlock_type; si_p->si_size = sizeof (generic_so.rwlock); - if (generic_so.rwlock.rwlock_type == USYNC_PROCESS) { - uint32_t *rwstate = - (uint32_t *)&si_p->si_state.nreaders; - - if (*rwstate & URW_WRITE_LOCKED) { - si_p->si_state.nreaders = -1; - si_p->si_is_wlock = 1; - si_p->si_owner.th_ta_p = sh_p->sh_ta_p; - si_p->si_owner.th_unique = - generic_so.rwlock.rwlock_owner; - } else if (*rwstate & URW_READERS_MASK) - si_p->si_state.nreaders = - *rwstate & URW_READERS_MASK; - else - si_p->si_state.nreaders = 0; - si_p->si_has_waiters = (*rwstate & URW_HAS_WAITERS); + + rwstate = (uint32_t)generic_so.rwlock.rwlock_readers; + if (rwstate & URW_WRITE_LOCKED) { + si_p->si_state.nreaders = -1; + si_p->si_is_wlock = 1; + si_p->si_owner.th_ta_p = sh_p->sh_ta_p; + si_p->si_owner.th_unique = + generic_so.rwlock.rwlock_owner; + if (si_p->si_shared_type & USYNC_PROCESS) + si_p->si_ownerpid = + generic_so.rwlock.rwlock_ownerpid; } else { - si_p->si_state.nreaders = generic_so.rwlock.readers; - si_p->si_has_waiters = - generic_so.rwlock.rwlock_mwaiters; - if (si_p->si_state.nreaders == -1) { - si_p->si_is_wlock = 1; - si_p->si_owner.th_ta_p = sh_p->sh_ta_p; - si_p->si_owner.th_unique = - generic_so.rwlock.rwlock_mowner; - } + si_p->si_state.nreaders = (rwstate & URW_READERS_MASK); } + si_p->si_has_waiters = ((rwstate & URW_HAS_WAITERS) != 0); + /* this is useless but the old interface provided it */ si_p->si_data = (psaddr_t)generic_so.rwlock.readers; break; + } default: return (TD_BADSH); } @@ -2823,36 +2816,18 @@ __td_sync_get_stats(const td_synchandle_t *sh_p, td_syncstats_t *ss_p) } case TDB_RWLOCK: { - psaddr_t cond_addr; - tdb_sync_stats_t cond_stats; td_rwlock_stats_t *rwsp = &ss_p->ss_un.rwlock; ss_p->ss_info.si_type = TD_SYNC_RWLOCK; ss_p->ss_info.si_size = sizeof (rwlock_t); rwsp->rw_rdlock = sync_stats.un.rwlock.rw_rdlock; - cond_addr = (psaddr_t)&((rwlock_t *)sh_p->sh_unique)->readercv; - if (read_sync_stats(ta_p, hashaddr, cond_addr, &cond_stats) - == TD_OK) { - rwsp->rw_rdlock_sleep = - cond_stats.un.cond.cond_wait; - rwsp->rw_rdlock_sleep_time = - cond_stats.un.cond.cond_wait_sleep_time; - } rwsp->rw_rdlock_try = sync_stats.un.rwlock.rw_rdlock_try; rwsp->rw_rdlock_try_fail = sync_stats.un.rwlock.rw_rdlock_try_fail; rwsp->rw_wrlock = sync_stats.un.rwlock.rw_wrlock; - cond_addr = (psaddr_t)&((rwlock_t *)sh_p->sh_unique)->writercv; - if (read_sync_stats(ta_p, hashaddr, cond_addr, &cond_stats) - == TD_OK) { - rwsp->rw_wrlock_sleep = - cond_stats.un.cond.cond_wait; - rwsp->rw_wrlock_sleep_time = - cond_stats.un.cond.cond_wait_sleep_time; - } rwsp->rw_wrlock_hold_time = sync_stats.un.rwlock.rw_wrlock_hold_time; rwsp->rw_wrlock_try = @@ -2900,8 +2875,8 @@ out: * Change the state of a synchronization variable. * 1) mutex lock state set to value * 2) semaphore's count set to value - * 3) writer's lock set to value - * 4) reader's lock number of readers set to value + * 3) writer's lock set by value < 0 + * 4) reader's lock number of readers set to value >= 0 * Currently unused by dbx. */ #pragma weak td_sync_setstate = __td_sync_setstate @@ -2912,6 +2887,7 @@ __td_sync_setstate(const td_synchandle_t *sh_p, long lvalue) int trunc = 0; td_err_e return_val; td_so_un_t generic_so; + uint32_t *rwstate; int value = (int)lvalue; if ((ph_p = ph_lock_sh(sh_p, &return_val)) == NULL) @@ -2975,18 +2951,12 @@ __td_sync_setstate(const td_synchandle_t *sh_p, long lvalue) return_val = TD_DBERR; break; } - if (generic_so.rwlock.rwlock_type == USYNC_PROCESS) { - uint32_t *rwstate = - (uint32_t *)&generic_so.rwlock.readers; - if (value < 0) - *rwstate = URW_WRITE_LOCKED; - else if (value > 0) - *rwstate = (value & URW_READERS_MASK); - else - *rwstate = 0; - } else - generic_so.rwlock.readers = value; - + rwstate = (uint32_t *)&generic_so.rwlock.readers; + *rwstate &= URW_HAS_WAITERS; + if (value < 0) + *rwstate |= URW_WRITE_LOCKED; + else + *rwstate |= (value & URW_READERS_MASK); if (ps_pdwrite(ph_p, sh_p->sh_unique, &generic_so.rwlock, sizeof (generic_so.rwlock)) != PS_OK) return_val = TD_DBERR; diff --git a/usr/src/uts/common/sys/synch.h b/usr/src/uts/common/sys/synch.h index 8f52d720cb..9b428e6040 100644 --- a/usr/src/uts/common/sys/synch.h +++ b/usr/src/uts/common/sys/synch.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -19,8 +18,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -116,12 +116,12 @@ typedef struct _lwp_sema { * for rwlock_t in head/sync.h that we cannot change. */ typedef struct _lwp_rwlock { - int32_t readers; /* -1 == writer else # of readers */ + int32_t readers; /* rwstate word */ uint16_t type; uint16_t magic; - lwp_mutex_t mutex; /* used to indicate ownership */ - lwp_cond_t readercv; /* unused */ - lwp_cond_t writercv; /* unused */ + lwp_mutex_t mutex; /* used with process-shared rwlocks */ + lwp_cond_t readercv; /* used only to indicate ownership */ + lwp_cond_t writercv; /* used only to indicate ownership */ } lwp_rwlock_t; #endif /* _ASM */ diff --git a/usr/src/uts/common/syscall/lwp_sobj.c b/usr/src/uts/common/syscall/lwp_sobj.c index 5b255912a0..65d9236a32 100644 --- a/usr/src/uts/common/syscall/lwp_sobj.c +++ b/usr/src/uts/common/syscall/lwp_sobj.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -19,15 +18,15 @@ * * CDDL HEADER END */ -/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ -/* All Rights Reserved */ - /* - * Copyright 2004 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ +/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ +/* All Rights Reserved */ + #pragma ident "%Z%%M% %I% %E% SMI" #include <sys/param.h> @@ -2187,7 +2186,7 @@ out: * * If the first thread is a reader we scan the queue releasing all readers * until we hit a writer or the end of the queue. If the first thread is a - * writer we still need to check for another writer (i.e. URW_WRITE_WANTED). + * writer we still need to check for another writer. */ void lwp_rwlock_release(lwpchan_t *lwpchan, lwp_rwlock_t *rw) @@ -2218,9 +2217,7 @@ lwp_rwlock_release(lwpchan_t *lwpchan, lwp_rwlock_t *rw) /* tpp already set for next thread. */ continue; } else { - rwstate |= - (URW_WRITE_WANTED|URW_HAS_WAITERS); - + rwstate |= URW_HAS_WAITERS; /* We need look no further. */ break; } @@ -2236,8 +2233,11 @@ lwp_rwlock_release(lwpchan_t *lwpchan, lwp_rwlock_t *rw) /* tpp already set for next thread. */ continue; - } else + } else { rwstate |= URW_HAS_WAITERS; + /* We need look no further. */ + break; + } } } tpp = &tp->t_link; @@ -2398,54 +2398,42 @@ lwp_rwlock_lock(lwp_rwlock_t *rw, timespec_t *tsp, int rd_wr) /* * Fetch the current rwlock state. * - * The possibility of spurious wake-ups or killed waiters means that - * rwstate's URW_HAS_WAITERS and URW_WRITE_WANTED bits may indicate - * false positives. We only fix these if they are important to us. + * The possibility of spurious wake-ups or killed waiters means + * rwstate's URW_HAS_WAITERS bit may indicate false positives. + * We only fix these if they are important to us. * * Although various error states can be observed here (e.g. the lock * is not held, but there are waiters) we assume these are applicaton * errors and so we take no corrective action. */ fuword32_noerr(&rw->rwlock_readers, &rwstate); - /* - * If the lock is uncontended we can acquire it here. These tests - * should have already been done at user-level, we just need to be - * sure. + * We cannot legitimately get here from user-level + * without URW_HAS_WAITERS being set. + * Set it now to guard against user-level error. */ - if (rd_wr == READ_LOCK) { - if ((rwstate & ~URW_READERS_MASK) == 0) { - rwstate++; - acquired = 1; - } - } else if (rwstate == 0) { - rwstate = URW_WRITE_LOCKED; - acquired = 1; - } + rwstate |= URW_HAS_WAITERS; /* - * We can only try harder if the lock isn't held by a writer. + * We can try only if the lock isn't held by a writer. */ - if (!acquired && !(rwstate & URW_WRITE_LOCKED)) { + if (!(rwstate & URW_WRITE_LOCKED)) { tp = lwp_queue_waiter(&lwpchan); if (tp == NULL) { /* * Hmmm, rwstate indicates waiters but there are * none queued. This could just be the result of a - * spurious wakeup, so let's fix it. - */ - rwstate &= URW_READERS_MASK; - - /* - * We now have another chance to acquire the lock - * uncontended, but this is the last chance for a - * writer to acquire the lock without blocking. + * spurious wakeup, so let's ignore it. + * + * We now have a chance to acquire the lock + * uncontended, but this is the last chance for + * a writer to acquire the lock without blocking. */ if (rd_wr == READ_LOCK) { rwstate++; acquired = 1; - } else if (rwstate == 0) { - rwstate = URW_WRITE_LOCKED; + } else if ((rwstate & URW_READERS_MASK) == 0) { + rwstate |= URW_WRITE_LOCKED; acquired = 1; } } else if (rd_wr == READ_LOCK) { @@ -2475,7 +2463,7 @@ lwp_rwlock_lock(lwp_rwlock_t *rw, timespec_t *tsp, int rd_wr) if (acquired || try_flag || time_error) { /* - * We're not going to block this time! + * We're not going to block this time. */ suword32_noerr(&rw->rwlock_readers, rwstate); lwpchan_unlock(&lwpchan, LWPCHAN_CVPOOL); @@ -2510,16 +2498,16 @@ lwp_rwlock_lock(lwp_rwlock_t *rw, timespec_t *tsp, int rd_wr) * We're about to block, so indicate what kind of waiter we are. */ t->t_writer = 0; - rwstate |= URW_HAS_WAITERS; - if (rd_wr == WRITE_LOCK) { + if (rd_wr == WRITE_LOCK) t->t_writer = TRW_WANT_WRITE; - rwstate |= URW_WRITE_WANTED; - } suword32_noerr(&rw->rwlock_readers, rwstate); /* * Unlock the rwlock's mutex (pagefaults are possible here). */ + suword32_noerr((uint32_t *)&mp->mutex_owner, 0); + suword32_noerr((uint32_t *)&mp->mutex_owner + 1, 0); + suword32_noerr(&mp->mutex_ownerpid, 0); ulock_clear(&mp->mutex_lockw); fuword8_noerr(&mp->mutex_waiters, &mwaiters); if (mwaiters != 0) { @@ -2622,6 +2610,8 @@ out_drop: lwpchan_lock(&mlwpchan, LWPCHAN_MPPOOL); mlocked = 1; } + suword32_noerr((uint32_t *)&mp->mutex_owner, 0); + suword32_noerr((uint32_t *)&mp->mutex_owner + 1, 0); suword32_noerr(&mp->mutex_ownerpid, 0); ulock_clear(&mp->mutex_lockw); fuword8_noerr(&mp->mutex_waiters, &mwaiters); diff --git a/usr/src/uts/intel/sys/synch32.h b/usr/src/uts/intel/sys/synch32.h index 3966fac47d..1674444b6d 100644 --- a/usr/src/uts/intel/sys/synch32.h +++ b/usr/src/uts/intel/sys/synch32.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -19,8 +18,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -67,17 +67,12 @@ extern "C" { #define rwlock_readers readers #define rwlock_type type #define rwlock_magic magic -#define rwlock_mwaiters mutex.mutex_waiters -#define rwlock_mlockw mutex.mutex_lockw -#define rwlock_mowner mutex.mutex_owner -#define rwlock_mownerpid mutex.mutex_ownerpid #define rwlock_owner readercv.data #define rwlock_ownerpid writercv.data #define URW_HAS_WAITERS 0x80000000 -#define URW_WRITE_WANTED 0x40000000 -#define URW_WRITE_LOCKED 0x20000000 -#define URW_READERS_MASK 0x1fffffff +#define URW_WRITE_LOCKED 0x40000000 +#define URW_READERS_MASK 0x3fffffff #ifdef __cplusplus } diff --git a/usr/src/uts/sparc/sys/synch32.h b/usr/src/uts/sparc/sys/synch32.h index 1d45147bda..7fe623540f 100644 --- a/usr/src/uts/sparc/sys/synch32.h +++ b/usr/src/uts/sparc/sys/synch32.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -19,8 +18,9 @@ * * CDDL HEADER END */ + /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -67,17 +67,12 @@ extern "C" { #define rwlock_readers readers #define rwlock_type type #define rwlock_magic magic -#define rwlock_mwaiters mutex.mutex_waiters -#define rwlock_mlockw mutex.mutex_lockw -#define rwlock_mowner mutex.mutex_owner -#define rwlock_mownerpid mutex.mutex_ownerpid #define rwlock_owner readercv.data #define rwlock_ownerpid writercv.data #define URW_HAS_WAITERS 0x80000000 -#define URW_WRITE_WANTED 0x40000000 -#define URW_WRITE_LOCKED 0x20000000 -#define URW_READERS_MASK 0x1fffffff +#define URW_WRITE_LOCKED 0x40000000 +#define URW_READERS_MASK 0x3fffffff #ifdef __cplusplus } |