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 */
29int	rwlock_init(lwp_rwlock_t *, int, void *);
30int	rwlock_destroy(lwp_rwlock_t *);
31int	rw_rdlock(lwp_rwlock_t *);
32int	rw_wrlock(lwp_rwlock_t *);
33int	rw_unlock(lwp_rwlock_t *);
34int	rw_tryrdlock(lwp_rwlock_t *);
35int	rw_trywrlock(lwp_rwlock_t *);
36int	_rw_read_held(void *);
37int	_rw_write_held(void *);
38
39/*ARGSUSED*/
40void
41rw_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
47void
48rw_destroy(krwlock_t *rwlp)
49{
50	(void) rwlock_destroy(&rwlp->rw_lock);
51	rwlp->rw_owner = _KTHREAD_INVALID;
52}
53
54void
55rw_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
68void
69rw_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
80int
81rw_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*/
96int
97rw_tryupgrade(krwlock_t *rwlp)
98{
99
100	return (0);
101}
102
103void
104rw_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
112int
113rw_read_held(krwlock_t *rwlp)
114{
115	return (_rw_read_held(rwlp));
116}
117
118int
119rw_write_held(krwlock_t *rwlp)
120{
121	return (_rw_write_held(rwlp));
122}
123
124int
125rw_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 */
133void *
134rw_owner(krwlock_t *rwlp)
135{
136	return (rwlp->rw_owner);
137}
138