1/*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#ifndef _SYS_MUTEX_IMPL_H
27#define	_SYS_MUTEX_IMPL_H
28
29#pragma ident	"%Z%%M%	%I%	%E% SMI"
30
31#ifndef	_ASM
32#include <sys/types.h>
33#include <sys/machlock.h>
34#endif
35
36#ifdef	__cplusplus
37extern "C" {
38#endif
39
40#define	MUTEX_THREAD	(-0x8)
41#ifndef	_ASM
42
43/*
44 * mutex_enter() assumes that the mutex is adaptive and tries to grab the
45 * lock by doing a cas on the first word of the mutex.  If the cas fails,
46 * it means that either (1) the lock is a spin lock, or (2) the lock is
47 * adaptive but already held.  mutex_vector_enter() distinguishes these
48 * cases by looking at the mutex type, which is encoded in the low-order
49 * bits of the owner field.
50 */
51typedef union mutex_impl {
52	/*
53	 * Adaptive mutex.
54	 */
55	struct adaptive_mutex {
56		uintptr_t _m_owner;	/* 0-3/0-7 owner and waiters bit */
57	} m_adaptive;
58
59	/*
60	 * Spin Mutex.
61	 */
62	struct spin_mutex {
63		ushort_t m_oldspl;	/* 0-1	old %pil value */
64		ushort_t m_minspl;	/* 2-3	min %pil val if lock held */
65		ushort_t m_filler;	/* 4-5	unused */
66		lock_t	m_spinlock;	/* 6	real lock */
67		lock_t	m_dummylock;	/* 7	dummy lock (always set) */
68	} m_spin;
69
70} mutex_impl_t;
71
72#define	m_owner	m_adaptive._m_owner
73
74#define	MUTEX_WAITERS		0x1
75#define	MUTEX_DEAD		0x6
76#define	MUTEX_THREAD		(-0x8)
77
78#define	MUTEX_OWNER(lp)		((kthread_id_t)((lp)->m_owner & MUTEX_THREAD))
79#define	MUTEX_NO_OWNER		((kthread_id_t)NULL)
80
81#define	MUTEX_SET_WAITERS(lp)						\
82{									\
83	uintptr_t old;							\
84	while ((old = (lp)->m_owner) != 0 &&				\
85	    casip(&(lp)->m_owner, old, old | MUTEX_WAITERS) != old)	\
86		continue;						\
87}
88
89#define	MUTEX_HAS_WAITERS(lp)			((lp)->m_owner & MUTEX_WAITERS)
90#define	MUTEX_CLEAR_LOCK_AND_WAITERS(lp)	(lp)->m_owner = 0
91
92#define	MUTEX_SET_TYPE(lp, type)
93#define	MUTEX_TYPE_ADAPTIVE(lp)	(((lp)->m_owner & MUTEX_DEAD) == 0)
94#define	MUTEX_TYPE_SPIN(lp)	((lp)->m_spin.m_dummylock == LOCK_HELD_VALUE)
95
96#define	MUTEX_DESTROY(lp)	\
97	(lp)->m_owner = ((uintptr_t)curthread | MUTEX_DEAD)
98
99#define	MUTEX_BACKOFF_BASE	1
100#define	MUTEX_BACKOFF_SHIFT	1
101#define	MUTEX_CAP_FACTOR	8
102#define	MUTEX_DELAY()	{ \
103				mutex_delay(); \
104			}
105
106/* low-overhead clock read */
107extern u_longlong_t gettick(void);
108#define	MUTEX_GETTICK()	gettick()
109extern void null_xcall(void);
110#define	MUTEX_SYNC()	xc_all((xcfunc_t *)null_xcall, 0, 0)
111
112extern void cas_delay(void *);
113extern void rdccr_delay(void);
114extern int mutex_adaptive_tryenter(mutex_impl_t *);
115extern void *mutex_owner_running(mutex_impl_t *);
116
117#endif	/* _ASM */
118
119#ifdef	__cplusplus
120}
121#endif
122
123#endif	/* _SYS_MUTEX_IMPL_H */
124