xref: /illumos-gate/usr/src/cmd/sendmail/db/lock/lock.c (revision 7c478bd9)
1*7c478bd9Sstevel@tonic-gate /*-
2*7c478bd9Sstevel@tonic-gate  * See the file LICENSE for redistribution information.
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * Copyright (c) 1996, 1997, 1998
5*7c478bd9Sstevel@tonic-gate  *	Sleepycat Software.  All rights reserved.
6*7c478bd9Sstevel@tonic-gate  */
7*7c478bd9Sstevel@tonic-gate 
8*7c478bd9Sstevel@tonic-gate #include "config.h"
9*7c478bd9Sstevel@tonic-gate 
10*7c478bd9Sstevel@tonic-gate #ifndef lint
11*7c478bd9Sstevel@tonic-gate static const char sccsid[] = "@(#)lock.c	10.61 (Sleepycat) 1/3/99";
12*7c478bd9Sstevel@tonic-gate #endif /* not lint */
13*7c478bd9Sstevel@tonic-gate 
14*7c478bd9Sstevel@tonic-gate #ifndef NO_SYSTEM_INCLUDES
15*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
16*7c478bd9Sstevel@tonic-gate 
17*7c478bd9Sstevel@tonic-gate #include <errno.h>
18*7c478bd9Sstevel@tonic-gate #include <string.h>
19*7c478bd9Sstevel@tonic-gate #endif
20*7c478bd9Sstevel@tonic-gate 
21*7c478bd9Sstevel@tonic-gate #include "db_int.h"
22*7c478bd9Sstevel@tonic-gate #include "shqueue.h"
23*7c478bd9Sstevel@tonic-gate #include "db_page.h"
24*7c478bd9Sstevel@tonic-gate #include "db_shash.h"
25*7c478bd9Sstevel@tonic-gate #include "lock.h"
26*7c478bd9Sstevel@tonic-gate #include "db_am.h"
27*7c478bd9Sstevel@tonic-gate #include "txn_auto.h"
28*7c478bd9Sstevel@tonic-gate #include "txn_ext.h"
29*7c478bd9Sstevel@tonic-gate #include "common_ext.h"
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate static void __lock_checklocker __P((DB_LOCKTAB *, struct __db_lock *, int));
32*7c478bd9Sstevel@tonic-gate static void __lock_freeobj __P((DB_LOCKTAB *, DB_LOCKOBJ *));
33*7c478bd9Sstevel@tonic-gate static int  __lock_get_internal __P((DB_LOCKTAB *, u_int32_t, DB_TXN *,
34*7c478bd9Sstevel@tonic-gate     u_int32_t, const DBT *, db_lockmode_t, struct __db_lock **));
35*7c478bd9Sstevel@tonic-gate static int  __lock_is_parent __P((u_int32_t, DB_TXN *));
36*7c478bd9Sstevel@tonic-gate static int  __lock_promote __P((DB_LOCKTAB *, DB_LOCKOBJ *));
37*7c478bd9Sstevel@tonic-gate static int  __lock_put_internal __P((DB_LOCKTAB *, struct __db_lock *, int));
38*7c478bd9Sstevel@tonic-gate static void __lock_remove_waiter
39*7c478bd9Sstevel@tonic-gate     __P((DB_LOCKTAB *, DB_LOCKOBJ *, struct __db_lock *, db_status_t));
40*7c478bd9Sstevel@tonic-gate static int  __lock_vec_internal __P((DB_LOCKTAB *, u_int32_t, DB_TXN *,
41*7c478bd9Sstevel@tonic-gate 	    u_int32_t, DB_LOCKREQ *, int, DB_LOCKREQ **elistp));
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate int
lock_id(lt,idp)44*7c478bd9Sstevel@tonic-gate lock_id(lt, idp)
45*7c478bd9Sstevel@tonic-gate 	DB_LOCKTAB *lt;
46*7c478bd9Sstevel@tonic-gate 	u_int32_t *idp;
47*7c478bd9Sstevel@tonic-gate {
48*7c478bd9Sstevel@tonic-gate 	u_int32_t id;
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate 	LOCK_PANIC_CHECK(lt);
51*7c478bd9Sstevel@tonic-gate 
52*7c478bd9Sstevel@tonic-gate 	LOCK_LOCKREGION(lt);
53*7c478bd9Sstevel@tonic-gate 	if (lt->region->id >= DB_LOCK_MAXID)
54*7c478bd9Sstevel@tonic-gate 		lt->region->id = 0;
55*7c478bd9Sstevel@tonic-gate 	id = ++lt->region->id;
56*7c478bd9Sstevel@tonic-gate 	UNLOCK_LOCKREGION(lt);
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate 	*idp = id;
59*7c478bd9Sstevel@tonic-gate 	return (0);
60*7c478bd9Sstevel@tonic-gate }
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate int
lock_vec(lt,locker,flags,list,nlist,elistp)63*7c478bd9Sstevel@tonic-gate lock_vec(lt, locker, flags, list, nlist, elistp)
64*7c478bd9Sstevel@tonic-gate 	DB_LOCKTAB *lt;
65*7c478bd9Sstevel@tonic-gate 	u_int32_t locker, flags;
66*7c478bd9Sstevel@tonic-gate 	int nlist;
67*7c478bd9Sstevel@tonic-gate 	DB_LOCKREQ *list, **elistp;
68*7c478bd9Sstevel@tonic-gate {
69*7c478bd9Sstevel@tonic-gate 	return (__lock_vec_internal(lt,
70*7c478bd9Sstevel@tonic-gate 	    locker, NULL, flags, list, nlist, elistp));
71*7c478bd9Sstevel@tonic-gate }
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate int
lock_tvec(lt,txn,flags,list,nlist,elistp)74*7c478bd9Sstevel@tonic-gate lock_tvec(lt, txn, flags, list, nlist, elistp)
75*7c478bd9Sstevel@tonic-gate 	DB_LOCKTAB *lt;
76*7c478bd9Sstevel@tonic-gate 	DB_TXN *txn;
77*7c478bd9Sstevel@tonic-gate 	u_int32_t flags;
78*7c478bd9Sstevel@tonic-gate 	int nlist;
79*7c478bd9Sstevel@tonic-gate 	DB_LOCKREQ *list, **elistp;
80*7c478bd9Sstevel@tonic-gate {
81*7c478bd9Sstevel@tonic-gate 	return (__lock_vec_internal(lt,
82*7c478bd9Sstevel@tonic-gate 	    txn->txnid, txn, flags, list, nlist, elistp));
83*7c478bd9Sstevel@tonic-gate }
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate static int
__lock_vec_internal(lt,locker,txn,flags,list,nlist,elistp)86*7c478bd9Sstevel@tonic-gate __lock_vec_internal(lt, locker, txn, flags, list, nlist, elistp)
87*7c478bd9Sstevel@tonic-gate 	DB_LOCKTAB *lt;
88*7c478bd9Sstevel@tonic-gate 	u_int32_t locker;
89*7c478bd9Sstevel@tonic-gate 	DB_TXN *txn;
90*7c478bd9Sstevel@tonic-gate 	u_int32_t flags;
91*7c478bd9Sstevel@tonic-gate 	int nlist;
92*7c478bd9Sstevel@tonic-gate 	DB_LOCKREQ *list, **elistp;
93*7c478bd9Sstevel@tonic-gate {
94*7c478bd9Sstevel@tonic-gate 	struct __db_lock *lp;
95*7c478bd9Sstevel@tonic-gate 	DB_LOCKOBJ *sh_obj, *sh_locker, *sh_parent;
96*7c478bd9Sstevel@tonic-gate 	int i, ret, run_dd;
97*7c478bd9Sstevel@tonic-gate 
98*7c478bd9Sstevel@tonic-gate 	LOCK_PANIC_CHECK(lt);
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate 	/* Validate arguments. */
101*7c478bd9Sstevel@tonic-gate 	if ((ret =
102*7c478bd9Sstevel@tonic-gate 	    __db_fchk(lt->dbenv, "lock_vec", flags, DB_LOCK_NOWAIT)) != 0)
103*7c478bd9Sstevel@tonic-gate 		return (ret);
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate 	LOCK_LOCKREGION(lt);
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate 	if ((ret = __lock_validate_region(lt)) != 0) {
108*7c478bd9Sstevel@tonic-gate 		UNLOCK_LOCKREGION(lt);
109*7c478bd9Sstevel@tonic-gate 		return (ret);
110*7c478bd9Sstevel@tonic-gate 	}
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate 	ret = 0;
113*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < nlist && ret == 0; i++) {
114*7c478bd9Sstevel@tonic-gate 		switch (list[i].op) {
115*7c478bd9Sstevel@tonic-gate 		case DB_LOCK_GET:
116*7c478bd9Sstevel@tonic-gate 			ret = __lock_get_internal(lt, locker, txn, flags,
117*7c478bd9Sstevel@tonic-gate 			    list[i].obj, list[i].mode, &lp);
118*7c478bd9Sstevel@tonic-gate 			if (ret == 0) {
119*7c478bd9Sstevel@tonic-gate 				list[i].lock = LOCK_TO_OFFSET(lt, lp);
120*7c478bd9Sstevel@tonic-gate 				lt->region->nrequests++;
121*7c478bd9Sstevel@tonic-gate 			}
122*7c478bd9Sstevel@tonic-gate 			break;
123*7c478bd9Sstevel@tonic-gate 		case DB_LOCK_INHERIT:
124*7c478bd9Sstevel@tonic-gate 			/* Find the locker. */
125*7c478bd9Sstevel@tonic-gate 			if ((ret = __lock_getobj(lt, locker,
126*7c478bd9Sstevel@tonic-gate 			    NULL, DB_LOCK_LOCKER, &sh_locker)) != 0)
127*7c478bd9Sstevel@tonic-gate 				break;
128*7c478bd9Sstevel@tonic-gate 			if (txn == NULL || txn->parent == NULL) {
129*7c478bd9Sstevel@tonic-gate 				ret = EINVAL;
130*7c478bd9Sstevel@tonic-gate 				break;
131*7c478bd9Sstevel@tonic-gate 			}
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate 			if ((ret = __lock_getobj(lt, txn->parent->txnid,
134*7c478bd9Sstevel@tonic-gate 			    NULL, DB_LOCK_LOCKER, &sh_parent)) != 0)
135*7c478bd9Sstevel@tonic-gate 				break;
136*7c478bd9Sstevel@tonic-gate 
137*7c478bd9Sstevel@tonic-gate 			/*
138*7c478bd9Sstevel@tonic-gate 			 * Traverse all the locks held by this locker.  Remove
139*7c478bd9Sstevel@tonic-gate 			 * the locks from the locker's list and put them on the
140*7c478bd9Sstevel@tonic-gate 			 * parent's list.
141*7c478bd9Sstevel@tonic-gate 			 */
142*7c478bd9Sstevel@tonic-gate 			for (lp = SH_LIST_FIRST(&sh_locker->heldby, __db_lock);
143*7c478bd9Sstevel@tonic-gate 			    lp != NULL;
144*7c478bd9Sstevel@tonic-gate 			    lp = SH_LIST_FIRST(&sh_locker->heldby, __db_lock)) {
145*7c478bd9Sstevel@tonic-gate 				SH_LIST_REMOVE(lp, locker_links, __db_lock);
146*7c478bd9Sstevel@tonic-gate 				SH_LIST_INSERT_HEAD(&sh_parent->heldby, lp,
147*7c478bd9Sstevel@tonic-gate 				    locker_links, __db_lock);
148*7c478bd9Sstevel@tonic-gate 				lp->holder = txn->parent->txnid;
149*7c478bd9Sstevel@tonic-gate 			}
150*7c478bd9Sstevel@tonic-gate 			__lock_freeobj(lt, sh_locker);
151*7c478bd9Sstevel@tonic-gate 			lt->region->nlockers--;
152*7c478bd9Sstevel@tonic-gate 			break;
153*7c478bd9Sstevel@tonic-gate 		case DB_LOCK_PUT:
154*7c478bd9Sstevel@tonic-gate 			lp = OFFSET_TO_LOCK(lt, list[i].lock);
155*7c478bd9Sstevel@tonic-gate 			if (lp->holder != locker) {
156*7c478bd9Sstevel@tonic-gate 				ret = DB_LOCK_NOTHELD;
157*7c478bd9Sstevel@tonic-gate 				break;
158*7c478bd9Sstevel@tonic-gate 			}
159*7c478bd9Sstevel@tonic-gate 			list[i].mode = lp->mode;
160*7c478bd9Sstevel@tonic-gate 
161*7c478bd9Sstevel@tonic-gate 			ret = __lock_put_internal(lt, lp, 0);
162*7c478bd9Sstevel@tonic-gate 			__lock_checklocker(lt, lp, 0);
163*7c478bd9Sstevel@tonic-gate 			break;
164*7c478bd9Sstevel@tonic-gate 		case DB_LOCK_PUT_ALL:
165*7c478bd9Sstevel@tonic-gate 			/* Find the locker. */
166*7c478bd9Sstevel@tonic-gate 			if ((ret = __lock_getobj(lt, locker,
167*7c478bd9Sstevel@tonic-gate 			    NULL, DB_LOCK_LOCKER, &sh_locker)) != 0)
168*7c478bd9Sstevel@tonic-gate 				break;
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate 			for (lp = SH_LIST_FIRST(&sh_locker->heldby, __db_lock);
171*7c478bd9Sstevel@tonic-gate 			    lp != NULL;
172*7c478bd9Sstevel@tonic-gate 			    lp = SH_LIST_FIRST(&sh_locker->heldby, __db_lock)) {
173*7c478bd9Sstevel@tonic-gate 				if ((ret = __lock_put_internal(lt, lp, 1)) != 0)
174*7c478bd9Sstevel@tonic-gate 					break;
175*7c478bd9Sstevel@tonic-gate 			}
176*7c478bd9Sstevel@tonic-gate 			__lock_freeobj(lt, sh_locker);
177*7c478bd9Sstevel@tonic-gate 			lt->region->nlockers--;
178*7c478bd9Sstevel@tonic-gate 			break;
179*7c478bd9Sstevel@tonic-gate 		case DB_LOCK_PUT_OBJ:
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 			/* Look up the object in the hash table. */
182*7c478bd9Sstevel@tonic-gate 			HASHLOOKUP(lt->hashtab, __db_lockobj, links,
183*7c478bd9Sstevel@tonic-gate 			    list[i].obj, sh_obj, lt->region->table_size,
184*7c478bd9Sstevel@tonic-gate 			    __lock_ohash, __lock_cmp);
185*7c478bd9Sstevel@tonic-gate 			if (sh_obj == NULL) {
186*7c478bd9Sstevel@tonic-gate 				ret = EINVAL;
187*7c478bd9Sstevel@tonic-gate 				break;
188*7c478bd9Sstevel@tonic-gate 			}
189*7c478bd9Sstevel@tonic-gate 			/*
190*7c478bd9Sstevel@tonic-gate 			 * Release waiters first, because they won't cause
191*7c478bd9Sstevel@tonic-gate 			 * anyone else to be awakened.  If we release the
192*7c478bd9Sstevel@tonic-gate 			 * lockers first, all the waiters get awakened
193*7c478bd9Sstevel@tonic-gate 			 * needlessly.
194*7c478bd9Sstevel@tonic-gate 			 */
195*7c478bd9Sstevel@tonic-gate 			for (lp = SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock);
196*7c478bd9Sstevel@tonic-gate 			    lp != NULL;
197*7c478bd9Sstevel@tonic-gate 			    lp = SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock)) {
198*7c478bd9Sstevel@tonic-gate 				lt->region->nreleases += lp->refcount;
199*7c478bd9Sstevel@tonic-gate 				__lock_remove_waiter(lt, sh_obj, lp,
200*7c478bd9Sstevel@tonic-gate 				    DB_LSTAT_NOGRANT);
201*7c478bd9Sstevel@tonic-gate 				__lock_checklocker(lt, lp, 1);
202*7c478bd9Sstevel@tonic-gate 			}
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 			for (lp = SH_TAILQ_FIRST(&sh_obj->holders, __db_lock);
205*7c478bd9Sstevel@tonic-gate 			    lp != NULL;
206*7c478bd9Sstevel@tonic-gate 			    lp = SH_TAILQ_FIRST(&sh_obj->holders, __db_lock)) {
207*7c478bd9Sstevel@tonic-gate 
208*7c478bd9Sstevel@tonic-gate 				lt->region->nreleases += lp->refcount;
209*7c478bd9Sstevel@tonic-gate 				SH_LIST_REMOVE(lp, locker_links, __db_lock);
210*7c478bd9Sstevel@tonic-gate 				SH_TAILQ_REMOVE(&sh_obj->holders, lp, links,
211*7c478bd9Sstevel@tonic-gate 				    __db_lock);
212*7c478bd9Sstevel@tonic-gate 				lp->status = DB_LSTAT_FREE;
213*7c478bd9Sstevel@tonic-gate 				SH_TAILQ_INSERT_HEAD(&lt->region->free_locks,
214*7c478bd9Sstevel@tonic-gate 				    lp, links, __db_lock);
215*7c478bd9Sstevel@tonic-gate 			}
216*7c478bd9Sstevel@tonic-gate 
217*7c478bd9Sstevel@tonic-gate 			/* Now free the object. */
218*7c478bd9Sstevel@tonic-gate 			__lock_freeobj(lt, sh_obj);
219*7c478bd9Sstevel@tonic-gate 			break;
220*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
221*7c478bd9Sstevel@tonic-gate 		case DB_LOCK_DUMP:
222*7c478bd9Sstevel@tonic-gate 			/* Find the locker. */
223*7c478bd9Sstevel@tonic-gate 			if ((ret = __lock_getobj(lt, locker,
224*7c478bd9Sstevel@tonic-gate 			    NULL, DB_LOCK_LOCKER, &sh_locker)) != 0)
225*7c478bd9Sstevel@tonic-gate 				break;
226*7c478bd9Sstevel@tonic-gate 
227*7c478bd9Sstevel@tonic-gate 			for (lp = SH_LIST_FIRST(&sh_locker->heldby, __db_lock);
228*7c478bd9Sstevel@tonic-gate 			    lp != NULL;
229*7c478bd9Sstevel@tonic-gate 			    lp = SH_LIST_NEXT(lp, locker_links, __db_lock)) {
230*7c478bd9Sstevel@tonic-gate 				__lock_printlock(lt, lp, 1);
231*7c478bd9Sstevel@tonic-gate 				ret = EINVAL;
232*7c478bd9Sstevel@tonic-gate 			}
233*7c478bd9Sstevel@tonic-gate 			if (ret == 0) {
234*7c478bd9Sstevel@tonic-gate 				__lock_freeobj(lt, sh_locker);
235*7c478bd9Sstevel@tonic-gate 				lt->region->nlockers--;
236*7c478bd9Sstevel@tonic-gate 			}
237*7c478bd9Sstevel@tonic-gate 			break;
238*7c478bd9Sstevel@tonic-gate #endif
239*7c478bd9Sstevel@tonic-gate 		default:
240*7c478bd9Sstevel@tonic-gate 			ret = EINVAL;
241*7c478bd9Sstevel@tonic-gate 			break;
242*7c478bd9Sstevel@tonic-gate 		}
243*7c478bd9Sstevel@tonic-gate 	}
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate 	if (lt->region->need_dd && lt->region->detect != DB_LOCK_NORUN) {
246*7c478bd9Sstevel@tonic-gate 		run_dd = 1;
247*7c478bd9Sstevel@tonic-gate 		lt->region->need_dd = 0;
248*7c478bd9Sstevel@tonic-gate 	} else
249*7c478bd9Sstevel@tonic-gate 		run_dd = 0;
250*7c478bd9Sstevel@tonic-gate 
251*7c478bd9Sstevel@tonic-gate 	UNLOCK_LOCKREGION(lt);
252*7c478bd9Sstevel@tonic-gate 
253*7c478bd9Sstevel@tonic-gate 	if (ret == 0 && run_dd)
254*7c478bd9Sstevel@tonic-gate 		lock_detect(lt, 0, lt->region->detect);
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate 	if (elistp && ret != 0)
257*7c478bd9Sstevel@tonic-gate 		*elistp = &list[i - 1];
258*7c478bd9Sstevel@tonic-gate 	return (ret);
259*7c478bd9Sstevel@tonic-gate }
260*7c478bd9Sstevel@tonic-gate 
261*7c478bd9Sstevel@tonic-gate int
lock_get(lt,locker,flags,obj,lock_mode,lock)262*7c478bd9Sstevel@tonic-gate lock_get(lt, locker, flags, obj, lock_mode, lock)
263*7c478bd9Sstevel@tonic-gate 	DB_LOCKTAB *lt;
264*7c478bd9Sstevel@tonic-gate 	u_int32_t locker, flags;
265*7c478bd9Sstevel@tonic-gate 	const DBT *obj;
266*7c478bd9Sstevel@tonic-gate 	db_lockmode_t lock_mode;
267*7c478bd9Sstevel@tonic-gate 	DB_LOCK *lock;
268*7c478bd9Sstevel@tonic-gate {
269*7c478bd9Sstevel@tonic-gate 	struct __db_lock *lockp;
270*7c478bd9Sstevel@tonic-gate 	int ret;
271*7c478bd9Sstevel@tonic-gate 
272*7c478bd9Sstevel@tonic-gate 	LOCK_PANIC_CHECK(lt);
273*7c478bd9Sstevel@tonic-gate 
274*7c478bd9Sstevel@tonic-gate 	/* Validate arguments. */
275*7c478bd9Sstevel@tonic-gate 	if ((ret = __db_fchk(lt->dbenv,
276*7c478bd9Sstevel@tonic-gate 	    "lock_get", flags, DB_LOCK_NOWAIT | DB_LOCK_UPGRADE)) != 0)
277*7c478bd9Sstevel@tonic-gate 		return (ret);
278*7c478bd9Sstevel@tonic-gate 
279*7c478bd9Sstevel@tonic-gate 	LOCK_LOCKREGION(lt);
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate 	if ((ret = __lock_validate_region(lt)) == 0) {
282*7c478bd9Sstevel@tonic-gate 		if (LF_ISSET(DB_LOCK_UPGRADE))
283*7c478bd9Sstevel@tonic-gate 			lockp = OFFSET_TO_LOCK(lt, *lock);
284*7c478bd9Sstevel@tonic-gate 
285*7c478bd9Sstevel@tonic-gate 		if ((ret = __lock_get_internal(lt,
286*7c478bd9Sstevel@tonic-gate 		    locker, NULL, flags, obj, lock_mode, &lockp)) == 0) {
287*7c478bd9Sstevel@tonic-gate 			if (!LF_ISSET(DB_LOCK_UPGRADE))
288*7c478bd9Sstevel@tonic-gate 				*lock = LOCK_TO_OFFSET(lt, lockp);
289*7c478bd9Sstevel@tonic-gate 			lt->region->nrequests++;
290*7c478bd9Sstevel@tonic-gate 		}
291*7c478bd9Sstevel@tonic-gate 	}
292*7c478bd9Sstevel@tonic-gate 
293*7c478bd9Sstevel@tonic-gate 	UNLOCK_LOCKREGION(lt);
294*7c478bd9Sstevel@tonic-gate 	return (ret);
295*7c478bd9Sstevel@tonic-gate }
296*7c478bd9Sstevel@tonic-gate 
297*7c478bd9Sstevel@tonic-gate int
lock_tget(lt,txn,flags,obj,lock_mode,lock)298*7c478bd9Sstevel@tonic-gate lock_tget(lt, txn, flags, obj, lock_mode, lock)
299*7c478bd9Sstevel@tonic-gate 	DB_LOCKTAB *lt;
300*7c478bd9Sstevel@tonic-gate 	DB_TXN *txn;
301*7c478bd9Sstevel@tonic-gate 	u_int32_t flags;
302*7c478bd9Sstevel@tonic-gate 	const DBT *obj;
303*7c478bd9Sstevel@tonic-gate 	db_lockmode_t lock_mode;
304*7c478bd9Sstevel@tonic-gate 	DB_LOCK *lock;
305*7c478bd9Sstevel@tonic-gate {
306*7c478bd9Sstevel@tonic-gate 	struct __db_lock *lockp;
307*7c478bd9Sstevel@tonic-gate 	int ret;
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate 	LOCK_PANIC_CHECK(lt);
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 	/* Validate arguments. */
312*7c478bd9Sstevel@tonic-gate 	if ((ret = __db_fchk(lt->dbenv,
313*7c478bd9Sstevel@tonic-gate 	    "lock_get", flags, DB_LOCK_NOWAIT | DB_LOCK_UPGRADE)) != 0)
314*7c478bd9Sstevel@tonic-gate 		return (ret);
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate 	LOCK_LOCKREGION(lt);
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate 	if ((ret = __lock_validate_region(lt)) == 0) {
319*7c478bd9Sstevel@tonic-gate 		if (LF_ISSET(DB_LOCK_UPGRADE))
320*7c478bd9Sstevel@tonic-gate 			lockp = OFFSET_TO_LOCK(lt, *lock);
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate 		if ((ret = __lock_get_internal(lt,
323*7c478bd9Sstevel@tonic-gate 		    txn->txnid, txn, flags, obj, lock_mode, &lockp)) == 0) {
324*7c478bd9Sstevel@tonic-gate 			if (!LF_ISSET(DB_LOCK_UPGRADE))
325*7c478bd9Sstevel@tonic-gate 				*lock = LOCK_TO_OFFSET(lt, lockp);
326*7c478bd9Sstevel@tonic-gate 			lt->region->nrequests++;
327*7c478bd9Sstevel@tonic-gate 		}
328*7c478bd9Sstevel@tonic-gate 	}
329*7c478bd9Sstevel@tonic-gate 
330*7c478bd9Sstevel@tonic-gate 	UNLOCK_LOCKREGION(lt);
331*7c478bd9Sstevel@tonic-gate 	return (ret);
332*7c478bd9Sstevel@tonic-gate }
333*7c478bd9Sstevel@tonic-gate int
lock_put(lt,lock)334*7c478bd9Sstevel@tonic-gate lock_put(lt, lock)
335*7c478bd9Sstevel@tonic-gate 	DB_LOCKTAB *lt;
336*7c478bd9Sstevel@tonic-gate 	DB_LOCK lock;
337*7c478bd9Sstevel@tonic-gate {
338*7c478bd9Sstevel@tonic-gate 	struct __db_lock *lockp;
339*7c478bd9Sstevel@tonic-gate 	int ret, run_dd;
340*7c478bd9Sstevel@tonic-gate 
341*7c478bd9Sstevel@tonic-gate 	LOCK_PANIC_CHECK(lt);
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate 	LOCK_LOCKREGION(lt);
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate 	if ((ret = __lock_validate_region(lt)) != 0)
346*7c478bd9Sstevel@tonic-gate 		return (ret);
347*7c478bd9Sstevel@tonic-gate 	else {
348*7c478bd9Sstevel@tonic-gate 		lockp = OFFSET_TO_LOCK(lt, lock);
349*7c478bd9Sstevel@tonic-gate 		ret = __lock_put_internal(lt, lockp, 0);
350*7c478bd9Sstevel@tonic-gate 	}
351*7c478bd9Sstevel@tonic-gate 
352*7c478bd9Sstevel@tonic-gate 	__lock_checklocker(lt, lockp, 0);
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 	if (lt->region->need_dd && lt->region->detect != DB_LOCK_NORUN) {
355*7c478bd9Sstevel@tonic-gate 		run_dd = 1;
356*7c478bd9Sstevel@tonic-gate 		lt->region->need_dd = 0;
357*7c478bd9Sstevel@tonic-gate 	} else
358*7c478bd9Sstevel@tonic-gate 		run_dd = 0;
359*7c478bd9Sstevel@tonic-gate 
360*7c478bd9Sstevel@tonic-gate 	UNLOCK_LOCKREGION(lt);
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate 	if (ret == 0 && run_dd)
363*7c478bd9Sstevel@tonic-gate 		lock_detect(lt, 0, lt->region->detect);
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate 	return (ret);
366*7c478bd9Sstevel@tonic-gate }
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate static int
__lock_put_internal(lt,lockp,do_all)369*7c478bd9Sstevel@tonic-gate __lock_put_internal(lt, lockp, do_all)
370*7c478bd9Sstevel@tonic-gate 	DB_LOCKTAB *lt;
371*7c478bd9Sstevel@tonic-gate 	struct __db_lock *lockp;
372*7c478bd9Sstevel@tonic-gate 	int do_all;
373*7c478bd9Sstevel@tonic-gate {
374*7c478bd9Sstevel@tonic-gate 	DB_LOCKOBJ *sh_obj;
375*7c478bd9Sstevel@tonic-gate 	int state_changed;
376*7c478bd9Sstevel@tonic-gate 
377*7c478bd9Sstevel@tonic-gate 	if (lockp->refcount == 0 || (lockp->status != DB_LSTAT_HELD &&
378*7c478bd9Sstevel@tonic-gate 	    lockp->status != DB_LSTAT_WAITING) || lockp->obj == 0) {
379*7c478bd9Sstevel@tonic-gate 		__db_err(lt->dbenv, "lock_put: invalid lock %lu",
380*7c478bd9Sstevel@tonic-gate 		    (u_long)((u_int8_t *)lockp - (u_int8_t *)lt->region));
381*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
382*7c478bd9Sstevel@tonic-gate 	}
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate 	if (do_all)
385*7c478bd9Sstevel@tonic-gate 		lt->region->nreleases += lockp->refcount;
386*7c478bd9Sstevel@tonic-gate 	else
387*7c478bd9Sstevel@tonic-gate 		lt->region->nreleases++;
388*7c478bd9Sstevel@tonic-gate 	if (do_all == 0 && lockp->refcount > 1) {
389*7c478bd9Sstevel@tonic-gate 		lockp->refcount--;
390*7c478bd9Sstevel@tonic-gate 		return (0);
391*7c478bd9Sstevel@tonic-gate 	}
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate 	/* Get the object associated with this lock. */
394*7c478bd9Sstevel@tonic-gate 	sh_obj = (DB_LOCKOBJ *)((u_int8_t *)lockp + lockp->obj);
395*7c478bd9Sstevel@tonic-gate 
396*7c478bd9Sstevel@tonic-gate 	/* Remove lock from locker list. */
397*7c478bd9Sstevel@tonic-gate 	SH_LIST_REMOVE(lockp, locker_links, __db_lock);
398*7c478bd9Sstevel@tonic-gate 
399*7c478bd9Sstevel@tonic-gate 	/* Remove this lock from its holders/waitlist. */
400*7c478bd9Sstevel@tonic-gate 	if (lockp->status != DB_LSTAT_HELD)
401*7c478bd9Sstevel@tonic-gate 		__lock_remove_waiter(lt, sh_obj, lockp, DB_LSTAT_FREE);
402*7c478bd9Sstevel@tonic-gate 	else
403*7c478bd9Sstevel@tonic-gate 		SH_TAILQ_REMOVE(&sh_obj->holders, lockp, links, __db_lock);
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 	state_changed = __lock_promote(lt, sh_obj);
406*7c478bd9Sstevel@tonic-gate 
407*7c478bd9Sstevel@tonic-gate 	/* Check if object should be reclaimed. */
408*7c478bd9Sstevel@tonic-gate 	if (SH_TAILQ_FIRST(&sh_obj->holders, __db_lock) == NULL) {
409*7c478bd9Sstevel@tonic-gate 		HASHREMOVE_EL(lt->hashtab, __db_lockobj,
410*7c478bd9Sstevel@tonic-gate 		    links, sh_obj, lt->region->table_size, __lock_lhash);
411*7c478bd9Sstevel@tonic-gate 		if (sh_obj->lockobj.size > sizeof(sh_obj->objdata))
412*7c478bd9Sstevel@tonic-gate 			__db_shalloc_free(lt->mem,
413*7c478bd9Sstevel@tonic-gate 			    SH_DBT_PTR(&sh_obj->lockobj));
414*7c478bd9Sstevel@tonic-gate 		SH_TAILQ_INSERT_HEAD(&lt->region->free_objs, sh_obj, links,
415*7c478bd9Sstevel@tonic-gate 		    __db_lockobj);
416*7c478bd9Sstevel@tonic-gate 		state_changed = 1;
417*7c478bd9Sstevel@tonic-gate 	}
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate 	/* Free lock. */
420*7c478bd9Sstevel@tonic-gate 	lockp->status = DB_LSTAT_FREE;
421*7c478bd9Sstevel@tonic-gate 	SH_TAILQ_INSERT_HEAD(&lt->region->free_locks, lockp, links, __db_lock);
422*7c478bd9Sstevel@tonic-gate 
423*7c478bd9Sstevel@tonic-gate 	/*
424*7c478bd9Sstevel@tonic-gate 	 * If we did not promote anyone; we need to run the deadlock
425*7c478bd9Sstevel@tonic-gate 	 * detector again.
426*7c478bd9Sstevel@tonic-gate 	 */
427*7c478bd9Sstevel@tonic-gate 	if (state_changed == 0)
428*7c478bd9Sstevel@tonic-gate 		lt->region->need_dd = 1;
429*7c478bd9Sstevel@tonic-gate 
430*7c478bd9Sstevel@tonic-gate 	return (0);
431*7c478bd9Sstevel@tonic-gate }
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate static int
__lock_get_internal(lt,locker,txn,flags,obj,lock_mode,lockp)434*7c478bd9Sstevel@tonic-gate __lock_get_internal(lt, locker, txn, flags, obj, lock_mode, lockp)
435*7c478bd9Sstevel@tonic-gate 	DB_LOCKTAB *lt;
436*7c478bd9Sstevel@tonic-gate 	u_int32_t locker, flags;
437*7c478bd9Sstevel@tonic-gate 	DB_TXN *txn;
438*7c478bd9Sstevel@tonic-gate 	const DBT *obj;
439*7c478bd9Sstevel@tonic-gate 	db_lockmode_t lock_mode;
440*7c478bd9Sstevel@tonic-gate 	struct __db_lock **lockp;
441*7c478bd9Sstevel@tonic-gate {
442*7c478bd9Sstevel@tonic-gate 	struct __db_lock *newl, *lp;
443*7c478bd9Sstevel@tonic-gate 	DB_LOCKOBJ *sh_obj, *sh_locker;
444*7c478bd9Sstevel@tonic-gate 	DB_LOCKREGION *lrp;
445*7c478bd9Sstevel@tonic-gate 	size_t newl_off;
446*7c478bd9Sstevel@tonic-gate 	int ihold, no_dd, ret;
447*7c478bd9Sstevel@tonic-gate 
448*7c478bd9Sstevel@tonic-gate 	no_dd = ret = 0;
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 	/*
451*7c478bd9Sstevel@tonic-gate 	 * Check that lock mode is valid.
452*7c478bd9Sstevel@tonic-gate 	 */
453*7c478bd9Sstevel@tonic-gate 	lrp = lt->region;
454*7c478bd9Sstevel@tonic-gate 	if ((u_int32_t)lock_mode >= lrp->nmodes) {
455*7c478bd9Sstevel@tonic-gate 		__db_err(lt->dbenv,
456*7c478bd9Sstevel@tonic-gate 		    "lock_get: invalid lock mode %lu\n", (u_long)lock_mode);
457*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
458*7c478bd9Sstevel@tonic-gate 	}
459*7c478bd9Sstevel@tonic-gate 
460*7c478bd9Sstevel@tonic-gate 	/* Allocate a new lock.  Optimize for the common case of a grant. */
461*7c478bd9Sstevel@tonic-gate 	if ((newl = SH_TAILQ_FIRST(&lrp->free_locks, __db_lock)) == NULL) {
462*7c478bd9Sstevel@tonic-gate 		if ((ret = __lock_grow_region(lt, DB_LOCK_LOCK, 0)) != 0)
463*7c478bd9Sstevel@tonic-gate 			return (ret);
464*7c478bd9Sstevel@tonic-gate 		lrp = lt->region;
465*7c478bd9Sstevel@tonic-gate 		newl = SH_TAILQ_FIRST(&lrp->free_locks, __db_lock);
466*7c478bd9Sstevel@tonic-gate 	}
467*7c478bd9Sstevel@tonic-gate 	newl_off = LOCK_TO_OFFSET(lt, newl);
468*7c478bd9Sstevel@tonic-gate 
469*7c478bd9Sstevel@tonic-gate 	/* Optimize for common case of granting a lock. */
470*7c478bd9Sstevel@tonic-gate 	SH_TAILQ_REMOVE(&lrp->free_locks, newl, links, __db_lock);
471*7c478bd9Sstevel@tonic-gate 
472*7c478bd9Sstevel@tonic-gate 	newl->mode = lock_mode;
473*7c478bd9Sstevel@tonic-gate 	newl->status = DB_LSTAT_HELD;
474*7c478bd9Sstevel@tonic-gate 	newl->holder = locker;
475*7c478bd9Sstevel@tonic-gate 	newl->refcount = 1;
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate 	if ((ret = __lock_getobj(lt, 0, obj, DB_LOCK_OBJTYPE, &sh_obj)) != 0)
478*7c478bd9Sstevel@tonic-gate 		return (ret);
479*7c478bd9Sstevel@tonic-gate 
480*7c478bd9Sstevel@tonic-gate 	lrp = lt->region;			/* getobj might have grown */
481*7c478bd9Sstevel@tonic-gate 	newl = OFFSET_TO_LOCK(lt, newl_off);
482*7c478bd9Sstevel@tonic-gate 
483*7c478bd9Sstevel@tonic-gate 	/* Now make new lock point to object */
484*7c478bd9Sstevel@tonic-gate 	newl->obj = SH_PTR_TO_OFF(newl, sh_obj);
485*7c478bd9Sstevel@tonic-gate 
486*7c478bd9Sstevel@tonic-gate 	/*
487*7c478bd9Sstevel@tonic-gate 	 * Now we have a lock and an object and we need to see if we should
488*7c478bd9Sstevel@tonic-gate 	 * grant the lock.  We use a FIFO ordering so we can only grant a
489*7c478bd9Sstevel@tonic-gate 	 * new lock if it does not conflict with anyone on the holders list
490*7c478bd9Sstevel@tonic-gate 	 * OR anyone on the waiters list.  The reason that we don't grant if
491*7c478bd9Sstevel@tonic-gate 	 * there's a conflict is that this can lead to starvation (a writer
492*7c478bd9Sstevel@tonic-gate 	 * waiting on a popularly read item will never be granted).  The
493*7c478bd9Sstevel@tonic-gate 	 * downside of this is that a waiting reader can prevent an upgrade
494*7c478bd9Sstevel@tonic-gate 	 * from reader to writer, which is not uncommon.
495*7c478bd9Sstevel@tonic-gate 	 *
496*7c478bd9Sstevel@tonic-gate 	 * There is one exception to the no-conflict rule.  If a lock is held
497*7c478bd9Sstevel@tonic-gate 	 * by the requesting locker AND the new lock does not conflict with
498*7c478bd9Sstevel@tonic-gate 	 * any other holders, then we grant the lock.  The most common place
499*7c478bd9Sstevel@tonic-gate 	 * this happens is when the holder has a WRITE lock and a READ lock
500*7c478bd9Sstevel@tonic-gate 	 * request comes in for the same locker.  If we do not grant the read
501*7c478bd9Sstevel@tonic-gate 	 * lock, then we guarantee deadlock.
502*7c478bd9Sstevel@tonic-gate 	 *
503*7c478bd9Sstevel@tonic-gate 	 * In case of conflict, we put the new lock on the end of the waiters
504*7c478bd9Sstevel@tonic-gate 	 * list, unless we are upgrading in which case the locker goes on the
505*7c478bd9Sstevel@tonic-gate 	 * front of the list.
506*7c478bd9Sstevel@tonic-gate 	 */
507*7c478bd9Sstevel@tonic-gate 	ihold = 0;
508*7c478bd9Sstevel@tonic-gate 	for (lp = SH_TAILQ_FIRST(&sh_obj->holders, __db_lock);
509*7c478bd9Sstevel@tonic-gate 	    lp != NULL;
510*7c478bd9Sstevel@tonic-gate 	    lp = SH_TAILQ_NEXT(lp, links, __db_lock)) {
511*7c478bd9Sstevel@tonic-gate 		if (locker == lp->holder ||
512*7c478bd9Sstevel@tonic-gate 		    __lock_is_parent(lp->holder, txn)) {
513*7c478bd9Sstevel@tonic-gate 			if (lp->mode == lock_mode &&
514*7c478bd9Sstevel@tonic-gate 			    lp->status == DB_LSTAT_HELD) {
515*7c478bd9Sstevel@tonic-gate 				if (LF_ISSET(DB_LOCK_UPGRADE))
516*7c478bd9Sstevel@tonic-gate 					goto upgrade;
517*7c478bd9Sstevel@tonic-gate 
518*7c478bd9Sstevel@tonic-gate 				/*
519*7c478bd9Sstevel@tonic-gate 				 * Lock is held, so we can increment the
520*7c478bd9Sstevel@tonic-gate 				 * reference count and return this lock.
521*7c478bd9Sstevel@tonic-gate 				 */
522*7c478bd9Sstevel@tonic-gate 				lp->refcount++;
523*7c478bd9Sstevel@tonic-gate 				*lockp = lp;
524*7c478bd9Sstevel@tonic-gate 				SH_TAILQ_INSERT_HEAD(&lrp->free_locks,
525*7c478bd9Sstevel@tonic-gate 				    newl, links, __db_lock);
526*7c478bd9Sstevel@tonic-gate 				return (0);
527*7c478bd9Sstevel@tonic-gate 			} else
528*7c478bd9Sstevel@tonic-gate 				ihold = 1;
529*7c478bd9Sstevel@tonic-gate 		} else if (CONFLICTS(lt, lp->mode, lock_mode))
530*7c478bd9Sstevel@tonic-gate 			break;
531*7c478bd9Sstevel@tonic-gate     	}
532*7c478bd9Sstevel@tonic-gate 
533*7c478bd9Sstevel@tonic-gate 	/*
534*7c478bd9Sstevel@tonic-gate 	 * If we are upgrading, then there are two scenarios.  Either
535*7c478bd9Sstevel@tonic-gate 	 * we had no conflicts, so we can do the upgrade.  Or, there
536*7c478bd9Sstevel@tonic-gate 	 * is a conflict and we should wait at the HEAD of the waiters
537*7c478bd9Sstevel@tonic-gate 	 * list.
538*7c478bd9Sstevel@tonic-gate 	 */
539*7c478bd9Sstevel@tonic-gate 	if (LF_ISSET(DB_LOCK_UPGRADE)) {
540*7c478bd9Sstevel@tonic-gate 		if (lp == NULL)
541*7c478bd9Sstevel@tonic-gate 			goto upgrade;
542*7c478bd9Sstevel@tonic-gate 
543*7c478bd9Sstevel@tonic-gate 		/* There was a conflict, wait. */
544*7c478bd9Sstevel@tonic-gate 		SH_TAILQ_INSERT_HEAD(&sh_obj->waiters, newl, links, __db_lock);
545*7c478bd9Sstevel@tonic-gate 		goto wait;
546*7c478bd9Sstevel@tonic-gate 	}
547*7c478bd9Sstevel@tonic-gate 
548*7c478bd9Sstevel@tonic-gate 	if (lp == NULL && !ihold)
549*7c478bd9Sstevel@tonic-gate 		for (lp = SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock);
550*7c478bd9Sstevel@tonic-gate 		    lp != NULL;
551*7c478bd9Sstevel@tonic-gate 		    lp = SH_TAILQ_NEXT(lp, links, __db_lock)) {
552*7c478bd9Sstevel@tonic-gate 			if (CONFLICTS(lt, lp->mode, lock_mode) &&
553*7c478bd9Sstevel@tonic-gate 			    locker != lp->holder)
554*7c478bd9Sstevel@tonic-gate 				break;
555*7c478bd9Sstevel@tonic-gate 		}
556*7c478bd9Sstevel@tonic-gate 	if (lp == NULL)
557*7c478bd9Sstevel@tonic-gate 		SH_TAILQ_INSERT_TAIL(&sh_obj->holders, newl, links);
558*7c478bd9Sstevel@tonic-gate 	else if (!(flags & DB_LOCK_NOWAIT))
559*7c478bd9Sstevel@tonic-gate 		SH_TAILQ_INSERT_TAIL(&sh_obj->waiters, newl, links);
560*7c478bd9Sstevel@tonic-gate 	else {
561*7c478bd9Sstevel@tonic-gate 		/* Free the lock and return an error. */
562*7c478bd9Sstevel@tonic-gate 		newl->status = DB_LSTAT_FREE;
563*7c478bd9Sstevel@tonic-gate 		SH_TAILQ_INSERT_HEAD(&lrp->free_locks, newl, links, __db_lock);
564*7c478bd9Sstevel@tonic-gate 		return (DB_LOCK_NOTGRANTED);
565*7c478bd9Sstevel@tonic-gate 	}
566*7c478bd9Sstevel@tonic-gate 
567*7c478bd9Sstevel@tonic-gate 	/*
568*7c478bd9Sstevel@tonic-gate 	 * Now, insert the lock onto its locker's list.  If the locker does
569*7c478bd9Sstevel@tonic-gate 	 * not currently hold any locks, there's no reason to run a deadlock
570*7c478bd9Sstevel@tonic-gate 	 * detector, save that information.
571*7c478bd9Sstevel@tonic-gate 	 */
572*7c478bd9Sstevel@tonic-gate 	if ((ret =
573*7c478bd9Sstevel@tonic-gate 	    __lock_getobj(lt, locker, NULL, DB_LOCK_LOCKER, &sh_locker)) != 0)
574*7c478bd9Sstevel@tonic-gate 		return (ret);
575*7c478bd9Sstevel@tonic-gate 	no_dd = SH_LIST_FIRST(&sh_locker->heldby, __db_lock) == NULL;
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate 	lrp = lt->region;
578*7c478bd9Sstevel@tonic-gate 	SH_LIST_INSERT_HEAD(&sh_locker->heldby, newl, locker_links, __db_lock);
579*7c478bd9Sstevel@tonic-gate 
580*7c478bd9Sstevel@tonic-gate 	if (lp != NULL) {
581*7c478bd9Sstevel@tonic-gate 		/*
582*7c478bd9Sstevel@tonic-gate 		 * This is really a blocker for the process, so initialize it
583*7c478bd9Sstevel@tonic-gate 		 * set.  That way the current process will block when it tries
584*7c478bd9Sstevel@tonic-gate 		 * to get it and the waking process will release it.
585*7c478bd9Sstevel@tonic-gate 		 */
586*7c478bd9Sstevel@tonic-gate wait:		(void)__db_mutex_init(&newl->mutex,
587*7c478bd9Sstevel@tonic-gate 		    MUTEX_LOCK_OFFSET(lt->region, &newl->mutex));
588*7c478bd9Sstevel@tonic-gate 		(void)__db_mutex_lock(&newl->mutex, lt->reginfo.fd);
589*7c478bd9Sstevel@tonic-gate 
590*7c478bd9Sstevel@tonic-gate 		newl->status = DB_LSTAT_WAITING;
591*7c478bd9Sstevel@tonic-gate 		lrp->nconflicts++;
592*7c478bd9Sstevel@tonic-gate 
593*7c478bd9Sstevel@tonic-gate 		/*
594*7c478bd9Sstevel@tonic-gate 		 * We are about to wait; must release the region mutex.  Then,
595*7c478bd9Sstevel@tonic-gate 		 * when we wakeup, we need to reacquire the region mutex before
596*7c478bd9Sstevel@tonic-gate 		 * continuing.
597*7c478bd9Sstevel@tonic-gate 		 */
598*7c478bd9Sstevel@tonic-gate 		if (lrp->detect == DB_LOCK_NORUN)
599*7c478bd9Sstevel@tonic-gate 			lt->region->need_dd = 1;
600*7c478bd9Sstevel@tonic-gate 		UNLOCK_LOCKREGION(lt);
601*7c478bd9Sstevel@tonic-gate 
602*7c478bd9Sstevel@tonic-gate 		/*
603*7c478bd9Sstevel@tonic-gate 		 * We are about to wait; before waiting, see if the deadlock
604*7c478bd9Sstevel@tonic-gate 		 * detector should be run.
605*7c478bd9Sstevel@tonic-gate 		 */
606*7c478bd9Sstevel@tonic-gate 		if (lrp->detect != DB_LOCK_NORUN && !no_dd)
607*7c478bd9Sstevel@tonic-gate 			(void)lock_detect(lt, 0, lrp->detect);
608*7c478bd9Sstevel@tonic-gate 
609*7c478bd9Sstevel@tonic-gate 		(void)__db_mutex_lock(&newl->mutex, lt->reginfo.fd);
610*7c478bd9Sstevel@tonic-gate 
611*7c478bd9Sstevel@tonic-gate 		LOCK_LOCKREGION(lt);
612*7c478bd9Sstevel@tonic-gate 		if (newl->status != DB_LSTAT_PENDING) {
613*7c478bd9Sstevel@tonic-gate 			/*
614*7c478bd9Sstevel@tonic-gate 			 * If this lock errored due to a deadlock, then
615*7c478bd9Sstevel@tonic-gate 			 * we have waiters that require promotion.
616*7c478bd9Sstevel@tonic-gate 			 */
617*7c478bd9Sstevel@tonic-gate 			if (newl->status == DB_LSTAT_ABORTED)
618*7c478bd9Sstevel@tonic-gate 				(void)__lock_promote(lt, sh_obj);
619*7c478bd9Sstevel@tonic-gate 			/* Return to free list. */
620*7c478bd9Sstevel@tonic-gate 			__lock_checklocker(lt, newl, 0);
621*7c478bd9Sstevel@tonic-gate 			SH_TAILQ_INSERT_HEAD(&lrp->free_locks, newl, links,
622*7c478bd9Sstevel@tonic-gate 			    __db_lock);
623*7c478bd9Sstevel@tonic-gate 			switch (newl->status) {
624*7c478bd9Sstevel@tonic-gate 				case DB_LSTAT_ABORTED:
625*7c478bd9Sstevel@tonic-gate 					ret = DB_LOCK_DEADLOCK;
626*7c478bd9Sstevel@tonic-gate 					break;
627*7c478bd9Sstevel@tonic-gate 				case DB_LSTAT_NOGRANT:
628*7c478bd9Sstevel@tonic-gate 					ret = DB_LOCK_NOTGRANTED;
629*7c478bd9Sstevel@tonic-gate 					break;
630*7c478bd9Sstevel@tonic-gate 				default:
631*7c478bd9Sstevel@tonic-gate 					ret = EINVAL;
632*7c478bd9Sstevel@tonic-gate 					break;
633*7c478bd9Sstevel@tonic-gate 			}
634*7c478bd9Sstevel@tonic-gate 			newl->status = DB_LSTAT_FREE;
635*7c478bd9Sstevel@tonic-gate 			newl = NULL;
636*7c478bd9Sstevel@tonic-gate 		} else if (LF_ISSET(DB_LOCK_UPGRADE)) {
637*7c478bd9Sstevel@tonic-gate 			/*
638*7c478bd9Sstevel@tonic-gate 			 * The lock that was just granted got put on the
639*7c478bd9Sstevel@tonic-gate 			 * holders list.  Since we're upgrading some other
640*7c478bd9Sstevel@tonic-gate 			 * lock, we've got to remove it here.
641*7c478bd9Sstevel@tonic-gate 			 */
642*7c478bd9Sstevel@tonic-gate 			SH_TAILQ_REMOVE(&sh_obj->holders,
643*7c478bd9Sstevel@tonic-gate 			    newl, links, __db_lock);
644*7c478bd9Sstevel@tonic-gate 			goto upgrade;
645*7c478bd9Sstevel@tonic-gate 		} else
646*7c478bd9Sstevel@tonic-gate 			newl->status = DB_LSTAT_HELD;
647*7c478bd9Sstevel@tonic-gate 	}
648*7c478bd9Sstevel@tonic-gate 
649*7c478bd9Sstevel@tonic-gate 	*lockp = newl;
650*7c478bd9Sstevel@tonic-gate 	return (ret);
651*7c478bd9Sstevel@tonic-gate 
652*7c478bd9Sstevel@tonic-gate upgrade:
653*7c478bd9Sstevel@tonic-gate 	/*
654*7c478bd9Sstevel@tonic-gate 	 * This was an upgrade, so return the new lock to the free list and
655*7c478bd9Sstevel@tonic-gate 	 * upgrade the mode.
656*7c478bd9Sstevel@tonic-gate 	 */
657*7c478bd9Sstevel@tonic-gate 	(*lockp)->mode = lock_mode;
658*7c478bd9Sstevel@tonic-gate 	newl->status = DB_LSTAT_FREE;
659*7c478bd9Sstevel@tonic-gate 	SH_TAILQ_INSERT_HEAD(&lrp->free_locks, newl, links, __db_lock);
660*7c478bd9Sstevel@tonic-gate 	return (0);
661*7c478bd9Sstevel@tonic-gate }
662*7c478bd9Sstevel@tonic-gate 
663*7c478bd9Sstevel@tonic-gate /*
664*7c478bd9Sstevel@tonic-gate  * __lock_is_locked --
665*7c478bd9Sstevel@tonic-gate  *
666*7c478bd9Sstevel@tonic-gate  * PUBLIC: int __lock_is_locked
667*7c478bd9Sstevel@tonic-gate  * PUBLIC:    __P((DB_LOCKTAB *, u_int32_t, DBT *, db_lockmode_t));
668*7c478bd9Sstevel@tonic-gate  */
669*7c478bd9Sstevel@tonic-gate int
__lock_is_locked(lt,locker,dbt,mode)670*7c478bd9Sstevel@tonic-gate __lock_is_locked(lt, locker, dbt, mode)
671*7c478bd9Sstevel@tonic-gate 	DB_LOCKTAB *lt;
672*7c478bd9Sstevel@tonic-gate 	u_int32_t locker;
673*7c478bd9Sstevel@tonic-gate 	DBT *dbt;
674*7c478bd9Sstevel@tonic-gate 	db_lockmode_t mode;
675*7c478bd9Sstevel@tonic-gate {
676*7c478bd9Sstevel@tonic-gate 	struct __db_lock *lp;
677*7c478bd9Sstevel@tonic-gate 	DB_LOCKOBJ *sh_obj;
678*7c478bd9Sstevel@tonic-gate 	DB_LOCKREGION *lrp;
679*7c478bd9Sstevel@tonic-gate 
680*7c478bd9Sstevel@tonic-gate 	lrp = lt->region;
681*7c478bd9Sstevel@tonic-gate 
682*7c478bd9Sstevel@tonic-gate 	/* Look up the object in the hash table. */
683*7c478bd9Sstevel@tonic-gate 	HASHLOOKUP(lt->hashtab, __db_lockobj, links,
684*7c478bd9Sstevel@tonic-gate 	    dbt, sh_obj, lrp->table_size, __lock_ohash, __lock_cmp);
685*7c478bd9Sstevel@tonic-gate 	if (sh_obj == NULL)
686*7c478bd9Sstevel@tonic-gate 		return (0);
687*7c478bd9Sstevel@tonic-gate 
688*7c478bd9Sstevel@tonic-gate 	for (lp = SH_TAILQ_FIRST(&sh_obj->holders, __db_lock);
689*7c478bd9Sstevel@tonic-gate 	    lp != NULL;
690*7c478bd9Sstevel@tonic-gate 	    lp = SH_TAILQ_FIRST(&sh_obj->holders, __db_lock)) {
691*7c478bd9Sstevel@tonic-gate 		if (lp->holder == locker && lp->mode == mode)
692*7c478bd9Sstevel@tonic-gate 			return (1);
693*7c478bd9Sstevel@tonic-gate 	}
694*7c478bd9Sstevel@tonic-gate 
695*7c478bd9Sstevel@tonic-gate 	return (0);
696*7c478bd9Sstevel@tonic-gate }
697*7c478bd9Sstevel@tonic-gate 
698*7c478bd9Sstevel@tonic-gate /*
699*7c478bd9Sstevel@tonic-gate  * __lock_printlock --
700*7c478bd9Sstevel@tonic-gate  *
701*7c478bd9Sstevel@tonic-gate  * PUBLIC: void __lock_printlock __P((DB_LOCKTAB *, struct __db_lock *, int));
702*7c478bd9Sstevel@tonic-gate  */
703*7c478bd9Sstevel@tonic-gate void
__lock_printlock(lt,lp,ispgno)704*7c478bd9Sstevel@tonic-gate __lock_printlock(lt, lp, ispgno)
705*7c478bd9Sstevel@tonic-gate 	DB_LOCKTAB *lt;
706*7c478bd9Sstevel@tonic-gate 	struct __db_lock *lp;
707*7c478bd9Sstevel@tonic-gate 	int ispgno;
708*7c478bd9Sstevel@tonic-gate {
709*7c478bd9Sstevel@tonic-gate 	DB_LOCKOBJ *lockobj;
710*7c478bd9Sstevel@tonic-gate 	db_pgno_t pgno;
711*7c478bd9Sstevel@tonic-gate 	size_t obj;
712*7c478bd9Sstevel@tonic-gate 	u_int8_t *ptr;
713*7c478bd9Sstevel@tonic-gate 	const char *mode, *status;
714*7c478bd9Sstevel@tonic-gate 
715*7c478bd9Sstevel@tonic-gate 	switch (lp->mode) {
716*7c478bd9Sstevel@tonic-gate 	case DB_LOCK_IREAD:
717*7c478bd9Sstevel@tonic-gate 		mode = "IREAD";
718*7c478bd9Sstevel@tonic-gate 		break;
719*7c478bd9Sstevel@tonic-gate 	case DB_LOCK_IWR:
720*7c478bd9Sstevel@tonic-gate 		mode = "IWR";
721*7c478bd9Sstevel@tonic-gate 		break;
722*7c478bd9Sstevel@tonic-gate 	case DB_LOCK_IWRITE:
723*7c478bd9Sstevel@tonic-gate 		mode = "IWRITE";
724*7c478bd9Sstevel@tonic-gate 		break;
725*7c478bd9Sstevel@tonic-gate 	case DB_LOCK_NG:
726*7c478bd9Sstevel@tonic-gate 		mode = "NG";
727*7c478bd9Sstevel@tonic-gate 		break;
728*7c478bd9Sstevel@tonic-gate 	case DB_LOCK_READ:
729*7c478bd9Sstevel@tonic-gate 		mode = "READ";
730*7c478bd9Sstevel@tonic-gate 		break;
731*7c478bd9Sstevel@tonic-gate 	case DB_LOCK_WRITE:
732*7c478bd9Sstevel@tonic-gate 		mode = "WRITE";
733*7c478bd9Sstevel@tonic-gate 		break;
734*7c478bd9Sstevel@tonic-gate 	default:
735*7c478bd9Sstevel@tonic-gate 		mode = "UNKNOWN";
736*7c478bd9Sstevel@tonic-gate 		break;
737*7c478bd9Sstevel@tonic-gate 	}
738*7c478bd9Sstevel@tonic-gate 	switch (lp->status) {
739*7c478bd9Sstevel@tonic-gate 	case DB_LSTAT_ABORTED:
740*7c478bd9Sstevel@tonic-gate 		status = "ABORT";
741*7c478bd9Sstevel@tonic-gate 		break;
742*7c478bd9Sstevel@tonic-gate 	case DB_LSTAT_ERR:
743*7c478bd9Sstevel@tonic-gate 		status = "ERROR";
744*7c478bd9Sstevel@tonic-gate 		break;
745*7c478bd9Sstevel@tonic-gate 	case DB_LSTAT_FREE:
746*7c478bd9Sstevel@tonic-gate 		status = "FREE";
747*7c478bd9Sstevel@tonic-gate 		break;
748*7c478bd9Sstevel@tonic-gate 	case DB_LSTAT_HELD:
749*7c478bd9Sstevel@tonic-gate 		status = "HELD";
750*7c478bd9Sstevel@tonic-gate 		break;
751*7c478bd9Sstevel@tonic-gate 	case DB_LSTAT_NOGRANT:
752*7c478bd9Sstevel@tonic-gate 		status = "NONE";
753*7c478bd9Sstevel@tonic-gate 		break;
754*7c478bd9Sstevel@tonic-gate 	case DB_LSTAT_WAITING:
755*7c478bd9Sstevel@tonic-gate 		status = "WAIT";
756*7c478bd9Sstevel@tonic-gate 		break;
757*7c478bd9Sstevel@tonic-gate 	case DB_LSTAT_PENDING:
758*7c478bd9Sstevel@tonic-gate 		status = "PENDING";
759*7c478bd9Sstevel@tonic-gate 		break;
760*7c478bd9Sstevel@tonic-gate 	default:
761*7c478bd9Sstevel@tonic-gate 		status = "UNKNOWN";
762*7c478bd9Sstevel@tonic-gate 		break;
763*7c478bd9Sstevel@tonic-gate 	}
764*7c478bd9Sstevel@tonic-gate 	printf("\t%lx\t%s\t%lu\t%s\t",
765*7c478bd9Sstevel@tonic-gate 	    (u_long)lp->holder, mode, (u_long)lp->refcount, status);
766*7c478bd9Sstevel@tonic-gate 
767*7c478bd9Sstevel@tonic-gate 	lockobj = (DB_LOCKOBJ *)((u_int8_t *)lp + lp->obj);
768*7c478bd9Sstevel@tonic-gate 	ptr = SH_DBT_PTR(&lockobj->lockobj);
769*7c478bd9Sstevel@tonic-gate 	if (ispgno) {
770*7c478bd9Sstevel@tonic-gate 		/* Assume this is a DBT lock. */
771*7c478bd9Sstevel@tonic-gate 		memcpy(&pgno, ptr, sizeof(db_pgno_t));
772*7c478bd9Sstevel@tonic-gate 		printf("page %lu\n", (u_long)pgno);
773*7c478bd9Sstevel@tonic-gate 	} else {
774*7c478bd9Sstevel@tonic-gate 		obj = (u_int8_t *)lp + lp->obj - (u_int8_t *)lt->region;
775*7c478bd9Sstevel@tonic-gate 		printf("0x%lx ", (u_long)obj);
776*7c478bd9Sstevel@tonic-gate 		__db_pr(ptr, lockobj->lockobj.size);
777*7c478bd9Sstevel@tonic-gate 		printf("\n");
778*7c478bd9Sstevel@tonic-gate 	}
779*7c478bd9Sstevel@tonic-gate }
780*7c478bd9Sstevel@tonic-gate 
781*7c478bd9Sstevel@tonic-gate /*
782*7c478bd9Sstevel@tonic-gate  * PUBLIC: int __lock_getobj  __P((DB_LOCKTAB *,
783*7c478bd9Sstevel@tonic-gate  * PUBLIC:     u_int32_t, const DBT *, u_int32_t type, DB_LOCKOBJ **));
784*7c478bd9Sstevel@tonic-gate  */
785*7c478bd9Sstevel@tonic-gate int
__lock_getobj(lt,locker,dbt,type,objp)786*7c478bd9Sstevel@tonic-gate __lock_getobj(lt, locker, dbt, type, objp)
787*7c478bd9Sstevel@tonic-gate 	DB_LOCKTAB *lt;
788*7c478bd9Sstevel@tonic-gate 	u_int32_t locker, type;
789*7c478bd9Sstevel@tonic-gate 	const DBT *dbt;
790*7c478bd9Sstevel@tonic-gate 	DB_LOCKOBJ **objp;
791*7c478bd9Sstevel@tonic-gate {
792*7c478bd9Sstevel@tonic-gate 	DB_LOCKREGION *lrp;
793*7c478bd9Sstevel@tonic-gate 	DB_LOCKOBJ *sh_obj;
794*7c478bd9Sstevel@tonic-gate 	u_int32_t obj_size;
795*7c478bd9Sstevel@tonic-gate 	int ret;
796*7c478bd9Sstevel@tonic-gate 	void *p, *src;
797*7c478bd9Sstevel@tonic-gate 
798*7c478bd9Sstevel@tonic-gate 	lrp = lt->region;
799*7c478bd9Sstevel@tonic-gate 
800*7c478bd9Sstevel@tonic-gate 	/* Look up the object in the hash table. */
801*7c478bd9Sstevel@tonic-gate 	if (type == DB_LOCK_OBJTYPE) {
802*7c478bd9Sstevel@tonic-gate 		HASHLOOKUP(lt->hashtab, __db_lockobj, links, dbt, sh_obj,
803*7c478bd9Sstevel@tonic-gate 		    lrp->table_size, __lock_ohash, __lock_cmp);
804*7c478bd9Sstevel@tonic-gate 		obj_size = dbt->size;
805*7c478bd9Sstevel@tonic-gate 	} else {
806*7c478bd9Sstevel@tonic-gate 		HASHLOOKUP(lt->hashtab, __db_lockobj, links, locker,
807*7c478bd9Sstevel@tonic-gate 		    sh_obj, lrp->table_size, __lock_locker_hash,
808*7c478bd9Sstevel@tonic-gate 		    __lock_locker_cmp);
809*7c478bd9Sstevel@tonic-gate 		obj_size = sizeof(locker);
810*7c478bd9Sstevel@tonic-gate 	}
811*7c478bd9Sstevel@tonic-gate 
812*7c478bd9Sstevel@tonic-gate 	/*
813*7c478bd9Sstevel@tonic-gate 	 * If we found the object, then we can just return it.  If
814*7c478bd9Sstevel@tonic-gate 	 * we didn't find the object, then we need to create it.
815*7c478bd9Sstevel@tonic-gate 	 */
816*7c478bd9Sstevel@tonic-gate 	if (sh_obj == NULL) {
817*7c478bd9Sstevel@tonic-gate 		/* Create new object and then insert it into hash table. */
818*7c478bd9Sstevel@tonic-gate 		if ((sh_obj =
819*7c478bd9Sstevel@tonic-gate 		    SH_TAILQ_FIRST(&lrp->free_objs, __db_lockobj)) == NULL) {
820*7c478bd9Sstevel@tonic-gate 			if ((ret = __lock_grow_region(lt, DB_LOCK_OBJ, 0)) != 0)
821*7c478bd9Sstevel@tonic-gate 				return (ret);
822*7c478bd9Sstevel@tonic-gate 			lrp = lt->region;
823*7c478bd9Sstevel@tonic-gate 			sh_obj = SH_TAILQ_FIRST(&lrp->free_objs, __db_lockobj);
824*7c478bd9Sstevel@tonic-gate 		}
825*7c478bd9Sstevel@tonic-gate 
826*7c478bd9Sstevel@tonic-gate 		/*
827*7c478bd9Sstevel@tonic-gate 		 * If we can fit this object in the structure, do so instead
828*7c478bd9Sstevel@tonic-gate 		 * of shalloc-ing space for it.
829*7c478bd9Sstevel@tonic-gate 		 */
830*7c478bd9Sstevel@tonic-gate 		if (obj_size <= sizeof(sh_obj->objdata))
831*7c478bd9Sstevel@tonic-gate 			p = sh_obj->objdata;
832*7c478bd9Sstevel@tonic-gate 		else
833*7c478bd9Sstevel@tonic-gate 			if ((ret =
834*7c478bd9Sstevel@tonic-gate 			    __db_shalloc(lt->mem, obj_size, 0, &p)) != 0) {
835*7c478bd9Sstevel@tonic-gate 				if ((ret = __lock_grow_region(lt,
836*7c478bd9Sstevel@tonic-gate 				    DB_LOCK_MEM, obj_size)) != 0)
837*7c478bd9Sstevel@tonic-gate 					return (ret);
838*7c478bd9Sstevel@tonic-gate 				lrp = lt->region;
839*7c478bd9Sstevel@tonic-gate 				/* Reacquire the head of the list. */
840*7c478bd9Sstevel@tonic-gate 				sh_obj = SH_TAILQ_FIRST(&lrp->free_objs,
841*7c478bd9Sstevel@tonic-gate 				    __db_lockobj);
842*7c478bd9Sstevel@tonic-gate 				(void)__db_shalloc(lt->mem, obj_size, 0, &p);
843*7c478bd9Sstevel@tonic-gate 			}
844*7c478bd9Sstevel@tonic-gate 
845*7c478bd9Sstevel@tonic-gate 		src = type == DB_LOCK_OBJTYPE ? dbt->data : (void *)&locker;
846*7c478bd9Sstevel@tonic-gate 		memcpy(p, src, obj_size);
847*7c478bd9Sstevel@tonic-gate 
848*7c478bd9Sstevel@tonic-gate 		sh_obj->type = type;
849*7c478bd9Sstevel@tonic-gate 		SH_TAILQ_REMOVE(&lrp->free_objs, sh_obj, links, __db_lockobj);
850*7c478bd9Sstevel@tonic-gate 
851*7c478bd9Sstevel@tonic-gate 		SH_TAILQ_INIT(&sh_obj->waiters);
852*7c478bd9Sstevel@tonic-gate 		if (type == DB_LOCK_LOCKER)
853*7c478bd9Sstevel@tonic-gate 			SH_LIST_INIT(&sh_obj->heldby);
854*7c478bd9Sstevel@tonic-gate 		else
855*7c478bd9Sstevel@tonic-gate 			SH_TAILQ_INIT(&sh_obj->holders);
856*7c478bd9Sstevel@tonic-gate 		sh_obj->lockobj.size = obj_size;
857*7c478bd9Sstevel@tonic-gate 		sh_obj->lockobj.off = SH_PTR_TO_OFF(&sh_obj->lockobj, p);
858*7c478bd9Sstevel@tonic-gate 
859*7c478bd9Sstevel@tonic-gate 		HASHINSERT(lt->hashtab,
860*7c478bd9Sstevel@tonic-gate 		    __db_lockobj, links, sh_obj, lrp->table_size, __lock_lhash);
861*7c478bd9Sstevel@tonic-gate 
862*7c478bd9Sstevel@tonic-gate 		if (type == DB_LOCK_LOCKER)
863*7c478bd9Sstevel@tonic-gate 			lrp->nlockers++;
864*7c478bd9Sstevel@tonic-gate 	}
865*7c478bd9Sstevel@tonic-gate 
866*7c478bd9Sstevel@tonic-gate 	*objp = sh_obj;
867*7c478bd9Sstevel@tonic-gate 	return (0);
868*7c478bd9Sstevel@tonic-gate }
869*7c478bd9Sstevel@tonic-gate 
870*7c478bd9Sstevel@tonic-gate /*
871*7c478bd9Sstevel@tonic-gate  * Any lock on the waitlist has a process waiting for it.  Therefore, we
872*7c478bd9Sstevel@tonic-gate  * can't return the lock to the freelist immediately.  Instead, we can
873*7c478bd9Sstevel@tonic-gate  * remove the lock from the list of waiters, set the status field of the
874*7c478bd9Sstevel@tonic-gate  * lock, and then let the process waking up return the lock to the
875*7c478bd9Sstevel@tonic-gate  * free list.
876*7c478bd9Sstevel@tonic-gate  */
877*7c478bd9Sstevel@tonic-gate static void
__lock_remove_waiter(lt,sh_obj,lockp,status)878*7c478bd9Sstevel@tonic-gate __lock_remove_waiter(lt, sh_obj, lockp, status)
879*7c478bd9Sstevel@tonic-gate 	DB_LOCKTAB *lt;
880*7c478bd9Sstevel@tonic-gate 	DB_LOCKOBJ *sh_obj;
881*7c478bd9Sstevel@tonic-gate 	struct __db_lock *lockp;
882*7c478bd9Sstevel@tonic-gate 	db_status_t status;
883*7c478bd9Sstevel@tonic-gate {
884*7c478bd9Sstevel@tonic-gate 	SH_TAILQ_REMOVE(&sh_obj->waiters, lockp, links, __db_lock);
885*7c478bd9Sstevel@tonic-gate 	lockp->status = status;
886*7c478bd9Sstevel@tonic-gate 
887*7c478bd9Sstevel@tonic-gate 	/* Wake whoever is waiting on this lock. */
888*7c478bd9Sstevel@tonic-gate 	(void)__db_mutex_unlock(&lockp->mutex, lt->reginfo.fd);
889*7c478bd9Sstevel@tonic-gate }
890*7c478bd9Sstevel@tonic-gate 
891*7c478bd9Sstevel@tonic-gate static void
__lock_checklocker(lt,lockp,do_remove)892*7c478bd9Sstevel@tonic-gate __lock_checklocker(lt, lockp, do_remove)
893*7c478bd9Sstevel@tonic-gate 	DB_LOCKTAB *lt;
894*7c478bd9Sstevel@tonic-gate 	struct __db_lock *lockp;
895*7c478bd9Sstevel@tonic-gate 	int do_remove;
896*7c478bd9Sstevel@tonic-gate {
897*7c478bd9Sstevel@tonic-gate 	DB_LOCKOBJ *sh_locker;
898*7c478bd9Sstevel@tonic-gate 
899*7c478bd9Sstevel@tonic-gate 	if (do_remove)
900*7c478bd9Sstevel@tonic-gate 		SH_LIST_REMOVE(lockp, locker_links, __db_lock);
901*7c478bd9Sstevel@tonic-gate 
902*7c478bd9Sstevel@tonic-gate 	/* if the locker list is NULL, free up the object. */
903*7c478bd9Sstevel@tonic-gate 	if (__lock_getobj(lt, lockp->holder, NULL, DB_LOCK_LOCKER, &sh_locker)
904*7c478bd9Sstevel@tonic-gate 	    == 0 && SH_LIST_FIRST(&sh_locker->heldby, __db_lock) == NULL) {
905*7c478bd9Sstevel@tonic-gate 		__lock_freeobj(lt, sh_locker);
906*7c478bd9Sstevel@tonic-gate 		    lt->region->nlockers--;
907*7c478bd9Sstevel@tonic-gate 	}
908*7c478bd9Sstevel@tonic-gate }
909*7c478bd9Sstevel@tonic-gate 
910*7c478bd9Sstevel@tonic-gate static void
__lock_freeobj(lt,obj)911*7c478bd9Sstevel@tonic-gate __lock_freeobj(lt, obj)
912*7c478bd9Sstevel@tonic-gate 	DB_LOCKTAB *lt;
913*7c478bd9Sstevel@tonic-gate 	DB_LOCKOBJ *obj;
914*7c478bd9Sstevel@tonic-gate {
915*7c478bd9Sstevel@tonic-gate 	HASHREMOVE_EL(lt->hashtab,
916*7c478bd9Sstevel@tonic-gate 	    __db_lockobj, links, obj, lt->region->table_size, __lock_lhash);
917*7c478bd9Sstevel@tonic-gate 	if (obj->lockobj.size > sizeof(obj->objdata))
918*7c478bd9Sstevel@tonic-gate 		__db_shalloc_free(lt->mem, SH_DBT_PTR(&obj->lockobj));
919*7c478bd9Sstevel@tonic-gate 	SH_TAILQ_INSERT_HEAD(&lt->region->free_objs, obj, links, __db_lockobj);
920*7c478bd9Sstevel@tonic-gate }
921*7c478bd9Sstevel@tonic-gate 
922*7c478bd9Sstevel@tonic-gate /*
923*7c478bd9Sstevel@tonic-gate  * __lock_downgrade --
924*7c478bd9Sstevel@tonic-gate  *	Used by the concurrent access product to downgrade write locks
925*7c478bd9Sstevel@tonic-gate  * back to iwrite locks.
926*7c478bd9Sstevel@tonic-gate  *
927*7c478bd9Sstevel@tonic-gate  * PUBLIC: int __lock_downgrade __P((DB_LOCKTAB *,
928*7c478bd9Sstevel@tonic-gate  * PUBLIC:     DB_LOCK, db_lockmode_t, u_int32_t));
929*7c478bd9Sstevel@tonic-gate  */
930*7c478bd9Sstevel@tonic-gate int
__lock_downgrade(lt,lock,new_mode,flags)931*7c478bd9Sstevel@tonic-gate __lock_downgrade(lt, lock, new_mode, flags)
932*7c478bd9Sstevel@tonic-gate 	DB_LOCKTAB *lt;
933*7c478bd9Sstevel@tonic-gate 	DB_LOCK lock;
934*7c478bd9Sstevel@tonic-gate 	db_lockmode_t new_mode;
935*7c478bd9Sstevel@tonic-gate 	u_int32_t flags;
936*7c478bd9Sstevel@tonic-gate {
937*7c478bd9Sstevel@tonic-gate 	struct __db_lock *lockp;
938*7c478bd9Sstevel@tonic-gate 	DB_LOCKOBJ *obj;
939*7c478bd9Sstevel@tonic-gate 	int ret;
940*7c478bd9Sstevel@tonic-gate 
941*7c478bd9Sstevel@tonic-gate 	COMPQUIET(flags, 0);
942*7c478bd9Sstevel@tonic-gate 	LOCK_PANIC_CHECK(lt);
943*7c478bd9Sstevel@tonic-gate 	LOCK_LOCKREGION(lt);
944*7c478bd9Sstevel@tonic-gate 
945*7c478bd9Sstevel@tonic-gate 	if ((ret = __lock_validate_region(lt)) == 0) {
946*7c478bd9Sstevel@tonic-gate 		lockp = OFFSET_TO_LOCK(lt, lock);
947*7c478bd9Sstevel@tonic-gate 		lockp->mode = new_mode;
948*7c478bd9Sstevel@tonic-gate 
949*7c478bd9Sstevel@tonic-gate 		/* Get the object associated with this lock. */
950*7c478bd9Sstevel@tonic-gate 		obj = (DB_LOCKOBJ *)((u_int8_t *)lockp + lockp->obj);
951*7c478bd9Sstevel@tonic-gate 		(void)__lock_promote(lt, obj);
952*7c478bd9Sstevel@tonic-gate 		++lt->region->nreleases;
953*7c478bd9Sstevel@tonic-gate 	}
954*7c478bd9Sstevel@tonic-gate 
955*7c478bd9Sstevel@tonic-gate 	UNLOCK_LOCKREGION(lt);
956*7c478bd9Sstevel@tonic-gate 
957*7c478bd9Sstevel@tonic-gate 	return (ret);
958*7c478bd9Sstevel@tonic-gate }
959*7c478bd9Sstevel@tonic-gate 
960*7c478bd9Sstevel@tonic-gate /*
961*7c478bd9Sstevel@tonic-gate  * __lock_promote --
962*7c478bd9Sstevel@tonic-gate  *
963*7c478bd9Sstevel@tonic-gate  * Look through the waiters and holders lists and decide which (if any)
964*7c478bd9Sstevel@tonic-gate  * locks can be promoted.   Promote any that are eligible.
965*7c478bd9Sstevel@tonic-gate  */
966*7c478bd9Sstevel@tonic-gate static int
__lock_promote(lt,obj)967*7c478bd9Sstevel@tonic-gate __lock_promote(lt, obj)
968*7c478bd9Sstevel@tonic-gate 	DB_LOCKTAB *lt;
969*7c478bd9Sstevel@tonic-gate 	DB_LOCKOBJ *obj;
970*7c478bd9Sstevel@tonic-gate {
971*7c478bd9Sstevel@tonic-gate 	struct __db_lock *lp_w, *lp_h, *next_waiter;
972*7c478bd9Sstevel@tonic-gate 	int state_changed, waiter_is_txn;
973*7c478bd9Sstevel@tonic-gate 
974*7c478bd9Sstevel@tonic-gate 	/*
975*7c478bd9Sstevel@tonic-gate 	 * We need to do lock promotion.  We also need to determine if
976*7c478bd9Sstevel@tonic-gate 	 * we're going to need to run the deadlock detector again.  If
977*7c478bd9Sstevel@tonic-gate 	 * we release locks, and there are waiters, but no one gets promoted,
978*7c478bd9Sstevel@tonic-gate 	 * then we haven't fundamentally changed the lockmgr state, so
979*7c478bd9Sstevel@tonic-gate 	 * we may still have a deadlock and we have to run again.  However,
980*7c478bd9Sstevel@tonic-gate 	 * if there were no waiters, or we actually promoted someone, then
981*7c478bd9Sstevel@tonic-gate 	 * we are OK and we don't have to run it immediately.
982*7c478bd9Sstevel@tonic-gate 	 *
983*7c478bd9Sstevel@tonic-gate 	 * During promotion, we look for state changes so we can return
984*7c478bd9Sstevel@tonic-gate 	 * this information to the caller.
985*7c478bd9Sstevel@tonic-gate 	 */
986*7c478bd9Sstevel@tonic-gate 	for (lp_w = SH_TAILQ_FIRST(&obj->waiters, __db_lock),
987*7c478bd9Sstevel@tonic-gate 	    state_changed = lp_w == NULL;
988*7c478bd9Sstevel@tonic-gate 	    lp_w != NULL;
989*7c478bd9Sstevel@tonic-gate 	    lp_w = next_waiter) {
990*7c478bd9Sstevel@tonic-gate 		waiter_is_txn = TXN_IS_HOLDING(lp_w);
991*7c478bd9Sstevel@tonic-gate 		next_waiter = SH_TAILQ_NEXT(lp_w, links, __db_lock);
992*7c478bd9Sstevel@tonic-gate 		for (lp_h = SH_TAILQ_FIRST(&obj->holders, __db_lock);
993*7c478bd9Sstevel@tonic-gate 		    lp_h != NULL;
994*7c478bd9Sstevel@tonic-gate 		    lp_h = SH_TAILQ_NEXT(lp_h, links, __db_lock)) {
995*7c478bd9Sstevel@tonic-gate 			if (CONFLICTS(lt, lp_h->mode, lp_w->mode) &&
996*7c478bd9Sstevel@tonic-gate 			    lp_h->holder != lp_w->holder &&
997*7c478bd9Sstevel@tonic-gate 			    !(waiter_is_txn &&
998*7c478bd9Sstevel@tonic-gate 			    TXN_IS_HOLDING(lp_h) &&
999*7c478bd9Sstevel@tonic-gate 			    __txn_is_ancestor(lt->dbenv->tx_info,
1000*7c478bd9Sstevel@tonic-gate 			        lp_h->txnoff, lp_w->txnoff)))
1001*7c478bd9Sstevel@tonic-gate 				break;
1002*7c478bd9Sstevel@tonic-gate 		}
1003*7c478bd9Sstevel@tonic-gate 		if (lp_h != NULL)	/* Found a conflict. */
1004*7c478bd9Sstevel@tonic-gate 			break;
1005*7c478bd9Sstevel@tonic-gate 
1006*7c478bd9Sstevel@tonic-gate 		/* No conflict, promote the waiting lock. */
1007*7c478bd9Sstevel@tonic-gate 		SH_TAILQ_REMOVE(&obj->waiters, lp_w, links, __db_lock);
1008*7c478bd9Sstevel@tonic-gate 		lp_w->status = DB_LSTAT_PENDING;
1009*7c478bd9Sstevel@tonic-gate 		SH_TAILQ_INSERT_TAIL(&obj->holders, lp_w, links);
1010*7c478bd9Sstevel@tonic-gate 
1011*7c478bd9Sstevel@tonic-gate 		/* Wake up waiter. */
1012*7c478bd9Sstevel@tonic-gate 		(void)__db_mutex_unlock(&lp_w->mutex, lt->reginfo.fd);
1013*7c478bd9Sstevel@tonic-gate 		state_changed = 1;
1014*7c478bd9Sstevel@tonic-gate 	}
1015*7c478bd9Sstevel@tonic-gate 
1016*7c478bd9Sstevel@tonic-gate 	return (state_changed);
1017*7c478bd9Sstevel@tonic-gate }
1018*7c478bd9Sstevel@tonic-gate 
1019*7c478bd9Sstevel@tonic-gate static int
__lock_is_parent(locker,txn)1020*7c478bd9Sstevel@tonic-gate __lock_is_parent(locker, txn)
1021*7c478bd9Sstevel@tonic-gate 	u_int32_t locker;
1022*7c478bd9Sstevel@tonic-gate 	DB_TXN *txn;
1023*7c478bd9Sstevel@tonic-gate {
1024*7c478bd9Sstevel@tonic-gate 	DB_TXN *t;
1025*7c478bd9Sstevel@tonic-gate 
1026*7c478bd9Sstevel@tonic-gate 	if (txn == NULL)
1027*7c478bd9Sstevel@tonic-gate 		return (0);
1028*7c478bd9Sstevel@tonic-gate 
1029*7c478bd9Sstevel@tonic-gate 	for (t = txn->parent; t != NULL; t = t->parent)
1030*7c478bd9Sstevel@tonic-gate 		if (t->txnid == locker)
1031*7c478bd9Sstevel@tonic-gate 			return (1);
1032*7c478bd9Sstevel@tonic-gate 
1033*7c478bd9Sstevel@tonic-gate 	return (0);
1034*7c478bd9Sstevel@tonic-gate }
1035