]>
git.ipfire.org Git - thirdparty/glibc.git/blob - db2/lock/lock.c
2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 1996, 1997
5 * Sleepycat Software. All rights reserved.
11 static const char sccsid
[] = "@(#)lock.c 10.43 (Sleepycat) 1/8/98";
14 #ifndef NO_SYSTEM_INCLUDES
15 #include <sys/types.h>
33 #include "common_ext.h"
36 static void __lock_checklocker
__P((DB_LOCKTAB
*, struct __db_lock
*, int));
37 static int __lock_count_locks
__P((DB_LOCKREGION
*));
38 static int __lock_count_objs
__P((DB_LOCKREGION
*));
39 static int __lock_create
__P((const char *, int, DB_ENV
*));
40 static void __lock_freeobj
__P((DB_LOCKTAB
*, DB_LOCKOBJ
*));
41 static int __lock_get_internal
__P((DB_LOCKTAB
*, u_int32_t
, int, const DBT
*,
42 db_lockmode_t
, struct __db_lock
**));
43 static int __lock_grow_region
__P((DB_LOCKTAB
*, int, size_t));
44 static int __lock_put_internal
__P((DB_LOCKTAB
*, struct __db_lock
*, int));
45 static void __lock_remove_waiter
46 __P((DB_LOCKTAB
*, DB_LOCKOBJ
*, struct __db_lock
*, db_status_t
));
47 static void __lock_reset_region
__P((DB_LOCKTAB
*));
48 static int __lock_validate_region
__P((DB_LOCKTAB
*));
50 static void __lock_dump_locker
__P((DB_LOCKTAB
*, DB_LOCKOBJ
*));
51 static void __lock_dump_object
__P((DB_LOCKTAB
*, DB_LOCKOBJ
*));
52 static void __lock_printlock
__P((DB_LOCKTAB
*, struct __db_lock
*, int));
56 * Create and initialize a lock region in shared memory.
61 * Create the lock region. Returns an errno. In most cases,
62 * the errno should be that returned by __db_ropen, in which case
63 * an EAGAIN means that we should retry, and an EEXIST means that
64 * the region exists and we didn't need to create it. Any other
65 * sort of errno should be treated as a system error, leading to a
66 * failure of the original interface call.
69 __lock_create(path
, mode
, dbenv
)
75 struct lock_header
*tq_head
;
76 struct obj_header
*obj_head
;
81 int fd
, lock_modes
, nelements
, ret
;
82 const u_int8_t
*conflicts
;
85 maxlocks
= dbenv
== NULL
|| dbenv
->lk_max
== 0 ?
86 DB_LOCK_DEFAULT_N
: dbenv
->lk_max
;
87 lock_modes
= dbenv
== NULL
|| dbenv
->lk_modes
== 0 ?
88 DB_LOCK_RW_N
: dbenv
->lk_modes
;
89 conflicts
= dbenv
== NULL
|| dbenv
->lk_conflicts
== NULL
?
90 db_rw_conflicts
: dbenv
->lk_conflicts
;
93 __db_rcreate(dbenv
, DB_APP_NONE
, path
, DB_DEFAULT_LOCK_FILE
, mode
,
94 LOCK_REGION_SIZE(lock_modes
, maxlocks
, __db_tablesize(maxlocks
)),
98 /* Region exists; now initialize it. */
99 lrp
->table_size
= __db_tablesize(maxlocks
);
100 lrp
->magic
= DB_LOCKMAGIC
;
101 lrp
->version
= DB_LOCKVERSION
;
103 lrp
->maxlocks
= maxlocks
;
105 lrp
->detect
= DB_LOCK_NORUN
;
106 lrp
->numobjs
= maxlocks
;
108 lrp
->mem_bytes
= ALIGN(STRING_SIZE(maxlocks
), sizeof(size_t));
109 lrp
->increment
= lrp
->hdr
.size
/ 2;
110 lrp
->nmodes
= lock_modes
;
117 * As we write the region, we've got to maintain the alignment
118 * for the structures that follow each chunk. This information
119 * ends up being encapsulated both in here as well as in the
120 * lock.h file for the XXX_SIZE macros.
122 /* Initialize conflict matrix. */
123 curaddr
= (u_int8_t
*)lrp
+ sizeof(DB_LOCKREGION
);
124 memcpy(curaddr
, conflicts
, lock_modes
* lock_modes
);
125 curaddr
+= lock_modes
* lock_modes
;
128 * Initialize hash table.
130 curaddr
= (u_int8_t
*)ALIGNP(curaddr
, LOCK_HASH_ALIGN
);
131 lrp
->hash_off
= curaddr
- (u_int8_t
*)lrp
;
132 nelements
= lrp
->table_size
;
133 __db_hashinit(curaddr
, nelements
);
134 curaddr
+= nelements
* sizeof(DB_HASHTAB
);
137 * Initialize locks onto a free list. Since locks contains mutexes,
138 * we need to make sure that each lock is aligned on a MUTEX_ALIGNMENT
141 curaddr
= (u_int8_t
*)ALIGNP(curaddr
, MUTEX_ALIGNMENT
);
142 tq_head
= &lrp
->free_locks
;
143 SH_TAILQ_INIT(tq_head
);
145 for (i
= 0; i
++ < maxlocks
;
146 curaddr
+= ALIGN(sizeof(struct __db_lock
), MUTEX_ALIGNMENT
)) {
147 lp
= (struct __db_lock
*)curaddr
;
148 lp
->status
= DB_LSTAT_FREE
;
149 SH_TAILQ_INSERT_HEAD(tq_head
, lp
, links
, __db_lock
);
152 /* Initialize objects onto a free list. */
153 obj_head
= &lrp
->free_objs
;
154 SH_TAILQ_INIT(obj_head
);
156 for (i
= 0; i
++ < maxlocks
; curaddr
+= sizeof(DB_LOCKOBJ
)) {
157 op
= (DB_LOCKOBJ
*)curaddr
;
158 SH_TAILQ_INSERT_HEAD(obj_head
, op
, links
, __db_lockobj
);
162 * Initialize the string space; as for all shared memory allocation
163 * regions, this requires size_t alignment, since we store the
164 * lengths of malloc'd areas in the area..
166 curaddr
= (u_int8_t
*)ALIGNP(curaddr
, sizeof(size_t));
167 lrp
->mem_off
= curaddr
- (u_int8_t
*)lrp
;
168 __db_shalloc_init(curaddr
, lrp
->mem_bytes
);
170 /* Release the lock. */
171 (void)__db_mutex_unlock(&lrp
->hdr
.lock
, fd
);
173 /* Now unmap the region. */
174 if ((ret
= __db_rclose(dbenv
, fd
, lrp
)) != 0) {
175 (void)lock_unlink(path
, 1 /* force */, dbenv
);
183 lock_open(path
, flags
, mode
, dbenv
, ltp
)
192 /* Validate arguments. */
193 #ifdef HAVE_SPINLOCKS
194 #define OKFLAGS (DB_CREATE | DB_THREAD)
196 #define OKFLAGS (DB_CREATE)
198 if ((ret
= __db_fchk(dbenv
, "lock_open", flags
, OKFLAGS
)) != 0)
202 * Create the lock table structure.
204 if ((lt
= (DB_LOCKTAB
*)__db_calloc(1, sizeof(DB_LOCKTAB
))) == NULL
) {
205 __db_err(dbenv
, "%s", strerror(ENOMEM
));
211 * Now, create the lock region if it doesn't already exist.
214 retry
: if (LF_ISSET(DB_CREATE
) &&
215 (ret
= __lock_create(path
, mode
, dbenv
)) != 0)
216 if (ret
== EAGAIN
&& ++retry_cnt
< 3) {
217 (void)__db_sleep(1, 0);
219 } else if (ret
== EEXIST
) /* We did not create the region */
225 * Finally, open the region, map it in, and increment the
229 retry1
: if ((ret
= __db_ropen(dbenv
, DB_APP_NONE
, path
, DB_DEFAULT_LOCK_FILE
,
230 LF_ISSET(~(DB_CREATE
| DB_THREAD
)), <
->fd
, <
->region
)) != 0) {
231 if (ret
== EAGAIN
&& ++retry_cnt
< 3) {
232 (void)__db_sleep(1, 0);
238 if (lt
->region
->magic
!= DB_LOCKMAGIC
) {
239 __db_err(dbenv
, "lock_open: Bad magic number");
244 /* Check for automatic deadlock detection. */
245 if (dbenv
->lk_detect
!= DB_LOCK_NORUN
) {
246 if (lt
->region
->detect
!= DB_LOCK_NORUN
&&
247 dbenv
->lk_detect
!= DB_LOCK_DEFAULT
&&
248 lt
->region
->detect
!= dbenv
->lk_detect
) {
250 "lock_open: incompatible deadlock detector mode");
254 if (lt
->region
->detect
== DB_LOCK_NORUN
)
255 lt
->region
->detect
= dbenv
->lk_detect
;
258 /* Set up remaining pointers into region. */
259 lt
->conflicts
= (u_int8_t
*)lt
->region
+ sizeof(DB_LOCKREGION
);
261 (DB_HASHTAB
*)((u_int8_t
*)lt
->region
+ lt
->region
->hash_off
);
262 lt
->mem
= (void *)((u_int8_t
*)lt
->region
+ lt
->region
->mem_off
);
263 lt
->reg_size
= lt
->region
->hdr
.size
;
268 /* Error handling. */
269 out
: if (lt
->region
!= NULL
)
270 (void)__db_rclose(lt
->dbenv
, lt
->fd
, lt
->region
);
271 if (LF_ISSET(DB_CREATE
))
272 (void)lock_unlink(path
, 1, lt
->dbenv
);
285 if (lt
->region
->id
>= DB_LOCK_MAXID
)
287 id
= ++lt
->region
->id
;
288 UNLOCK_LOCKREGION(lt
);
295 lock_vec(lt
, locker
, flags
, list
, nlist
, elistp
)
299 DB_LOCKREQ
*list
, **elistp
;
301 struct __db_lock
*lp
;
302 DB_LOCKOBJ
*sh_obj
, *sh_locker
;
305 /* Validate arguments. */
307 __db_fchk(lt
->dbenv
, "lock_vec", flags
, DB_LOCK_NOWAIT
)) != 0)
312 if ((ret
= __lock_validate_region(lt
)) != 0) {
313 UNLOCK_LOCKREGION(lt
);
318 for (i
= 0; i
< nlist
&& ret
== 0; i
++) {
319 switch (list
[i
].op
) {
321 ret
= __lock_get_internal(lt
, locker
, flags
,
322 list
[i
].obj
, list
[i
].mode
, &lp
);
324 list
[i
].lock
= LOCK_TO_OFFSET(lt
, lp
);
325 lt
->region
->nrequests
++;
329 lp
= OFFSET_TO_LOCK(lt
, list
[i
].lock
);
330 if (lp
->holder
!= locker
) {
331 ret
= DB_LOCK_NOTHELD
;
334 list
[i
].mode
= lp
->mode
;
336 /* XXX Need to copy the object. ??? */
337 ret
= __lock_put_internal(lt
, lp
, 0);
339 case DB_LOCK_PUT_ALL
:
340 /* Find the locker. */
341 if ((ret
= __lock_getobj(lt
, locker
,
342 NULL
, DB_LOCK_LOCKER
, &sh_locker
)) != 0)
345 for (lp
= SH_LIST_FIRST(&sh_locker
->heldby
, __db_lock
);
347 lp
= SH_LIST_FIRST(&sh_locker
->heldby
, __db_lock
)) {
348 if ((ret
= __lock_put_internal(lt
, lp
, 0)) != 0)
351 __lock_freeobj(lt
, sh_locker
);
352 lt
->region
->nlockers
--;
354 case DB_LOCK_PUT_OBJ
:
356 /* Look up the object in the hash table. */
357 HASHLOOKUP(lt
->hashtab
, __db_lockobj
, links
,
358 list
[i
].obj
, sh_obj
, lt
->region
->table_size
,
359 __lock_ohash
, __lock_cmp
);
360 if (sh_obj
== NULL
) {
365 * Release waiters first, because they won't cause
366 * anyone else to be awakened. If we release the
367 * lockers first, all the waiters get awakened
370 for (lp
= SH_TAILQ_FIRST(&sh_obj
->waiters
, __db_lock
);
372 lp
= SH_TAILQ_FIRST(&sh_obj
->waiters
, __db_lock
)) {
373 lt
->region
->nreleases
+= lp
->refcount
;
374 __lock_remove_waiter(lt
, sh_obj
, lp
,
376 __lock_checklocker(lt
, lp
, 1);
379 for (lp
= SH_TAILQ_FIRST(&sh_obj
->holders
, __db_lock
);
381 lp
= SH_TAILQ_FIRST(&sh_obj
->holders
, __db_lock
)) {
383 lt
->region
->nreleases
+= lp
->refcount
;
384 SH_LIST_REMOVE(lp
, locker_links
, __db_lock
);
385 SH_TAILQ_REMOVE(&sh_obj
->holders
, lp
, links
,
387 lp
->status
= DB_LSTAT_FREE
;
388 SH_TAILQ_INSERT_HEAD(<
->region
->free_locks
,
389 lp
, links
, __db_lock
);
392 /* Now free the object. */
393 __lock_freeobj(lt
, sh_obj
);
397 /* Find the locker. */
398 if ((ret
= __lock_getobj(lt
, locker
,
399 NULL
, DB_LOCK_LOCKER
, &sh_locker
)) != 0)
402 for (lp
= SH_LIST_FIRST(&sh_locker
->heldby
, __db_lock
);
404 lp
= SH_LIST_NEXT(lp
, locker_links
, __db_lock
)) {
405 __lock_printlock(lt
, lp
, 1);
409 __lock_freeobj(lt
, sh_locker
);
410 lt
->region
->nlockers
--;
420 if (lt
->region
->need_dd
&& lt
->region
->detect
!= DB_LOCK_NORUN
) {
422 lt
->region
->need_dd
= 0;
426 UNLOCK_LOCKREGION(lt
);
428 if (ret
== 0 && run_dd
)
429 lock_detect(lt
, 0, lt
->region
->detect
);
431 if (elistp
&& ret
!= 0)
432 *elistp
= &list
[i
- 1];
437 lock_get(lt
, locker
, flags
, obj
, lock_mode
, lock
)
442 db_lockmode_t lock_mode
;
445 struct __db_lock
*lockp
;
448 /* Validate arguments. */
450 __db_fchk(lt
->dbenv
, "lock_get", flags
, DB_LOCK_NOWAIT
)) != 0)
455 ret
= __lock_validate_region(lt
);
456 if (ret
== 0 && (ret
= __lock_get_internal(lt
,
457 locker
, flags
, obj
, lock_mode
, &lockp
)) == 0) {
458 *lock
= LOCK_TO_OFFSET(lt
, lockp
);
459 lt
->region
->nrequests
++;
462 UNLOCK_LOCKREGION(lt
);
471 struct __db_lock
*lockp
;
476 if ((ret
= __lock_validate_region(lt
)) != 0)
479 lockp
= OFFSET_TO_LOCK(lt
, lock
);
480 ret
= __lock_put_internal(lt
, lockp
, 0);
483 __lock_checklocker(lt
, lockp
, 0);
485 if (lt
->region
->need_dd
&& lt
->region
->detect
!= DB_LOCK_NORUN
) {
487 lt
->region
->need_dd
= 0;
491 UNLOCK_LOCKREGION(lt
);
493 if (ret
== 0 && run_dd
)
494 lock_detect(lt
, 0, lt
->region
->detect
);
505 if ((ret
= __db_rclose(lt
->dbenv
, lt
->fd
, lt
->region
)) != 0)
508 /* Free lock table. */
514 lock_unlink(path
, force
, dbenv
)
519 return (__db_runlink(dbenv
,
520 DB_APP_NONE
, path
, DB_DEFAULT_LOCK_FILE
, force
));
524 * XXX This looks like it could be void, but I'm leaving it returning
525 * an int because I think it will have to when we go through and add
526 * the appropriate error checking for the EINTR on mutexes.
529 __lock_put_internal(lt
, lockp
, do_all
)
531 struct __db_lock
*lockp
;
534 struct __db_lock
*lp_w
, *lp_h
, *next_waiter
;
538 if (lockp
->refcount
== 0 || (lockp
->status
!= DB_LSTAT_HELD
&&
539 lockp
->status
!= DB_LSTAT_WAITING
) || lockp
->obj
== 0) {
540 __db_err(lt
->dbenv
, "lock_put: invalid lock %lu",
541 (u_long
)((u_int8_t
*)lockp
- (u_int8_t
*)lt
->region
));
546 lt
->region
->nreleases
+= lockp
->refcount
;
548 lt
->region
->nreleases
++;
549 if (do_all
== 0 && lockp
->refcount
> 1) {
554 /* Get the object associated with this lock. */
555 sh_obj
= (DB_LOCKOBJ
*)((u_int8_t
*)lockp
+ lockp
->obj
);
557 /* Remove lock from locker list. */
558 SH_LIST_REMOVE(lockp
, locker_links
, __db_lock
);
560 /* Remove this lock from its holders/waitlist. */
561 if (lockp
->status
!= DB_LSTAT_HELD
)
562 __lock_remove_waiter(lt
, sh_obj
, lockp
, DB_LSTAT_FREE
);
564 SH_TAILQ_REMOVE(&sh_obj
->holders
, lockp
, links
, __db_lock
);
567 * We need to do lock promotion. We also need to determine if
568 * we're going to need to run the deadlock detector again. If
569 * we release locks, and there are waiters, but no one gets promoted,
570 * then we haven't fundamentally changed the lockmgr state, so
571 * we may still have a deadlock and we have to run again. However,
572 * if there were no waiters, or we actually promoted someone, then
573 * we are OK and we don't have to run it immediately.
575 for (lp_w
= SH_TAILQ_FIRST(&sh_obj
->waiters
, __db_lock
),
576 state_changed
= lp_w
== NULL
;
578 lp_w
= next_waiter
) {
579 next_waiter
= SH_TAILQ_NEXT(lp_w
, links
, __db_lock
);
580 for (lp_h
= SH_TAILQ_FIRST(&sh_obj
->holders
, __db_lock
);
582 lp_h
= SH_TAILQ_NEXT(lp_h
, links
, __db_lock
)) {
583 if (CONFLICTS(lt
, lp_h
->mode
, lp_w
->mode
) &&
584 lp_h
->holder
!= lp_w
->holder
)
587 if (lp_h
!= NULL
) /* Found a conflict. */
590 /* No conflict, promote the waiting lock. */
591 SH_TAILQ_REMOVE(&sh_obj
->waiters
, lp_w
, links
, __db_lock
);
592 lp_w
->status
= DB_LSTAT_PENDING
;
593 SH_TAILQ_INSERT_TAIL(&sh_obj
->holders
, lp_w
, links
);
595 /* Wake up waiter. */
596 (void)__db_mutex_unlock(&lp_w
->mutex
, lt
->fd
);
600 /* Check if object should be reclaimed. */
601 if (SH_TAILQ_FIRST(&sh_obj
->holders
, __db_lock
) == NULL
) {
602 HASHREMOVE_EL(lt
->hashtab
, __db_lockobj
,
603 links
, sh_obj
, lt
->region
->table_size
, __lock_lhash
);
604 if (sh_obj
->lockobj
.size
> sizeof(sh_obj
->objdata
))
605 __db_shalloc_free(lt
->mem
,
606 SH_DBT_PTR(&sh_obj
->lockobj
));
607 SH_TAILQ_INSERT_HEAD(<
->region
->free_objs
, sh_obj
, links
,
613 lockp
->status
= DB_LSTAT_FREE
;
614 SH_TAILQ_INSERT_HEAD(<
->region
->free_locks
, lockp
, links
, __db_lock
);
617 * If we did not promote anyone; we need to run the deadlock
620 if (state_changed
== 0)
621 lt
->region
->need_dd
= 1;
627 __lock_get_internal(lt
, locker
, flags
, obj
, lock_mode
, lockp
)
632 db_lockmode_t lock_mode
;
633 struct __db_lock
**lockp
;
635 struct __db_lock
*newl
, *lp
;
636 DB_LOCKOBJ
*sh_obj
, *sh_locker
;
643 * Check that lock mode is valid.
647 if ((u_int32_t
)lock_mode
>= lrp
->nmodes
) {
649 "lock_get: invalid lock mode %lu\n", (u_long
)lock_mode
);
653 /* Allocate a new lock. Optimize for the common case of a grant. */
654 if ((newl
= SH_TAILQ_FIRST(&lrp
->free_locks
, __db_lock
)) == NULL
) {
655 if ((ret
= __lock_grow_region(lt
, DB_LOCK_LOCK
, 0)) != 0)
658 newl
= SH_TAILQ_FIRST(&lrp
->free_locks
, __db_lock
);
660 newl_off
= LOCK_TO_OFFSET(lt
, newl
);
662 /* Optimize for common case of granting a lock. */
663 SH_TAILQ_REMOVE(&lrp
->free_locks
, newl
, links
, __db_lock
);
665 newl
->mode
= lock_mode
;
666 newl
->status
= DB_LSTAT_HELD
;
667 newl
->holder
= locker
;
670 if ((ret
= __lock_getobj(lt
, 0, obj
, DB_LOCK_OBJTYPE
, &sh_obj
)) != 0)
673 lrp
= lt
->region
; /* getobj might have grown */
674 newl
= OFFSET_TO_LOCK(lt
, newl_off
);
676 /* Now make new lock point to object */
677 newl
->obj
= SH_PTR_TO_OFF(newl
, sh_obj
);
680 * Now we have a lock and an object and we need to see if we should
681 * grant the lock. We use a FIFO ordering so we can only grant a
682 * new lock if it does not conflict with anyone on the holders list
683 * OR anyone on the waiters list. The reason that we don't grant if
684 * there's a conflict is that this can lead to starvation (a writer
685 * waiting on a popularly read item will never be granted). The
686 * downside of this is that a waiting reader can prevent an upgrade
687 * from reader to writer, which is not uncommon.
689 * There is one exception to the no-conflict rule. If a lock is held
690 * by the requesting locker AND the new lock does not conflict with
691 * any other holders, then we grant the lock. The most common place
692 * this happens is when the holder has a WRITE lock and a READ lock
693 * request comes in for the same locker. If we do not grant the read
694 * lock, then we guarantee deadlock.
696 * In case of conflict, we put the new lock on the end of the waiters
700 for (lp
= SH_TAILQ_FIRST(&sh_obj
->holders
, __db_lock
);
702 lp
= SH_TAILQ_NEXT(lp
, links
, __db_lock
)) {
703 if (locker
== lp
->holder
) {
704 if (lp
->mode
== lock_mode
&&
705 lp
->status
== DB_LSTAT_HELD
) {
706 /* Lock is held, just inc the ref count. */
708 SH_TAILQ_INSERT_HEAD(&lrp
->free_locks
,
709 newl
, links
, __db_lock
);
714 } else if (CONFLICTS(lt
, lp
->mode
, lock_mode
))
718 if (lp
== NULL
&& !ihold
)
719 for (lp
= SH_TAILQ_FIRST(&sh_obj
->waiters
, __db_lock
);
721 lp
= SH_TAILQ_NEXT(lp
, links
, __db_lock
)) {
722 if (CONFLICTS(lt
, lp
->mode
, lock_mode
) &&
723 locker
!= lp
->holder
)
727 SH_TAILQ_INSERT_TAIL(&sh_obj
->holders
, newl
, links
);
728 else if (!(flags
& DB_LOCK_NOWAIT
))
729 SH_TAILQ_INSERT_TAIL(&sh_obj
->waiters
, newl
, links
);
731 /* Free the lock and return an error. */
732 newl
->status
= DB_LSTAT_FREE
;
733 SH_TAILQ_INSERT_HEAD(&lrp
->free_locks
, newl
, links
, __db_lock
);
734 return (DB_LOCK_NOTGRANTED
);
738 * This is really a blocker for the process, so initialize it
739 * set. That way the current process will block when it tries
740 * to get it and the waking process will release it.
742 (void)__db_mutex_init(&newl
->mutex
,
743 MUTEX_LOCK_OFFSET(lt
->region
, &newl
->mutex
));
744 (void)__db_mutex_lock(&newl
->mutex
, lt
->fd
);
747 * Now, insert the lock onto its locker's list.
750 __lock_getobj(lt
, locker
, NULL
, DB_LOCK_LOCKER
, &sh_locker
)) != 0)
754 SH_LIST_INSERT_HEAD(&sh_locker
->heldby
, newl
, locker_links
, __db_lock
);
757 newl
->status
= DB_LSTAT_WAITING
;
760 * We are about to wait; must release the region mutex.
761 * Then, when we wakeup, we need to reacquire the region
762 * mutex before continuing.
764 if (lrp
->detect
== DB_LOCK_NORUN
)
765 lt
->region
->need_dd
= 1;
766 UNLOCK_LOCKREGION(lt
);
769 * We are about to wait; before waiting, see if the deadlock
770 * detector should be run.
772 if (lrp
->detect
!= DB_LOCK_NORUN
)
773 ret
= lock_detect(lt
, 0, lrp
->detect
);
775 (void)__db_mutex_lock(&newl
->mutex
, lt
->fd
);
778 if (newl
->status
!= DB_LSTAT_PENDING
) {
779 /* Return to free list. */
780 __lock_checklocker(lt
, newl
, 0);
781 SH_TAILQ_INSERT_HEAD(&lrp
->free_locks
, newl
, links
,
783 switch (newl
->status
) {
784 case DB_LSTAT_ABORTED
:
785 ret
= DB_LOCK_DEADLOCK
;
787 case DB_LSTAT_NOGRANT
:
788 ret
= DB_LOCK_NOTGRANTED
;
794 newl
->status
= DB_LSTAT_FREE
;
797 newl
->status
= DB_LSTAT_HELD
;
805 * This is called at every interface to verify if the region
806 * has changed size, and if so, to remap the region in and
807 * reset the process pointers.
810 __lock_validate_region(lt
)
815 if (lt
->reg_size
== lt
->region
->hdr
.size
)
818 /* Grow the region. */
819 if ((ret
= __db_rremap(lt
->dbenv
, lt
->region
,
820 lt
->reg_size
, lt
->region
->hdr
.size
, lt
->fd
, <
->region
)) != 0)
823 __lock_reset_region(lt
);
829 * We have run out of space; time to grow the region.
832 __lock_grow_region(lt
, which
, howmuch
)
837 struct __db_lock
*newl
;
838 struct lock_header
*lock_head
;
839 struct obj_header
*obj_head
;
842 float lock_ratio
, obj_ratio
;
843 size_t incr
, oldsize
, used
;
844 u_int32_t i
, newlocks
, newmem
, newobjs
;
845 int ret
, usedlocks
, usedmem
, usedobjs
;
849 oldsize
= lrp
->hdr
.size
;
850 incr
= lrp
->increment
;
852 /* Figure out how much of each sort of space we have. */
853 usedmem
= lrp
->mem_bytes
- __db_shalloc_count(lt
->mem
);
854 usedobjs
= lrp
->numobjs
- __lock_count_objs(lrp
);
855 usedlocks
= lrp
->maxlocks
- __lock_count_locks(lrp
);
858 * Figure out what fraction of the used space belongs to each
859 * different type of "thing" in the region. Then partition the
860 * new space up according to this ratio.
863 usedlocks
* ALIGN(sizeof(struct __db_lock
), MUTEX_ALIGNMENT
) +
864 usedobjs
* sizeof(DB_LOCKOBJ
);
866 lock_ratio
= usedlocks
*
867 ALIGN(sizeof(struct __db_lock
), MUTEX_ALIGNMENT
) / (float)used
;
868 obj_ratio
= usedobjs
* sizeof(DB_LOCKOBJ
) / (float)used
;
870 newlocks
= (u_int32_t
)(lock_ratio
*
871 incr
/ ALIGN(sizeof(struct __db_lock
), MUTEX_ALIGNMENT
));
872 newobjs
= (u_int32_t
)(obj_ratio
* incr
/ sizeof(DB_LOCKOBJ
));
874 (newobjs
* sizeof(DB_LOCKOBJ
) +
875 newlocks
* ALIGN(sizeof(struct __db_lock
), MUTEX_ALIGNMENT
));
878 * Make sure we allocate enough memory for the object being
885 incr
+= newlocks
* sizeof(struct __db_lock
);
891 incr
+= newobjs
* sizeof(DB_LOCKOBJ
);
895 if (newmem
< howmuch
* 2) {
896 incr
+= howmuch
* 2 - newmem
;
897 newmem
= howmuch
* 2;
902 newmem
+= ALIGN(incr
, sizeof(size_t)) - incr
;
903 incr
= ALIGN(incr
, sizeof(size_t));
906 * Since we are going to be allocating locks at the beginning of the
907 * new chunk, we need to make sure that the chunk is MUTEX_ALIGNMENT
908 * aligned. We did not guarantee this when we created the region, so
909 * we may need to pad the old region by extra bytes to ensure this
912 incr
+= ALIGN(oldsize
, MUTEX_ALIGNMENT
) - oldsize
;
915 "Growing lock region: %lu locks %lu objs %lu bytes",
916 (u_long
)newlocks
, (u_long
)newobjs
, (u_long
)newmem
);
918 if ((ret
= __db_rgrow(lt
->dbenv
, lt
->fd
, incr
)) != 0)
920 if ((ret
= __db_rremap(lt
->dbenv
,
921 lt
->region
, oldsize
, oldsize
+ incr
, lt
->fd
, <
->region
)) != 0)
923 __lock_reset_region(lt
);
925 /* Update region parameters. */
927 lrp
->increment
= incr
<< 1;
928 lrp
->maxlocks
+= newlocks
;
929 lrp
->numobjs
+= newobjs
;
930 lrp
->mem_bytes
+= newmem
;
932 curaddr
= (u_int8_t
*)lrp
+ oldsize
;
933 curaddr
= (u_int8_t
*)ALIGNP(curaddr
, MUTEX_ALIGNMENT
);
935 /* Put new locks onto the free list. */
936 lock_head
= &lrp
->free_locks
;
937 for (i
= 0; i
++ < newlocks
;
938 curaddr
+= ALIGN(sizeof(struct __db_lock
), MUTEX_ALIGNMENT
)) {
939 newl
= (struct __db_lock
*)curaddr
;
940 SH_TAILQ_INSERT_HEAD(lock_head
, newl
, links
, __db_lock
);
943 /* Put new objects onto the free list. */
944 obj_head
= &lrp
->free_objs
;
945 for (i
= 0; i
++ < newobjs
; curaddr
+= sizeof(DB_LOCKOBJ
)) {
946 op
= (DB_LOCKOBJ
*)curaddr
;
947 SH_TAILQ_INSERT_HEAD(obj_head
, op
, links
, __db_lockobj
);
950 *((size_t *)curaddr
) = newmem
- sizeof(size_t);
951 curaddr
+= sizeof(size_t);
952 __db_shalloc_free(lt
->mem
, curaddr
);
959 * __lock_dump_region --
961 * PUBLIC: void __lock_dump_region __P((DB_LOCKTAB *, u_int));
964 __lock_dump_region(lt
, flags
)
968 struct __db_lock
*lp
;
975 printf("Lock region parameters\n");
976 printf("%s:0x%x\t%s:%lu\t%s:%lu\t%s:%lu\n%s:%lu\t%s:%lu\t%s:%lu\t\n",
977 "magic ", lrp
->magic
,
978 "version ", (u_long
)lrp
->version
,
979 "processes ", (u_long
)lrp
->hdr
.refcnt
,
980 "maxlocks ", (u_long
)lrp
->maxlocks
,
981 "table size ", (u_long
)lrp
->table_size
,
982 "nmodes ", (u_long
)lrp
->nmodes
,
983 "numobjs ", (u_long
)lrp
->numobjs
);
984 printf("%s:%lu\t%s:%lu\t%s:%lu\n%s:%lu\t%s:%lu\t%s:%lu\n",
985 "size ", (u_long
)lrp
->hdr
.size
,
986 "nlockers ", (u_long
)lrp
->nlockers
,
987 "hash_off ", (u_long
)lrp
->hash_off
,
988 "increment ", (u_long
)lrp
->increment
,
989 "mem_off ", (u_long
)lrp
->mem_off
,
990 "mem_bytes ", (u_long
)lrp
->mem_bytes
);
991 #ifndef HAVE_SPINLOCKS
992 printf("Mutex: off %lu", (u_long
)lrp
->hdr
.lock
.off
);
994 printf(" waits %lu nowaits %lu",
995 (u_long
)lrp
->hdr
.lock
.mutex_set_wait
,
996 (u_long
)lrp
->hdr
.lock
.mutex_set_nowait
);
997 printf("\n%s:%lu\t%s:%lu\t%s:%lu\t%s:%lu\n",
998 "nconflicts ", (u_long
)lrp
->nconflicts
,
999 "nrequests ", (u_long
)lrp
->nrequests
,
1000 "nreleases ", (u_long
)lrp
->nreleases
,
1001 "ndeadlocks ", (u_long
)lrp
->ndeadlocks
);
1002 printf("need_dd %lu\n", (u_long
)lrp
->need_dd
);
1003 if (flags
& LOCK_DEBUG_CONF
) {
1004 printf("\nConflict matrix\n");
1006 for (i
= 0; i
< lrp
->nmodes
; i
++) {
1007 for (j
= 0; j
< lrp
->nmodes
; j
++)
1009 (u_long
)lt
->conflicts
[i
* lrp
->nmodes
+ j
]);
1014 for (i
= 0; i
< lrp
->table_size
; i
++) {
1015 op
= SH_TAILQ_FIRST(<
->hashtab
[i
], __db_lockobj
);
1016 if (op
!= NULL
&& flags
& LOCK_DEBUG_BUCKET
)
1017 printf("Bucket %lu:\n", (unsigned long)i
);
1018 while (op
!= NULL
) {
1019 if (op
->type
== DB_LOCK_LOCKER
&&
1020 flags
& LOCK_DEBUG_LOCKERS
)
1021 __lock_dump_locker(lt
, op
);
1022 else if (flags
& LOCK_DEBUG_OBJECTS
&&
1023 op
->type
== DB_LOCK_OBJTYPE
)
1024 __lock_dump_object(lt
, op
);
1025 op
= SH_TAILQ_NEXT(op
, links
, __db_lockobj
);
1029 if (flags
& LOCK_DEBUG_LOCK
) {
1030 printf("\nLock Free List\n");
1031 for (lp
= SH_TAILQ_FIRST(&lrp
->free_locks
, __db_lock
);
1033 lp
= SH_TAILQ_NEXT(lp
, links
, __db_lock
)) {
1034 printf("0x%x: %lu\t%lu\t%lu\t0x%x\n", (u_int
)lp
,
1035 (u_long
)lp
->holder
, (u_long
)lp
->mode
,
1036 (u_long
)lp
->status
, (u_int
)lp
->obj
);
1040 if (flags
& LOCK_DEBUG_LOCK
) {
1041 printf("\nObject Free List\n");
1042 for (op
= SH_TAILQ_FIRST(&lrp
->free_objs
, __db_lockobj
);
1044 op
= SH_TAILQ_NEXT(op
, links
, __db_lockobj
))
1045 printf("0x%x\n", (u_int
)op
);
1048 if (flags
& LOCK_DEBUG_MEM
) {
1049 printf("\nMemory Free List\n");
1050 __db_shalloc_dump(stdout
, lt
->mem
);
1055 __lock_dump_locker(lt
, op
)
1059 struct __db_lock
*lp
;
1063 ptr
= SH_DBT_PTR(&op
->lockobj
);
1064 memcpy(&locker
, ptr
, sizeof(u_int32_t
));
1065 printf("L %lx", (u_long
)locker
);
1067 lp
= SH_LIST_FIRST(&op
->heldby
, __db_lock
);
1072 for (; lp
!= NULL
; lp
= SH_LIST_NEXT(lp
, locker_links
, __db_lock
))
1073 __lock_printlock(lt
, lp
, 0);
1077 __lock_dump_object(lt
, op
)
1081 struct __db_lock
*lp
;
1085 ptr
= SH_DBT_PTR(&op
->lockobj
);
1086 for (j
= 0; j
< op
->lockobj
.size
; ptr
++, j
++)
1087 printf("%c", (int)*ptr
);
1092 SH_TAILQ_FIRST(&op
->holders
, __db_lock
);
1094 lp
= SH_TAILQ_NEXT(lp
, links
, __db_lock
))
1095 __lock_printlock(lt
, lp
, 0);
1096 lp
= SH_TAILQ_FIRST(&op
->waiters
, __db_lock
);
1099 for (; lp
!= NULL
; lp
= SH_TAILQ_NEXT(lp
, links
, __db_lock
))
1100 __lock_printlock(lt
, lp
, 0);
1105 * __lock_is_locked --
1107 * PUBLIC: int __lock_is_locked
1108 * PUBLIC: __P((DB_LOCKTAB *, u_int32_t, DBT *, db_lockmode_t));
1111 __lock_is_locked(lt
, locker
, dbt
, mode
)
1117 struct __db_lock
*lp
;
1123 /* Look up the object in the hash table. */
1124 HASHLOOKUP(lt
->hashtab
, __db_lockobj
, links
,
1125 dbt
, sh_obj
, lrp
->table_size
, __lock_ohash
, __lock_cmp
);
1129 for (lp
= SH_TAILQ_FIRST(&sh_obj
->holders
, __db_lock
);
1131 lp
= SH_TAILQ_FIRST(&sh_obj
->holders
, __db_lock
)) {
1132 if (lp
->holder
== locker
&& lp
->mode
== mode
)
1140 __lock_printlock(lt
, lp
, ispgno
)
1142 struct __db_lock
*lp
;
1145 DB_LOCKOBJ
*lockobj
;
1149 const char *mode
, *status
;
1158 case DB_LOCK_IWRITE
:
1174 switch (lp
->status
) {
1175 case DB_LSTAT_ABORTED
:
1187 case DB_LSTAT_NOGRANT
:
1190 case DB_LSTAT_WAITING
:
1193 case DB_LSTAT_PENDING
:
1200 printf("\t%lx\t%s\t%lu\t%s\t",
1201 (u_long
)lp
->holder
, mode
, (u_long
)lp
->refcount
, status
);
1203 lockobj
= (DB_LOCKOBJ
*)((u_int8_t
*)lp
+ lp
->obj
);
1204 ptr
= SH_DBT_PTR(&lockobj
->lockobj
);
1206 /* Assume this is a DBT lock. */
1207 memcpy(&pgno
, ptr
, sizeof(db_pgno_t
));
1208 printf("page %lu\n", (u_long
)pgno
);
1210 obj
= (u_int8_t
*)lp
+ lp
->obj
- (u_int8_t
*)lt
->region
;
1211 printf("0x%lx ", (u_long
)obj
);
1212 __db_pr(ptr
, lockobj
->lockobj
.size
);
1219 __lock_count_locks(lrp
)
1222 struct __db_lock
*newl
;
1226 for (newl
= SH_TAILQ_FIRST(&lrp
->free_locks
, __db_lock
);
1228 newl
= SH_TAILQ_NEXT(newl
, links
, __db_lock
))
1235 __lock_count_objs(lrp
)
1242 for (obj
= SH_TAILQ_FIRST(&lrp
->free_objs
, __db_lockobj
);
1244 obj
= SH_TAILQ_NEXT(obj
, links
, __db_lockobj
))
1251 * PUBLIC: int __lock_getobj __P((DB_LOCKTAB *,
1252 * PUBLIC: u_int32_t, const DBT *, u_int32_t type, DB_LOCKOBJ **));
1255 __lock_getobj(lt
, locker
, dbt
, type
, objp
)
1257 u_int32_t locker
, type
;
1269 /* Look up the object in the hash table. */
1270 if (type
== DB_LOCK_OBJTYPE
) {
1271 HASHLOOKUP(lt
->hashtab
, __db_lockobj
, links
, dbt
, sh_obj
,
1272 lrp
->table_size
, __lock_ohash
, __lock_cmp
);
1273 obj_size
= dbt
->size
;
1275 HASHLOOKUP(lt
->hashtab
, __db_lockobj
, links
, locker
,
1276 sh_obj
, lrp
->table_size
, __lock_locker_hash
,
1278 obj_size
= sizeof(locker
);
1282 * If we found the object, then we can just return it. If
1283 * we didn't find the object, then we need to create it.
1285 if (sh_obj
== NULL
) {
1286 /* Create new object and then insert it into hash table. */
1288 SH_TAILQ_FIRST(&lrp
->free_objs
, __db_lockobj
)) == NULL
) {
1289 if ((ret
= __lock_grow_region(lt
, DB_LOCK_OBJ
, 0)) != 0)
1292 sh_obj
= SH_TAILQ_FIRST(&lrp
->free_objs
, __db_lockobj
);
1296 * If we can fit this object in the structure, do so instead
1297 * of shalloc-ing space for it.
1299 if (obj_size
<= sizeof(sh_obj
->objdata
))
1300 p
= sh_obj
->objdata
;
1303 __db_shalloc(lt
->mem
, obj_size
, 0, &p
)) != 0) {
1304 if ((ret
= __lock_grow_region(lt
,
1305 DB_LOCK_MEM
, obj_size
)) != 0)
1308 /* Reacquire the head of the list. */
1309 sh_obj
= SH_TAILQ_FIRST(&lrp
->free_objs
,
1311 (void)__db_shalloc(lt
->mem
, obj_size
, 0, &p
);
1314 src
= type
== DB_LOCK_OBJTYPE
? dbt
->data
: (void *)&locker
;
1315 memcpy(p
, src
, obj_size
);
1317 sh_obj
->type
= type
;
1318 SH_TAILQ_REMOVE(&lrp
->free_objs
, sh_obj
, links
, __db_lockobj
);
1320 SH_TAILQ_INIT(&sh_obj
->waiters
);
1321 if (type
== DB_LOCK_LOCKER
)
1322 SH_LIST_INIT(&sh_obj
->heldby
);
1324 SH_TAILQ_INIT(&sh_obj
->holders
);
1325 sh_obj
->lockobj
.size
= obj_size
;
1326 sh_obj
->lockobj
.off
= SH_PTR_TO_OFF(&sh_obj
->lockobj
, p
);
1328 HASHINSERT(lt
->hashtab
,
1329 __db_lockobj
, links
, sh_obj
, lrp
->table_size
, __lock_lhash
);
1331 if (type
== DB_LOCK_LOCKER
)
1340 * Any lock on the waitlist has a process waiting for it. Therefore, we
1341 * can't return the lock to the freelist immediately. Instead, we can
1342 * remove the lock from the list of waiters, set the status field of the
1343 * lock, and then let the process waking up return the lock to the
1347 __lock_remove_waiter(lt
, sh_obj
, lockp
, status
)
1350 struct __db_lock
*lockp
;
1353 SH_TAILQ_REMOVE(&sh_obj
->waiters
, lockp
, links
, __db_lock
);
1354 lockp
->status
= status
;
1356 /* Wake whoever is waiting on this lock. */
1357 (void)__db_mutex_unlock(&lockp
->mutex
, lt
->fd
);
1361 __lock_freeobj(lt
, obj
)
1365 HASHREMOVE_EL(lt
->hashtab
,
1366 __db_lockobj
, links
, obj
, lt
->region
->table_size
, __lock_lhash
);
1367 if (obj
->lockobj
.size
> sizeof(obj
->objdata
))
1368 __db_shalloc_free(lt
->mem
, SH_DBT_PTR(&obj
->lockobj
));
1369 SH_TAILQ_INSERT_HEAD(<
->region
->free_objs
, obj
, links
, __db_lockobj
);
1373 __lock_checklocker(lt
, lockp
, do_remove
)
1375 struct __db_lock
*lockp
;
1378 DB_LOCKOBJ
*sh_locker
;
1381 SH_LIST_REMOVE(lockp
, locker_links
, __db_lock
);
1383 /* if the locker list is NULL, free up the object. */
1384 if (__lock_getobj(lt
, lockp
->holder
, NULL
, DB_LOCK_LOCKER
, &sh_locker
)
1385 == 0 && SH_LIST_FIRST(&sh_locker
->heldby
, __db_lock
) == NULL
) {
1386 __lock_freeobj(lt
, sh_locker
);
1387 lt
->region
->nlockers
--;
1392 __lock_reset_region(lt
)
1395 lt
->conflicts
= (u_int8_t
*)lt
->region
+ sizeof(DB_LOCKREGION
);
1397 (DB_HASHTAB
*)((u_int8_t
*)lt
->region
+ lt
->region
->hash_off
);
1398 lt
->mem
= (void *)((u_int8_t
*)lt
->region
+ lt
->region
->mem_off
);
1399 lt
->reg_size
= lt
->region
->hdr
.size
;