1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 /*
  13  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
  14  */
  15 
  16 /*
  17  * rwlock(9f)
  18  */
  19 
  20 /* This is the API we're emulating */
  21 #include <sys/rwlock.h>
  22 
  23 #include <sys/errno.h>
  24 #include <sys/debug.h>
  25 #include <sys/param.h>
  26 #include <sys/thread.h>
  27 
  28 /* avoiding synch.h */
  29 int     rwlock_init(lwp_rwlock_t *, int, void *);
  30 int     rwlock_destroy(lwp_rwlock_t *);
  31 int     rw_rdlock(lwp_rwlock_t *);
  32 int     rw_wrlock(lwp_rwlock_t *);
  33 int     rw_unlock(lwp_rwlock_t *);
  34 int     rw_tryrdlock(lwp_rwlock_t *);
  35 int     rw_trywrlock(lwp_rwlock_t *);
  36 int     _rw_read_held(void *);
  37 int     _rw_write_held(void *);
  38 
  39 /*ARGSUSED*/
  40 void
  41 rw_init(krwlock_t *rwlp, char *name, krw_type_t type, void *arg)
  42 {
  43         (void) rwlock_init(&rwlp->rw_lock, USYNC_THREAD, NULL);
  44         rwlp->rw_owner = _KTHREAD_INVALID;
  45 }
  46 
  47 void
  48 rw_destroy(krwlock_t *rwlp)
  49 {
  50         (void) rwlock_destroy(&rwlp->rw_lock);
  51         rwlp->rw_owner = _KTHREAD_INVALID;
  52 }
  53 
  54 void
  55 rw_enter(krwlock_t *rwlp, krw_t rw)
  56 {
  57         int rc;
  58 
  59         if (rw == RW_READER) {
  60                 rc = rw_rdlock(&rwlp->rw_lock);
  61         } else {
  62                 rc = rw_wrlock(&rwlp->rw_lock);
  63                 rwlp->rw_owner = _curthread();
  64         }
  65         VERIFY(rc == 0);
  66 }
  67 
  68 void
  69 rw_exit(krwlock_t *rwlp)
  70 {
  71         if (_rw_write_held(&rwlp->rw_lock)) {
  72                 ASSERT(rwlp->rw_owner == _curthread());
  73                 rwlp->rw_owner = _KTHREAD_INVALID;
  74         } else {
  75                 ASSERT(_rw_read_held(&rwlp->rw_lock));
  76         }
  77         (void) rw_unlock(&rwlp->rw_lock);
  78 }
  79 
  80 int
  81 rw_tryenter(krwlock_t *rwlp, krw_t rw)
  82 {
  83         int rv;
  84 
  85         if (rw == RW_WRITER) {
  86                 rv = rw_trywrlock(&rwlp->rw_lock);
  87                 if (rv == 0)
  88                         rwlp->rw_owner = _curthread();
  89         } else
  90                 rv = rw_tryrdlock(&rwlp->rw_lock);
  91 
  92         return ((rv == 0) ? 1 : 0);
  93 }
  94 
  95 /*ARGSUSED*/
  96 int
  97 rw_tryupgrade(krwlock_t *rwlp)
  98 {
  99 
 100         return (0);
 101 }
 102 
 103 void
 104 rw_downgrade(krwlock_t *rwlp)
 105 {
 106         ASSERT(rwlp->rw_owner == _curthread());
 107         rwlp->rw_owner = _KTHREAD_INVALID;
 108         VERIFY(rw_unlock(&rwlp->rw_lock) == 0);
 109         VERIFY(rw_rdlock(&rwlp->rw_lock) == 0);
 110 }
 111 
 112 int
 113 rw_read_held(krwlock_t *rwlp)
 114 {
 115         return (_rw_read_held(rwlp));
 116 }
 117 
 118 int
 119 rw_write_held(krwlock_t *rwlp)
 120 {
 121         return (_rw_write_held(rwlp));
 122 }
 123 
 124 int
 125 rw_lock_held(krwlock_t *rwlp)
 126 {
 127         return (rw_read_held(rwlp) || rw_write_held(rwlp));
 128 }
 129 
 130 /*
 131  * Return the kthread_t * of the lock owner
 132  */
 133 void *
 134 rw_owner(krwlock_t *rwlp)
 135 {
 136         return (rwlp->rw_owner);
 137 }