xref: /original-bsd/sys/sys/lock.h (revision 00695d63)
1 /*
2  * Copyright (c) 1995
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code contains ideas from software contributed to Berkeley by
6  * Avadis Tevanian, Jr., Michael Wayne Young, and the Mach Operating
7  * System project at Carnegie-Mellon University.
8  *
9  * %sccs.include.redist.c%
10  *
11  *	@(#)lock.h	8.7 (Berkeley) 04/27/95
12  */
13 
14 #ifndef	_LOCK_H_
15 #define	_LOCK_H_
16 
17 /*
18  * XXX This belongs in <machine/param.h>, but is here for now.
19  */
20 #define NCPUS 1
21 
22 /*
23  * A simple spin lock.
24  *
25  * This structure only sets one bit of data, but is sized based on the
26  * minimum word size that can be operated on by the hardware test-and-set
27  * instruction. It is only needed for multiprocessors, as uniprocessors
28  * will always run to completion or a sleep. It is an error to hold one
29  * of these locks while a process is sleeping.
30  */
31 struct simple_lock {
32 	int	lock_data;
33 };
34 
35 /*
36  * XXX end of stuff that belongs in <machine/param.h>
37  */
38 
39 /*
40  * The general lock structure.  Provides for multiple shared locks,
41  * upgrading from shared to exclusive, and sleeping until the lock
42  * can be gained.
43  */
44 struct lock {
45 	struct	simple_lock lk_interlock; /* lock on remaining fields */
46 	u_int	lk_flags;		/* see below */
47 	int	lk_sharecount;		/* # of accepted shared locks */
48 	int	lk_exclusivecount;	/* # of recursive exclusive locks */
49 	int	lk_waitcount;		/* # of processes sleeping for lock */
50 	int	lk_prio;		/* priority at which to sleep */
51 	char	*lk_wmesg;		/* resource sleeping (for tsleep) */
52 	int	lk_timo;		/* maximum sleep time (for tsleep) */
53 	pid_t	lk_lockholder;		/* pid of exclusive lock holder */
54 };
55 /*
56  * Lock request types:
57  *   LK_SHARED - get one of many possible shared locks. If a process
58  *	holding an exclusive lock requests a shared lock, the exclusive
59  *	lock(s) will be downgraded to shared locks.
60  *   LK_EXCLUSIVE - stop further shared locks, when they are cleared,
61  *	grant a pending upgrade if it exists, then grant an exclusive
62  *	lock. Only one exclusive lock may exist at a time, except that
63  *	a process holding an exclusive lock may get additional exclusive
64  *	locks if it explicitly sets the LK_CANRECURSE flag in the lock
65  *	request, or if the LK_CANRECUSE flag was set when the lock was
66  *	initialized.
67  *   LK_UPGRADE - the process must hold a shared lock that it wants to
68  *	have upgraded to an exclusive lock. Other processes may get
69  *	exclusive access to the resource between the time that the upgrade
70  *	is requested and the time that it is granted.
71  *   LK_EXCLUPGRADE - the process must hold a shared lock that it wants to
72  *	have upgraded to an exclusive lock. If the request succeeds, no
73  *	other processes will have gotten exclusive access to the resource
74  *	between the time that the upgrade is requested and the time that
75  *	it is granted. However, if another process has already requested
76  *	an upgrade, the request will fail (see error returns below).
77  *   LK_DOWNGRADE - the process must hold an exclusive lock that it wants
78  *	to have downgraded to a shared lock. If the process holds multiple
79  *	(recursive) exclusive locks, they will all be downgraded to shared
80  *	locks.
81  *   LK_RELEASE - release one instance of a lock.
82  *   LK_DRAIN - wait for all activity on the lock to end, then mark it
83  *	decommissioned. This feature is used before freeing a lock that
84  *	is part of a piece of memory that is about to be freed.
85  *
86  * These are flags that are passed to the lockmgr routine.
87  */
88 #define LK_TYPE_MASK	0x00000007	/* type of lock sought */
89 #define LK_SHARED	0x00000001	/* shared lock */
90 #define LK_EXCLUSIVE	0x00000002	/* exclusive lock */
91 #define LK_UPGRADE	0x00000003	/* shared-to-exclusive upgrade */
92 #define LK_EXCLUPGRADE	0x00000004	/* first shared-to-exclusive upgrade */
93 #define LK_DOWNGRADE	0x00000005	/* exclusive-to-shared downgrade */
94 #define LK_RELEASE	0x00000006	/* release any type of lock */
95 #define LK_DRAIN	0x00000007	/* wait for all lock activity to end */
96 /*
97  * External lock flags.
98  *
99  * These flags may be set in lock_init to set their mode permanently,
100  * or passed in as arguments to the lock manager.
101  */
102 #define LK_EXTFLG_MASK	0x000000f0	/* mask of external flags */
103 #define LK_NOWAIT	0x00000010	/* do not sleep to await lock */
104 #define LK_SLEEPFAIL	0x00000020	/* sleep, then return failure */
105 #define LK_CANRECURSE	0x00000040	/* allow recursive exclusive lock */
106 /*
107  * Internal lock flags.
108  *
109  * These flags are used internally to the lock manager.
110  */
111 #define LK_WANT_UPGRADE	0x00000100	/* waiting for share-to-excl upgrade */
112 #define LK_WANT_EXCL	0x00000200	/* exclusive lock sought */
113 #define LK_HAVE_EXCL	0x00000400	/* exclusive lock obtained */
114 #define LK_WAITDRAIN	0x00000800	/* process waiting for lock to drain */
115 #define LK_DRAINED	0x00001000	/* lock has been decommissioned */
116 /*
117  * Control flags
118  *
119  * Non-persistent external flags.
120  */
121 #define LK_INTERLOCK	0x00010000	/* unlock passed simple lock after
122 					   getting lk_interlock */
123 #define LK_RETRY	0x00020000	/* vn_lock: retry until locked */
124 
125 /*
126  * Lock return status.
127  *
128  * Successfully obtained locks return 0. Locks will always succeed
129  * unless one of the following is true:
130  *	LK_FORCEUPGRADE is requested and some other process has already
131  *	    requested a lock upgrade (returns EBUSY).
132  *	LK_WAIT is set and a sleep would be required (returns EBUSY).
133  *	LK_SLEEPFAIL is set and a sleep was done (returns ENOLCK).
134  *	PCATCH is set in lock priority and a signal arrives (returns
135  *	    either EINTR or ERESTART if system calls is to be restarted).
136  *	Non-null lock timeout and timeout expires (returns EWOULDBLOCK).
137  * A failed lock attempt always returns a non-zero error value. No lock
138  * is held after an error return (in particular, a failed LK_UPGRADE
139  * or LK_FORCEUPGRADE will have released its shared access lock).
140  */
141 
142 /*
143  * Indicator that no process holds exclusive lock
144  */
145 #define LK_KERNPROC ((pid_t) -2)
146 #define LK_NOPROC ((pid_t) -1)
147 
148 void	lock_init __P((struct lock *, int prio, char *wmesg, int timo,
149 			int flags));
150 int	lockmgr __P((__volatile struct lock *, u_int flags,
151 			struct simple_lock *, pid_t pid));
152 int	lockstatus __P((struct lock *));
153 
154 #if NCPUS > 1
155 /*
156  * The simple-lock routines are the primitives out of which the lock
157  * package is built. The machine-dependent code must implement an
158  * atomic test_and_set operation that indivisibly sets the simple_lock
159  * to non-zero and returns its old value. It also assumes that the
160  * setting of the lock to zero below is indivisible. Simple locks may
161  * only be used for exclusive locks.
162  */
163 static __inline void
164 simple_lock_init(lkp)
165 	struct simple_lock *lkp;
166 {
167 
168 	lkp->lock_data = 0;
169 }
170 
171 static __inline void
172 simple_lock(lkp)
173 	__volatile struct simple_lock *lkp;
174 {
175 
176 	while (test_and_set(&lkp->lock_data))
177 		continue;
178 }
179 
180 static __inline int
181 simple_lock_try(lkp)
182 	__volatile struct simple_lock *lkp;
183 {
184 
185 	return (!test_and_set(&lkp->lock_data))
186 }
187 
188 static __inline void
189 simple_unlock(lkp)
190 	struct simple_lock *lkp;
191 {
192 
193 	lkp->lock_data = 0;
194 }
195 
196 #else /* NCPUS == 1, so no multiprocessor locking is necessary */
197 
198 #ifdef DEBUG
199 static __inline void
200 simple_lock_init(alp)
201 	struct simple_lock *alp;
202 {
203 
204 	alp->lock_data = 0;
205 }
206 
207 static __inline void
208 simple_lock(alp)
209 	__volatile struct simple_lock *alp;
210 {
211 	extern const char *simple_lock_held;
212 
213 	if (alp->lock_data == 1)
214 		panic(simple_lock_held);
215 	alp->lock_data = 1;
216 }
217 
218 static __inline int
219 simple_lock_try(alp)
220 	__volatile struct simple_lock *alp;
221 {
222 	extern const char *simple_lock_held;
223 
224 	if (alp->lock_data == 1)
225 		panic(simple_lock_held);
226 	alp->lock_data = 1;
227 	return (1);
228 }
229 
230 static __inline void
231 simple_unlock(alp)
232 	struct simple_lock *alp;
233 {
234 	extern const char *simple_lock_not_held;
235 
236 	if (alp->lock_data == 0)
237 		panic(simple_lock_not_held);
238 	alp->lock_data = 0;
239 }
240 
241 #else /* !DEBUG */
242 #define	simple_lock_init(alp)
243 #define	simple_lock(alp)
244 #define	simple_lock_try(alp)	(1)	/* always succeeds */
245 #define	simple_unlock(alp)
246 #endif /* !DIAGNOSTIC */
247 
248 #endif /* NCPUS == 1 */
249 
250 #endif /* !_LOCK_H_ */
251