4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2016 by Delphix. All rights reserved.
28 #include "thr_uberdata.h"
34 #define READ_LOCK_TRY (READ_LOCK | TRY_FLAG)
35 #define WRITE_LOCK_TRY (WRITE_LOCK | TRY_FLAG)
37 #define NLOCKS 4 /* initial number of readlock_t structs allocated */
39 #define ASSERT_CONSISTENT_STATE(readers) \
40 ASSERT(!((readers) & URW_WRITE_LOCKED) || \
41 ((readers) & ~URW_HAS_WAITERS) == URW_WRITE_LOCKED)
44 * Find/allocate an entry for rwlp in our array of rwlocks held for reading.
45 * We must be deferring signals for this to be safe.
46 * Else if we are returning an entry with ul_rdlockcnt == 0,
47 * it could be reassigned behind our back in a signal handler.
50 rwl_entry(rwlock_t
*rwlp
)
52 ulwp_t
*self
= curthread
;
53 readlock_t
*remembered
= NULL
;
54 readlock_t
*readlockp
;
57 /* we must be deferring signals */
58 ASSERT((self
->ul_critical
+ self
->ul_sigdefer
) != 0);
60 if ((nlocks
= self
->ul_rdlockcnt
) != 0)
61 readlockp
= self
->ul_readlock
.array
;
64 readlockp
= &self
->ul_readlock
.single
;
67 for (; nlocks
; nlocks
--, readlockp
++) {
68 if (readlockp
->rd_rwlock
== rwlp
)
70 if (readlockp
->rd_count
== 0 && remembered
== NULL
)
71 remembered
= readlockp
;
73 if (remembered
!= NULL
) {
74 remembered
->rd_rwlock
= rwlp
;
79 * No entry available. Allocate more space, converting the single
80 * readlock_t entry into an array of readlock_t entries if necessary.
82 if ((nlocks
= self
->ul_rdlockcnt
) == 0) {
84 * Initial allocation of the readlock_t array.
85 * Convert the single entry into an array.
87 self
->ul_rdlockcnt
= nlocks
= NLOCKS
;
88 readlockp
= lmalloc(nlocks
* sizeof (readlock_t
));
90 * The single readlock_t becomes the first entry in the array.
92 *readlockp
= self
->ul_readlock
.single
;
93 self
->ul_readlock
.single
.rd_count
= 0;
94 self
->ul_readlock
.array
= readlockp
;
96 * Return the next available entry in the array.
98 (++readlockp
)->rd_rwlock
= rwlp
;
102 * Reallocate the array, double the size each time.
104 readlockp
= lmalloc(nlocks
* 2 * sizeof (readlock_t
));
105 (void) memcpy(readlockp
, self
->ul_readlock
.array
,
106 nlocks
* sizeof (readlock_t
));
107 lfree(self
->ul_readlock
.array
, nlocks
* sizeof (readlock_t
));
108 self
->ul_readlock
.array
= readlockp
;
109 self
->ul_rdlockcnt
*= 2;
111 * Return the next available entry in the newly allocated array.
113 (readlockp
+= nlocks
)->rd_rwlock
= rwlp
;
118 * Free the array of rwlocks held for reading.
121 rwl_free(ulwp_t
*ulwp
)
125 if ((nlocks
= ulwp
->ul_rdlockcnt
) != 0)
126 lfree(ulwp
->ul_readlock
.array
, nlocks
* sizeof (readlock_t
));
127 ulwp
->ul_rdlockcnt
= 0;
128 ulwp
->ul_readlock
.single
.rd_rwlock
= NULL
;
129 ulwp
->ul_readlock
.single
.rd_count
= 0;
133 * Check if a reader version of the lock is held by the current thread.
135 #pragma weak _rw_read_held = rw_read_held
137 rw_read_held(rwlock_t
*rwlp
)
139 volatile uint32_t *rwstate
= (volatile uint32_t *)&rwlp
->rwlock_readers
;
141 ulwp_t
*self
= curthread
;
142 readlock_t
*readlockp
;
149 ASSERT_CONSISTENT_STATE(readers
);
150 if (!(readers
& URW_WRITE_LOCKED
) &&
151 (readers
& URW_READERS_MASK
) != 0) {
153 * The lock is held for reading by some thread.
154 * Search our array of rwlocks held for reading for a match.
156 if ((nlocks
= self
->ul_rdlockcnt
) != 0)
157 readlockp
= self
->ul_readlock
.array
;
160 readlockp
= &self
->ul_readlock
.single
;
162 for (; nlocks
; nlocks
--, readlockp
++) {
163 if (readlockp
->rd_rwlock
== rwlp
) {
164 if (readlockp
->rd_count
)
176 * Check if a writer version of the lock is held by the current thread.
178 #pragma weak _rw_write_held = rw_write_held
180 rw_write_held(rwlock_t
*rwlp
)
182 volatile uint32_t *rwstate
= (volatile uint32_t *)&rwlp
->rwlock_readers
;
184 ulwp_t
*self
= curthread
;
190 ASSERT_CONSISTENT_STATE(readers
);
191 rval
= ((readers
& URW_WRITE_LOCKED
) &&
192 rwlp
->rwlock_owner
== (uintptr_t)self
&&
193 (rwlp
->rwlock_type
== USYNC_THREAD
||
194 rwlp
->rwlock_ownerpid
== self
->ul_uberdata
->pid
));
200 #pragma weak _rwlock_init = rwlock_init
203 rwlock_init(rwlock_t
*rwlp
, int type
, void *arg
)
205 ulwp_t
*self
= curthread
;
207 if (type
!= USYNC_THREAD
&& type
!= USYNC_PROCESS
)
210 * Once reinitialized, we can no longer be holding a read or write lock.
211 * We can do nothing about other threads that are holding read locks.
214 rwl_entry(rwlp
)->rd_count
= 0;
216 (void) memset(rwlp
, 0, sizeof (*rwlp
));
217 rwlp
->rwlock_type
= (uint16_t)type
;
218 rwlp
->rwlock_magic
= RWL_MAGIC
;
219 rwlp
->mutex
.mutex_type
= (uint8_t)type
;
220 rwlp
->mutex
.mutex_flag
= LOCK_INITED
;
221 rwlp
->mutex
.mutex_magic
= MUTEX_MAGIC
;
224 * This should be at the beginning of the function,
225 * but for the sake of old broken applications that
226 * do not have proper alignment for their rwlocks
227 * (and don't check the return code from rwlock_init),
228 * we put it here, after initializing the rwlock regardless.
230 if (((uintptr_t)rwlp
& (_LONG_LONG_ALIGNMENT
- 1)) &&
231 self
->ul_misaligned
== 0)
237 #pragma weak pthread_rwlock_destroy = rwlock_destroy
238 #pragma weak _rwlock_destroy = rwlock_destroy
240 rwlock_destroy(rwlock_t
*rwlp
)
242 ulwp_t
*self
= curthread
;
245 * Once destroyed, we can no longer be holding a read or write lock.
246 * We can do nothing about other threads that are holding read locks.
249 rwl_entry(rwlp
)->rd_count
= 0;
251 rwlp
->rwlock_magic
= 0;
252 tdb_sync_obj_deregister(rwlp
);
257 * The following four functions:
262 * lie at the heart of the fast-path code for rwlocks,
263 * both process-private and process-shared.
265 * They are called once without recourse to any other locking primitives.
266 * If they succeed, we are done and the fast-path code was successful.
267 * If they fail, we have to deal with lock queues, either to enqueue
268 * ourself and sleep or to dequeue and wake up someone else (slow paths).
270 * Unless 'ignore_waiters_flag' is true (a condition that applies only
271 * when read_lock_try() or write_lock_try() is called from code that
272 * is already in the slow path and has already acquired the queue lock),
273 * these functions will always fail if the waiters flag, URW_HAS_WAITERS,
274 * is set in the 'rwstate' word. Thus, setting the waiters flag on the
275 * rwlock and acquiring the queue lock guarantees exclusive access to
276 * the rwlock (and is the only way to guarantee exclusive access).
280 * Attempt to acquire a readers lock. Return true on success.
283 read_lock_try(rwlock_t
*rwlp
, int ignore_waiters_flag
)
285 volatile uint32_t *rwstate
= (volatile uint32_t *)&rwlp
->rwlock_readers
;
286 uint32_t mask
= ignore_waiters_flag
?
287 URW_WRITE_LOCKED
: (URW_HAS_WAITERS
| URW_WRITE_LOCKED
);
289 ulwp_t
*self
= curthread
;
292 while (((readers
= *rwstate
) & mask
) == 0) {
293 if (atomic_cas_32(rwstate
, readers
, readers
+ 1) == readers
) {
303 * Attempt to release a reader lock. Return true on success.
306 read_unlock_try(rwlock_t
*rwlp
)
308 volatile uint32_t *rwstate
= (volatile uint32_t *)&rwlp
->rwlock_readers
;
310 ulwp_t
*self
= curthread
;
313 while (((readers
= *rwstate
) & URW_HAS_WAITERS
) == 0) {
314 if (atomic_cas_32(rwstate
, readers
, readers
- 1) == readers
) {
324 * Attempt to acquire a writer lock. Return true on success.
327 write_lock_try(rwlock_t
*rwlp
, int ignore_waiters_flag
)
329 volatile uint32_t *rwstate
= (volatile uint32_t *)&rwlp
->rwlock_readers
;
330 uint32_t mask
= ignore_waiters_flag
?
331 (URW_WRITE_LOCKED
| URW_READERS_MASK
) :
332 (URW_HAS_WAITERS
| URW_WRITE_LOCKED
| URW_READERS_MASK
);
333 ulwp_t
*self
= curthread
;
337 while (((readers
= *rwstate
) & mask
) == 0) {
338 if (atomic_cas_32(rwstate
, readers
, readers
| URW_WRITE_LOCKED
)
349 * Attempt to release a writer lock. Return true on success.
352 write_unlock_try(rwlock_t
*rwlp
)
354 volatile uint32_t *rwstate
= (volatile uint32_t *)&rwlp
->rwlock_readers
;
356 ulwp_t
*self
= curthread
;
359 while (((readers
= *rwstate
) & URW_HAS_WAITERS
) == 0) {
360 if (atomic_cas_32(rwstate
, readers
, 0) == readers
) {
370 * Release a process-private rwlock and wake up any thread(s) sleeping on it.
371 * This is called when a thread releases a lock that appears to have waiters.
374 rw_queue_release(rwlock_t
*rwlp
)
376 volatile uint32_t *rwstate
= (volatile uint32_t *)&rwlp
->rwlock_readers
;
385 int maxlwps
= MAXLWPS
;
386 lwpid_t buffer
[MAXLWPS
];
387 lwpid_t
*lwpid
= buffer
;
389 qp
= queue_lock(rwlp
, MX
);
392 * Here is where we actually drop the lock,
393 * but we retain the URW_HAS_WAITERS flag, if it is already set.
396 ASSERT_CONSISTENT_STATE(readers
);
397 if (readers
& URW_WRITE_LOCKED
) /* drop the writer lock */
398 atomic_and_32(rwstate
, ~URW_WRITE_LOCKED
);
399 else /* drop the readers lock */
400 atomic_dec_32(rwstate
);
401 if (!(readers
& URW_HAS_WAITERS
)) { /* no waiters */
407 * The presence of the URW_HAS_WAITERS flag causes all rwlock
408 * code to go through the slow path, acquiring queue_lock(qp).
409 * Therefore, the rest of this code is safe because we are
410 * holding the queue lock and the URW_HAS_WAITERS flag is set.
413 readers
= *rwstate
; /* must fetch the value again */
414 ASSERT_CONSISTENT_STATE(readers
);
415 ASSERT(readers
& URW_HAS_WAITERS
);
416 readers
&= URW_READERS_MASK
; /* count of current readers */
417 writer
= 0; /* no current writer */
420 * Examine the queue of waiters in priority order and prepare
421 * to wake up as many readers as we encounter before encountering
422 * a writer. If the highest priority thread on the queue is a
423 * writer, stop there and wake it up.
425 * We keep track of lwpids that are to be unparked in lwpid[].
426 * __lwp_unpark_all() is called to unpark all of them after
427 * they have been removed from the sleep queue and the sleep
428 * queue lock has been dropped. If we run out of space in our
429 * on-stack buffer, we need to allocate more but we can't call
430 * lmalloc() because we are holding a queue lock when the overflow
431 * occurs and lmalloc() acquires a lock. We can't use alloca()
432 * either because the application may have allocated a small
433 * stack and we don't want to overrun the stack. So we call
434 * alloc_lwpids() to allocate a bigger buffer using the mmap()
435 * system call directly since that path acquires no locks.
437 while ((ulwpp
= queue_slot(qp
, &prev
, &more
)) != NULL
) {
439 ASSERT(ulwp
->ul_wchan
== rwlp
);
440 if (ulwp
->ul_writer
) {
441 if (writer
!= 0 || readers
!= 0)
443 /* one writer to wake */
448 /* at least one reader to wake */
450 if (nlwpid
== maxlwps
)
451 lwpid
= alloc_lwpids(lwpid
, &nlwpid
, &maxlwps
);
453 queue_unlink(qp
, ulwpp
, prev
);
454 ulwp
->ul_sleepq
= NULL
;
455 ulwp
->ul_wchan
= NULL
;
458 * Hand off the lock to the writer we will be waking.
460 ASSERT((*rwstate
& ~URW_HAS_WAITERS
) == 0);
461 atomic_or_32(rwstate
, URW_WRITE_LOCKED
);
462 rwlp
->rwlock_owner
= (uintptr_t)ulwp
;
464 lwpid
[nlwpid
++] = ulwp
->ul_lwpid
;
468 * This modification of rwstate must be done last.
469 * The presence of the URW_HAS_WAITERS flag causes all rwlock
470 * code to go through the slow path, acquiring queue_lock(qp).
471 * Otherwise the read_lock_try() and write_lock_try() fast paths
475 atomic_and_32(rwstate
, ~URW_HAS_WAITERS
);
480 ulwp_t
*self
= curthread
;
484 (void) __lwp_unpark(lwpid
[0]);
486 (void) __lwp_unpark_all(lwpid
, nlwpid
);
490 (void) munmap((caddr_t
)lwpid
, maxlwps
* sizeof (lwpid_t
));
494 * Common code for rdlock, timedrdlock, wrlock, timedwrlock, tryrdlock,
495 * and trywrlock for process-shared (USYNC_PROCESS) rwlocks.
497 * Note: if the lock appears to be contended we call __lwp_rwlock_rdlock()
498 * or __lwp_rwlock_wrlock() holding the mutex. These return with the mutex
499 * released, and if they need to sleep will release the mutex first. In the
500 * event of a spurious wakeup, these will return EAGAIN (because it is much
501 * easier for us to re-acquire the mutex here).
504 shared_rwlock_lock(rwlock_t
*rwlp
, timespec_t
*tsp
, int rd_wr
)
506 volatile uint32_t *rwstate
= (volatile uint32_t *)&rwlp
->rwlock_readers
;
507 mutex_t
*mp
= &rwlp
->mutex
;
512 try_flag
= (rd_wr
& TRY_FLAG
);
514 ASSERT(rd_wr
== READ_LOCK
|| rd_wr
== WRITE_LOCK
);
517 DTRACE_PROBE2(plockstat
, rw__block
, rwlp
, rd_wr
);
521 if (try_flag
&& (*rwstate
& URW_WRITE_LOCKED
)) {
525 if ((error
= mutex_lock(mp
)) != 0)
527 if (rd_wr
== READ_LOCK
) {
528 if (read_lock_try(rwlp
, 0)) {
529 (void) mutex_unlock(mp
);
533 if (write_lock_try(rwlp
, 0)) {
534 (void) mutex_unlock(mp
);
538 atomic_or_32(rwstate
, URW_HAS_WAITERS
);
540 ASSERT_CONSISTENT_STATE(readers
);
542 * The calls to __lwp_rwlock_*() below will release the mutex,
543 * so we need a dtrace probe here. The owner field of the
544 * mutex is cleared in the kernel when the mutex is released,
545 * so we should not clear it here.
547 DTRACE_PROBE2(plockstat
, mutex__release
, mp
, 0);
549 * The waiters bit may be inaccurate.
550 * Only the kernel knows for sure.
552 if (rd_wr
== READ_LOCK
) {
554 error
= __lwp_rwlock_tryrdlock(rwlp
);
556 error
= __lwp_rwlock_rdlock(rwlp
, tsp
);
559 error
= __lwp_rwlock_trywrlock(rwlp
);
561 error
= __lwp_rwlock_wrlock(rwlp
, tsp
);
563 } while (error
== EAGAIN
|| error
== EINTR
);
566 DTRACE_PROBE3(plockstat
, rw__blocked
, rwlp
, rd_wr
, error
== 0);
573 * Common code for rdlock, timedrdlock, wrlock, timedwrlock, tryrdlock,
574 * and trywrlock for process-private (USYNC_THREAD) rwlocks.
577 rwlock_lock(rwlock_t
*rwlp
, timespec_t
*tsp
, int rd_wr
)
579 volatile uint32_t *rwstate
= (volatile uint32_t *)&rwlp
->rwlock_readers
;
581 ulwp_t
*self
= curthread
;
585 int ignore_waiters_flag
;
588 try_flag
= (rd_wr
& TRY_FLAG
);
590 ASSERT(rd_wr
== READ_LOCK
|| rd_wr
== WRITE_LOCK
);
593 DTRACE_PROBE2(plockstat
, rw__block
, rwlp
, rd_wr
);
596 qp
= queue_lock(rwlp
, MX
);
597 /* initial attempt to acquire the lock fails if there are waiters */
598 ignore_waiters_flag
= 0;
600 if (rd_wr
== READ_LOCK
) {
601 if (read_lock_try(rwlp
, ignore_waiters_flag
))
604 if (write_lock_try(rwlp
, ignore_waiters_flag
))
607 /* subsequent attempts do not fail due to waiters */
608 ignore_waiters_flag
= 1;
609 atomic_or_32(rwstate
, URW_HAS_WAITERS
);
611 ASSERT_CONSISTENT_STATE(readers
);
612 if ((readers
& URW_WRITE_LOCKED
) ||
613 (rd_wr
== WRITE_LOCK
&&
614 (readers
& URW_READERS_MASK
) != 0))
615 /* EMPTY */; /* somebody holds the lock */
616 else if ((ulwp
= queue_waiter(qp
)) == NULL
) {
617 atomic_and_32(rwstate
, ~URW_HAS_WAITERS
);
618 ignore_waiters_flag
= 0;
619 continue; /* no queued waiters, start over */
622 * Do a priority check on the queued waiter (the
623 * highest priority thread on the queue) to see
624 * if we should defer to it or just grab the lock.
626 int our_pri
= real_priority(self
);
627 int his_pri
= real_priority(ulwp
);
629 if (rd_wr
== WRITE_LOCK
) {
631 * We defer to a queued thread that has
632 * a higher priority than ours.
634 if (his_pri
<= our_pri
) {
636 * Don't defer, just grab the lock.
642 * We defer to a queued thread that has
643 * a higher priority than ours or that
644 * is a writer whose priority equals ours.
646 if (his_pri
< our_pri
||
647 (his_pri
== our_pri
&& !ulwp
->ul_writer
)) {
649 * Don't defer, just grab the lock.
656 * We are about to block.
657 * If we're doing a trylock, return EBUSY instead.
664 * Enqueue writers ahead of readers.
666 self
->ul_writer
= rd_wr
; /* *must* be 0 or 1 */
667 enqueue(qp
, self
, 0);
668 set_parking_flag(self
, 1);
670 if ((error
= __lwp_park(tsp
, 0)) == EINTR
)
672 set_parking_flag(self
, 0);
673 qp
= queue_lock(rwlp
, MX
);
674 if (self
->ul_sleepq
&& dequeue_self(qp
) == 0) {
675 atomic_and_32(rwstate
, ~URW_HAS_WAITERS
);
676 ignore_waiters_flag
= 0;
679 if (rd_wr
== WRITE_LOCK
&&
680 (*rwstate
& URW_WRITE_LOCKED
) &&
681 rwlp
->rwlock_owner
== (uintptr_t)self
) {
683 * We acquired the lock by hand-off
684 * from the previous owner,
686 error
= 0; /* timedlock did not fail */
692 * Make one final check to see if there are any threads left
693 * on the rwlock queue. Clear the URW_HAS_WAITERS flag if not.
695 if (qp
->qh_root
== NULL
|| qp
->qh_root
->qr_head
== NULL
)
696 atomic_and_32(rwstate
, ~URW_HAS_WAITERS
);
701 DTRACE_PROBE3(plockstat
, rw__blocked
, rwlp
, rd_wr
, error
== 0);
708 rw_rdlock_impl(rwlock_t
*rwlp
, timespec_t
*tsp
)
710 ulwp_t
*self
= curthread
;
711 uberdata_t
*udp
= self
->ul_uberdata
;
712 readlock_t
*readlockp
;
713 tdb_rwlock_stats_t
*rwsp
= RWLOCK_STATS(rwlp
, udp
);
717 * If we already hold a readers lock on this rwlock,
718 * just increment our reference count and return.
721 readlockp
= rwl_entry(rwlp
);
722 if (readlockp
->rd_count
!= 0) {
723 if (readlockp
->rd_count
== READ_LOCK_MAX
) {
735 * If we hold the writer lock, bail out.
737 if (rw_write_held(rwlp
)) {
738 if (self
->ul_error_detection
)
739 rwlock_error(rwlp
, "rwlock_rdlock",
740 "calling thread owns the writer lock");
745 if (read_lock_try(rwlp
, 0))
747 else if (rwlp
->rwlock_type
== USYNC_PROCESS
) /* kernel-level */
748 error
= shared_rwlock_lock(rwlp
, tsp
, READ_LOCK
);
749 else /* user-level */
750 error
= rwlock_lock(rwlp
, tsp
, READ_LOCK
);
755 rwl_entry(rwlp
)->rd_count
++;
758 tdb_incr(rwsp
->rw_rdlock
);
759 DTRACE_PROBE2(plockstat
, rw__acquire
, rwlp
, READ_LOCK
);
761 DTRACE_PROBE3(plockstat
, rw__error
, rwlp
, READ_LOCK
, error
);
767 #pragma weak pthread_rwlock_rdlock = rw_rdlock
768 #pragma weak _rw_rdlock = rw_rdlock
770 rw_rdlock(rwlock_t
*rwlp
)
772 ASSERT(!curthread
->ul_critical
|| curthread
->ul_bindflags
);
773 return (rw_rdlock_impl(rwlp
, NULL
));
777 lrw_rdlock(rwlock_t
*rwlp
)
779 enter_critical(curthread
);
780 (void) rw_rdlock_impl(rwlp
, NULL
);
784 pthread_rwlock_reltimedrdlock_np(pthread_rwlock_t
*_RESTRICT_KYWD rwlp
,
785 const struct timespec
*_RESTRICT_KYWD reltime
)
787 timespec_t tslocal
= *reltime
;
790 ASSERT(!curthread
->ul_critical
|| curthread
->ul_bindflags
);
791 error
= rw_rdlock_impl((rwlock_t
*)rwlp
, &tslocal
);
798 pthread_rwlock_timedrdlock(pthread_rwlock_t
*_RESTRICT_KYWD rwlp
,
799 const struct timespec
*_RESTRICT_KYWD abstime
)
804 ASSERT(!curthread
->ul_critical
|| curthread
->ul_bindflags
);
805 abstime_to_reltime(CLOCK_REALTIME
, abstime
, &tslocal
);
806 error
= rw_rdlock_impl((rwlock_t
*)rwlp
, &tslocal
);
813 rw_wrlock_impl(rwlock_t
*rwlp
, timespec_t
*tsp
)
815 ulwp_t
*self
= curthread
;
816 uberdata_t
*udp
= self
->ul_uberdata
;
817 tdb_rwlock_stats_t
*rwsp
= RWLOCK_STATS(rwlp
, udp
);
821 * If we hold a readers lock on this rwlock, bail out.
823 if (rw_read_held(rwlp
)) {
824 if (self
->ul_error_detection
)
825 rwlock_error(rwlp
, "rwlock_wrlock",
826 "calling thread owns the readers lock");
832 * If we hold the writer lock, bail out.
834 if (rw_write_held(rwlp
)) {
835 if (self
->ul_error_detection
)
836 rwlock_error(rwlp
, "rwlock_wrlock",
837 "calling thread owns the writer lock");
842 if (write_lock_try(rwlp
, 0))
844 else if (rwlp
->rwlock_type
== USYNC_PROCESS
) /* kernel-level */
845 error
= shared_rwlock_lock(rwlp
, tsp
, WRITE_LOCK
);
846 else /* user-level */
847 error
= rwlock_lock(rwlp
, tsp
, WRITE_LOCK
);
851 rwlp
->rwlock_owner
= (uintptr_t)self
;
852 if (rwlp
->rwlock_type
== USYNC_PROCESS
)
853 rwlp
->rwlock_ownerpid
= udp
->pid
;
855 tdb_incr(rwsp
->rw_wrlock
);
856 rwsp
->rw_wrlock_begin_hold
= gethrtime();
858 DTRACE_PROBE2(plockstat
, rw__acquire
, rwlp
, WRITE_LOCK
);
860 DTRACE_PROBE3(plockstat
, rw__error
, rwlp
, WRITE_LOCK
, error
);
865 #pragma weak pthread_rwlock_wrlock = rw_wrlock
866 #pragma weak _rw_wrlock = rw_wrlock
868 rw_wrlock(rwlock_t
*rwlp
)
870 ASSERT(!curthread
->ul_critical
|| curthread
->ul_bindflags
);
871 return (rw_wrlock_impl(rwlp
, NULL
));
875 lrw_wrlock(rwlock_t
*rwlp
)
877 enter_critical(curthread
);
878 (void) rw_wrlock_impl(rwlp
, NULL
);
882 pthread_rwlock_reltimedwrlock_np(pthread_rwlock_t
*_RESTRICT_KYWD rwlp
,
883 const struct timespec
*_RESTRICT_KYWD reltime
)
885 timespec_t tslocal
= *reltime
;
888 ASSERT(!curthread
->ul_critical
|| curthread
->ul_bindflags
);
889 error
= rw_wrlock_impl((rwlock_t
*)rwlp
, &tslocal
);
896 pthread_rwlock_timedwrlock(pthread_rwlock_t
*rwlp
, const timespec_t
*abstime
)
901 ASSERT(!curthread
->ul_critical
|| curthread
->ul_bindflags
);
902 abstime_to_reltime(CLOCK_REALTIME
, abstime
, &tslocal
);
903 error
= rw_wrlock_impl((rwlock_t
*)rwlp
, &tslocal
);
909 #pragma weak pthread_rwlock_tryrdlock = rw_tryrdlock
911 rw_tryrdlock(rwlock_t
*rwlp
)
913 ulwp_t
*self
= curthread
;
914 uberdata_t
*udp
= self
->ul_uberdata
;
915 tdb_rwlock_stats_t
*rwsp
= RWLOCK_STATS(rwlp
, udp
);
916 readlock_t
*readlockp
;
919 ASSERT(!curthread
->ul_critical
|| curthread
->ul_bindflags
);
922 tdb_incr(rwsp
->rw_rdlock_try
);
925 * If we already hold a readers lock on this rwlock,
926 * just increment our reference count and return.
929 readlockp
= rwl_entry(rwlp
);
930 if (readlockp
->rd_count
!= 0) {
931 if (readlockp
->rd_count
== READ_LOCK_MAX
) {
942 if (read_lock_try(rwlp
, 0))
944 else if (rwlp
->rwlock_type
== USYNC_PROCESS
) /* kernel-level */
945 error
= shared_rwlock_lock(rwlp
, NULL
, READ_LOCK_TRY
);
946 else /* user-level */
947 error
= rwlock_lock(rwlp
, NULL
, READ_LOCK_TRY
);
952 rwl_entry(rwlp
)->rd_count
++;
954 DTRACE_PROBE2(plockstat
, rw__acquire
, rwlp
, READ_LOCK
);
957 tdb_incr(rwsp
->rw_rdlock_try_fail
);
958 if (error
!= EBUSY
) {
959 DTRACE_PROBE3(plockstat
, rw__error
, rwlp
, READ_LOCK
,
967 #pragma weak pthread_rwlock_trywrlock = rw_trywrlock
969 rw_trywrlock(rwlock_t
*rwlp
)
971 ulwp_t
*self
= curthread
;
972 uberdata_t
*udp
= self
->ul_uberdata
;
973 tdb_rwlock_stats_t
*rwsp
= RWLOCK_STATS(rwlp
, udp
);
976 ASSERT(!self
->ul_critical
|| self
->ul_bindflags
);
979 tdb_incr(rwsp
->rw_wrlock_try
);
981 if (write_lock_try(rwlp
, 0))
983 else if (rwlp
->rwlock_type
== USYNC_PROCESS
) /* kernel-level */
984 error
= shared_rwlock_lock(rwlp
, NULL
, WRITE_LOCK_TRY
);
985 else /* user-level */
986 error
= rwlock_lock(rwlp
, NULL
, WRITE_LOCK_TRY
);
989 rwlp
->rwlock_owner
= (uintptr_t)self
;
990 if (rwlp
->rwlock_type
== USYNC_PROCESS
)
991 rwlp
->rwlock_ownerpid
= udp
->pid
;
993 rwsp
->rw_wrlock_begin_hold
= gethrtime();
994 DTRACE_PROBE2(plockstat
, rw__acquire
, rwlp
, WRITE_LOCK
);
997 tdb_incr(rwsp
->rw_wrlock_try_fail
);
998 if (error
!= EBUSY
) {
999 DTRACE_PROBE3(plockstat
, rw__error
, rwlp
, WRITE_LOCK
,
1006 #pragma weak pthread_rwlock_unlock = rw_unlock
1007 #pragma weak _rw_unlock = rw_unlock
1009 rw_unlock(rwlock_t
*rwlp
)
1011 volatile uint32_t *rwstate
= (volatile uint32_t *)&rwlp
->rwlock_readers
;
1013 ulwp_t
*self
= curthread
;
1014 uberdata_t
*udp
= self
->ul_uberdata
;
1015 tdb_rwlock_stats_t
*rwsp
;
1019 ASSERT_CONSISTENT_STATE(readers
);
1020 if (readers
& URW_WRITE_LOCKED
) {
1025 readers
&= URW_READERS_MASK
;
1028 if (rd_wr
== WRITE_LOCK
) {
1030 * Since the writer lock is held, we'd better be
1031 * holding it, else we cannot legitimately be here.
1033 if (!rw_write_held(rwlp
)) {
1034 if (self
->ul_error_detection
)
1035 rwlock_error(rwlp
, "rwlock_unlock",
1036 "writer lock held, "
1037 "but not by the calling thread");
1040 if ((rwsp
= RWLOCK_STATS(rwlp
, udp
)) != NULL
) {
1041 if (rwsp
->rw_wrlock_begin_hold
)
1042 rwsp
->rw_wrlock_hold_time
+=
1043 gethrtime() - rwsp
->rw_wrlock_begin_hold
;
1044 rwsp
->rw_wrlock_begin_hold
= 0;
1046 rwlp
->rwlock_owner
= 0;
1047 rwlp
->rwlock_ownerpid
= 0;
1048 } else if (readers
> 0) {
1050 * A readers lock is held; if we don't hold one, bail out.
1052 readlock_t
*readlockp
;
1055 readlockp
= rwl_entry(rwlp
);
1056 if (readlockp
->rd_count
== 0) {
1058 if (self
->ul_error_detection
)
1059 rwlock_error(rwlp
, "rwlock_unlock",
1060 "readers lock held, "
1061 "but not by the calling thread");
1065 * If we hold more than one readers lock on this rwlock,
1066 * just decrement our reference count and return.
1068 if (--readlockp
->rd_count
!= 0) {
1075 * This is a usage error.
1076 * No thread should release an unowned lock.
1078 if (self
->ul_error_detection
)
1079 rwlock_error(rwlp
, "rwlock_unlock", "lock not owned");
1083 if (rd_wr
== WRITE_LOCK
&& write_unlock_try(rwlp
)) {
1085 } else if (rd_wr
== READ_LOCK
&& read_unlock_try(rwlp
)) {
1087 } else if (rwlp
->rwlock_type
== USYNC_PROCESS
) {
1088 (void) mutex_lock(&rwlp
->mutex
);
1089 (void) __lwp_rwlock_unlock(rwlp
);
1090 (void) mutex_unlock(&rwlp
->mutex
);
1092 rw_queue_release(rwlp
);
1096 DTRACE_PROBE2(plockstat
, rw__release
, rwlp
, rd_wr
);
1101 lrw_unlock(rwlock_t
*rwlp
)
1103 (void) rw_unlock(rwlp
);
1104 exit_critical(curthread
);