diff options
| author | Ulrich Drepper <drepper@redhat.com> | 1997-08-27 20:26:10 +0000 |
|---|---|---|
| committer | Ulrich Drepper <drepper@redhat.com> | 1997-08-27 20:26:10 +0000 |
| commit | 92f1da4da04a7a86ddee91be5eaf0b10c333ac64 (patch) | |
| tree | 2a10ce9e4e407e7e5b5ca092ca0947d234b5ff60 /db2/lock | |
| parent | 22be878ecbc66606371bd33258f56e6711e6ba7a (diff) | |
| download | glibc-cvs/libc-ud-970827.tar.xz glibc-cvs/libc-ud-970827.zip | |
Update.cvs/libc-ud-970827
1997-08-10 19:17 Philip Blundell <Philip.Blundell@pobox.com>
* nss/nss_db/db-XXX.c: Include <db_185.h> not <db.h>. Somebody
should update this to use the new db API.
* nss/nss_db/db-netgrp.c: Likewise.
* nss/nss_db/db-alias.c: Likewise.
* db2/Makefile: Makefile for db-2.x in glibc.
1997-08-27 21:20 Ulrich Drepper <drepper@cygnus.com>
* csu/Makefile (before-compile): New goal. Make sure abi-tag.h
is generated.
[$(elf)=yes] (asm-CPPFLAGS): Make sure abi-tag.h file can be found.
* Makeconfig [$(build-omitfp)=yes] (CFLAGS-.o): Add
-D__USE_STRING_INLINES.
* string/string.f: Move strnlen optimization after inclusion of
<bits/string.h>. Include <bits/string.h> only if __USE_STRING_INLINES
is defined.
* sysdeps/generic/memcpy.c: Undef memcpy to allow macro of this name
in <bits/string.h>.
* sysdeps/generic/memset.c: Likewise.
* sysdeps/i386/string.h: i386 optimized string functions.
* sysdeps/i386/i486string.h: i486+ optimized string functions.
* Makefile (subdirs): Change db to db2.
* shlib-versions: Bump libdb verion number to 3.
* include/db.h: Include from db2 directory.
* include/db_185.h: New file.
* sysdeps/i386/Makefile [$(subdirs)=db2] (CPPFLAGS): Add macros
to provide spinlock information for db2.
* sysdeps/m68k/m68020/Makefile: New file. Likewise.
* sysdeps/sparc/Makefile: New file. Likewise.
* sysdeps/unix/sysv/linux/Makefile [$(subdirs)=db2] (CPPFLAGS):
Add -DHAVE_LLSEEK.
* db2/config.h: Hand-edited config file for db2 in glibc.
* db2/compat.h: New file from db-2.3.4.
* db2/db.h: Likewise.
* db2/db_185.h: Likewise.
* db2/db_int.h: Likewise.
* db2/makedb.c: Likewise.
* db2/btree/bt_close.c: Likewise.
* db2/btree/bt_compare.c: Likewise.
* db2/btree/bt_conv.c: Likewise.
* db2/btree/bt_cursor.c: Likewise.
* db2/btree/bt_delete.c: Likewise.
* db2/btree/bt_open.c: Likewise.
* db2/btree/bt_page.c: Likewise.
* db2/btree/bt_put.c: Likewise.
* db2/btree/bt_rec.c: Likewise.
* db2/btree/bt_recno.c: Likewise.
* db2/btree/btree_auto.c: Likewise.
* db2/btree/bt_rsearch.c: Likewise.
* db2/btree/bt_search.c: Likewise.
* db2/btree/bt_split.c: Likewise.
* db2/btree/bt_stat.c: Likewise.
* db2/btree/btree.src: Likewise.
* db2/common/db_appinit.c: Likewise.
* db2/common/db_err.c: Likewise.
* db2/common/db_byteorder.c: Likewise.
* db2/common/db_apprec.c: Likewise.
* db2/common/db_salloc.c: Likewise.
* db2/common/db_log2.c: Likewise.
* db2/common/db_region.c: Likewise.
* db2/common/db_shash.c: Likewise.
* db2/db/db.c: Likewise.
* db2/db/db.src: Likewise.
* db2/db/db_conv.c: Likewise.
* db2/db/db_dispatch.c: Likewise.
* db2/db/db_dup.c: Likewise.
* db2/db/db_overflow.c: Likewise.
* db2/db/db_pr.c: Likewise.
* db2/db/db_rec.c: Likewise.
* db2/db/db_ret.c: Likewise.
* db2/db/db_thread.c: Likewise.
* db2/db/db_auto.c: Likewise.
* db2/db185/db185.c: Likewise.
* db2/db185/db185_int.h: Likewise.
* db2/dbm/dbm.c: Likewise.
* db2/hash/hash.c: Likewise.
* db2/hash/hash.src: Likewise.
* db2/hash/hash_page.c: Likewise.
* db2/hash/hash_conv.c: Likewise.
* db2/hash/hash_debug.c: Likewise.
* db2/hash/hash_stat.c: Likewise.
* db2/hash/hash_rec.c: Likewise.
* db2/hash/hash_dup.c: Likewise.
* db2/hash/hash_func.c: Likewise.
* db2/hash/hash_auto.c: Likewise.
* db2/include/mp.h: Likewise.
* db2/include/btree.h: Likewise.
* db2/include/db.h.src: Likewise.
* db2/include/db_int.h.src: Likewise.
* db2/include/db_shash.h: Likewise.
* db2/include/db_swap.h: Likewise.
* db2/include/db_185.h.src: Likewise.
* db2/include/txn.h: Likewise.
* db2/include/db_am.h: Likewise.
* db2/include/shqueue.h: Likewise.
* db2/include/hash.h: Likewise.
* db2/include/db_dispatch.h: Likewise.
* db2/include/lock.h: Likewise.
* db2/include/db_page.h: Likewise.
* db2/include/log.h: Likewise.
* db2/include/db_auto.h: Likewise.
* db2/include/btree_auto.h: Likewise.
* db2/include/hash_auto.h: Likewise.
* db2/include/log_auto.h: Likewise.
* db2/include/txn_auto.h: Likewise.
* db2/include/db_ext.h: Likewise.
* db2/include/btree_ext.h: Likewise.
* db2/include/clib_ext.h: Likewise.
* db2/include/common_ext.h: Likewise.
* db2/include/hash_ext.h: Likewise.
* db2/include/lock_ext.h: Likewise.
* db2/include/log_ext.h: Likewise.
* db2/include/mp_ext.h: Likewise.
* db2/include/mutex_ext.h: Likewise.
* db2/include/os_ext.h: Likewise.
* db2/include/txn_ext.h: Likewise.
* db2/include/cxx_int.h: Likewise.
* db2/include/db_cxx.h: Likewise.
* db2/include/queue.h: Likewise.
* db2/lock/lock.c: Likewise.
* db2/lock/lock_conflict.c: Likewise.
* db2/lock/lock_util.c: Likewise.
* db2/lock/lock_deadlock.c: Likewise.
* db2/log/log.c: Likewise.
* db2/log/log_get.c: Likewise.
* db2/log/log.src: Likewise.
* db2/log/log_compare.c: Likewise.
* db2/log/log_put.c: Likewise.
* db2/log/log_rec.c: Likewise.
* db2/log/log_archive.c: Likewise.
* db2/log/log_register.c: Likewise.
* db2/log/log_auto.c: Likewise.
* db2/log/log_findckp.c: Likewise.
* db2/mp/mp_bh.c: Likewise.
* db2/mp/mp_fget.c: Likewise.
* db2/mp/mp_fopen.c: Likewise.
* db2/mp/mp_fput.c: Likewise.
* db2/mp/mp_fset.c: Likewise.
* db2/mp/mp_open.c: Likewise.
* db2/mp/mp_region.c: Likewise.
* db2/mp/mp_pr.c: Likewise.
* db2/mp/mp_sync.c: Likewise.
* db2/mutex/68020.gcc: Likewise.
* db2/mutex/mutex.c: Likewise.
* db2/mutex/README: Likewise.
* db2/mutex/x86.gcc: Likewise.
* db2/mutex/sparc.gcc: Likewise.
* db2/mutex/uts4.cc.s: Likewise.
* db2/mutex/alpha.dec: Likewise.
* db2/mutex/alpha.gcc: Likewise.
* db2/mutex/parisc.gcc: Likewise.
* db2/mutex/parisc.hp: Likewise.
* db2/os/db_os_abs.c: Likewise.
* db2/os/db_os_dir.c: Likewise.
* db2/os/db_os_fid.c: Likewise.
* db2/os/db_os_lseek.c: Likewise.
* db2/os/db_os_mmap.c: Likewise.
* db2/os/db_os_open.c: Likewise.
* db2/os/db_os_rw.c: Likewise.
* db2/os/db_os_sleep.c: Likewise.
* db2/os/db_os_stat.c: Likewise.
* db2/os/db_os_unlink.c: Likewise.
* db2/txn/txn.c: Likewise.
* db2/txn/txn.src: Likewise.
* db2/txn/txn_rec.c: Likewise.
* db2/txn/txn_auto.c: Likewise.
* db2/clib/getlong.c: Likewise.
* db2/progs/db_archive/db_archive.c: Likewise.
* db2/progs/db_checkpoint/db_checkpoint.c: Likewise.
* db2/progs/db_deadlock/db_deadlock.c: Likewise.
* db2/progs/db_dump/db_dump.c: Likewise.
* db2/progs/db_dump185/db_dump185.c: Likewise.
* db2/progs/db_load/db_load.c: Likewise.
* db2/progs/db_printlog/db_printlog.c: Likewise.
* db2/progs/db_recover/db_recover.c: Likewise.
* db2/progs/db_stat/db_stat.c: Likewise.
* libio/stdio.h [__cplusplus] (__STDIO_INLINE): Define as inline.
* po/de.po, po/sv.po: Update from 2.0.5 translations.
* sysdeps/unix/sysv/linux/netinet/tcp.h: Pretty print.
* sunrpc/rpc/xdr.h (XDR): Don't define argument of x_destroy callback
as const.
* sunrpc/xdr_mem.c (xdrmem_destroy): Don't define argument as const.
* sunrpx/xdr_rec.c (xdrrec_destroy): Likewise.
* sunrpx/xdr_stdio.c (xdrstdio_destroy): Likewise.
1997-08-27 18:47 Ulrich Drepper <drepper@cygnus.com>
* sysdeps/unix/sysv/linux/if_index.c: Include <errno.h>.
Reported by Benjamin Kosnik <bkoz@cygnus.com>.
1997-08-27 02:27 Roland McGrath <roland@baalperazim.frob.com>
* abi-tags: New file.
* csu/Makefile (distribute): Remove abi-tag.h.
($(objpfx)abi-tag.h): New target.
* Makefile (distribute): Add abi-tags.
* sysdeps/unix/sysv/linux/abi-tag.h: File removed.
* sysdeps/mach/hurd/abi-tag.h: File removed.
* sysdeps/stub/abi-tag.h: File removed.
1997-08-25 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
* sysdeps/unix/make-syscalls.sh: Change output so that it
generates compilation rules only for the currently selected object
suffixes.
1997-08-25 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
* sysdeps/m68k/dl-machine.h (RTLD_START): Switch back to previous
section to avoid confusing the compiler.
* sysdeps/alpha/dl-machine.h (RTLD_START): Likewise.
* sysdeps/i386/dl-machine.h (RTLD_START): Likewise.
* sysdeps/mips/dl-machine.h (RTLD_START): Likewise.
* sysdeps/mips/mips64/dl-machine.h (RTLD_START): Likewise.
* sysdeps/sparc/sparc32/dl-machine.h (RTLD_START): Likewise.
* sysdeps/m68k/dl-machine.h (elf_machine_load_address): Use a GOT
relocation instead of a constant to avoid text relocation.
(ELF_MACHINE_BEFORE_RTLD_RELOC): Removed.
(RTLD_START): Declare global labels as functions and add size
directive.
1997-08-25 17:01 Ulrich Drepper <drepper@cygnus.com>
* sysdeps/i386/bits/select.h: Correct assembler versions to work even
for descriptors >= 32.
* stdlib/alloca.h: Don't define alloca to __alloca since if gcc
is used __alloca is not defined to __builtin_alloca and so might
not be available.
Reported by Uwe Ohse <uwe@ohse.de>.
* sysdeps/unix/sysv/linux/sys/sysmacros.h: Define macros in a special
way if gcc is not used and so dev_t is an array.
Reported by Uwe Ohse <uwe@ohse.de>.
1997-08-23 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de>
* manual/libc.texinfo: Reorder chapters to match logical order.
1997-08-25 12:22 Ulrich Drepper <drepper@cygnus.com>
* sunrpc/rpc/xdr.h: Change name of parameters in prototypes of
xdr_reference, xdrmem_create, and xdrstdio_create because of clash
with g++ internal symbols.
Patch by Sudish Joseph <sj@eng.mindspring.net>.
* elf/dl-deps.c: Implement handling of DT_FILTER.
Diffstat (limited to 'db2/lock')
| -rw-r--r-- | db2/lock/lock.c | 1362 | ||||
| -rw-r--r-- | db2/lock/lock_conflict.c | 39 | ||||
| -rw-r--r-- | db2/lock/lock_deadlock.c | 496 | ||||
| -rw-r--r-- | db2/lock/lock_util.c | 103 |
4 files changed, 2000 insertions, 0 deletions
diff --git a/db2/lock/lock.c b/db2/lock/lock.c new file mode 100644 index 0000000000..8fc91334a7 --- /dev/null +++ b/db2/lock/lock.c @@ -0,0 +1,1362 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1996, 1997 + * Sleepycat Software. All rights reserved. + */ + +#include "config.h" + +#ifndef lint +static const char sccsid[] = "@(#)lock.c 10.31 (Sleepycat) 8/17/97"; +#endif /* not lint */ + +#ifndef NO_SYSTEM_INCLUDES +#include <sys/types.h> +#include <sys/mman.h> +#include <sys/stat.h> + +#include <errno.h> +#include <fcntl.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#endif + +#include "db_int.h" +#include "shqueue.h" +#include "db_page.h" +#include "db_shash.h" +#include "lock.h" +#include "common_ext.h" +#include "db_am.h" + +static void __lock_checklocker __P((DB_LOCKTAB *, struct __db_lock *, int)); +static int __lock_count_locks __P((DB_LOCKREGION *)); +static int __lock_count_objs __P((DB_LOCKREGION *)); +static int __lock_create __P((const char *, int, DB_ENV *)); +static void __lock_freeobj __P((DB_LOCKTAB *, DB_LOCKOBJ *)); +static int __lock_get_internal __P((DB_LOCKTAB *, u_int32_t, int, const DBT *, + db_lockmode_t, struct __db_lock **)); +static int __lock_grow_region __P((DB_LOCKTAB *, int, size_t)); +static int __lock_put_internal __P((DB_LOCKTAB *, struct __db_lock *, int)); +static void __lock_remove_waiter + __P((DB_LOCKTAB *, DB_LOCKOBJ *, struct __db_lock *, db_status_t)); +static void __lock_reset_region __P((DB_LOCKTAB *)); +static int __lock_validate_region __P((DB_LOCKTAB *)); +#ifdef DEBUG +static void __lock_dump_locker __P((DB_LOCKTAB *, DB_LOCKOBJ *)); +static void __lock_dump_object __P((DB_LOCKTAB *, DB_LOCKOBJ *)); +static void __lock_printlock __P((DB_LOCKTAB *, struct __db_lock *, int)); +#endif + +/* + * Create and initialize a lock region in shared memory. + */ + +/* + * __lock_create -- + * Create the lock region. Returns an errno. In most cases, + * the errno should be that returned by __db_ropen, in which case + * an EAGAIN means that we should retry, and an EEXIST means that + * the region exists and we didn't need to create it. Any other + * sort of errno should be treated as a system error, leading to a + * failure of the original interface call. + */ +static int +__lock_create(path, mode, dbenv) + const char *path; + int mode; + DB_ENV *dbenv; +{ + struct __db_lock *lp; + struct lock_header *tq_head; + struct obj_header *obj_head; + DB_LOCKOBJ *op; + DB_LOCKREGION *lrp; + u_int maxlocks; + u_int32_t i; + int fd, lock_modes, nelements, ret; + u_int8_t *conflicts, *curaddr; + + maxlocks = dbenv == NULL || dbenv->lk_max == 0 ? + DB_LOCK_DEFAULT_N : dbenv->lk_max; + lock_modes = dbenv == NULL || dbenv->lk_modes == 0 ? + DB_LOCK_RW_N : dbenv->lk_modes; + conflicts = dbenv == NULL || dbenv->lk_conflicts == NULL ? + (u_int8_t *)db_rw_conflicts : dbenv->lk_conflicts; + + if ((ret = + __db_rcreate(dbenv, DB_APP_NONE, path, DB_DEFAULT_LOCK_FILE, mode, + LOCK_REGION_SIZE(lock_modes, maxlocks, __db_tablesize(maxlocks)), + &fd, &lrp)) != 0) + return (ret); + + /* Region exists; now initialize it. */ + lrp->table_size = __db_tablesize(maxlocks); + lrp->magic = DB_LOCKMAGIC; + lrp->version = DB_LOCKVERSION; + lrp->id = 0; + lrp->maxlocks = maxlocks; + lrp->need_dd = 0; + lrp->detect = DB_LOCK_NORUN; + lrp->numobjs = maxlocks; + lrp->nlockers = 0; + lrp->mem_bytes = ALIGN(STRING_SIZE(maxlocks), sizeof(size_t)); + lrp->increment = lrp->hdr.size / 2; + lrp->nmodes = lock_modes; + lrp->nconflicts = 0; + lrp->nrequests = 0; + lrp->nreleases = 0; + lrp->ndeadlocks = 0; + + /* + * As we write the region, we've got to maintain the alignment + * for the structures that follow each chunk. This information + * ends up being encapsulated both in here as well as in the + * lock.h file for the XXX_SIZE macros. + */ + /* Initialize conflict matrix. */ + curaddr = (u_int8_t *)lrp + sizeof(DB_LOCKREGION); + memcpy(curaddr, conflicts, lock_modes * lock_modes); + curaddr += lock_modes * lock_modes; + + /* + * Initialize hash table. + */ + curaddr = (u_int8_t *)ALIGNP(curaddr, LOCK_HASH_ALIGN); + lrp->hash_off = curaddr - (u_int8_t *)lrp; + nelements = lrp->table_size; + __db_hashinit(curaddr, nelements); + curaddr += nelements * sizeof(DB_HASHTAB); + + /* + * Initialize locks onto a free list. Since locks contains mutexes, + * we need to make sure that each lock is aligned on a MUTEX_ALIGNMENT + * boundary. + */ + curaddr = (u_int8_t *)ALIGNP(curaddr, MUTEX_ALIGNMENT); + tq_head = &lrp->free_locks; + SH_TAILQ_INIT(tq_head); + + for (i = 0; i++ < maxlocks; + curaddr += ALIGN(sizeof(struct __db_lock), MUTEX_ALIGNMENT)) { + lp = (struct __db_lock *)curaddr; + lp->status = DB_LSTAT_FREE; + SH_TAILQ_INSERT_HEAD(tq_head, lp, links, __db_lock); + } + + /* Initialize objects onto a free list. */ + obj_head = &lrp->free_objs; + SH_TAILQ_INIT(obj_head); + + for (i = 0; i++ < maxlocks; curaddr += sizeof(DB_LOCKOBJ)) { + op = (DB_LOCKOBJ *)curaddr; + SH_TAILQ_INSERT_HEAD(obj_head, op, links, __db_lockobj); + } + + /* + * Initialize the string space; as for all shared memory allocation + * regions, this requires size_t alignment, since we store the + * lengths of malloc'd areas in the area.. + */ + curaddr = (u_int8_t *)ALIGNP(curaddr, sizeof(size_t)); + lrp->mem_off = curaddr - (u_int8_t *)lrp; + __db_shalloc_init(curaddr, lrp->mem_bytes); + + /* Release the lock. */ + (void)__db_mutex_unlock(&lrp->hdr.lock, fd); + + /* Now unmap the region. */ + if ((ret = __db_rclose(dbenv, fd, lrp)) != 0) { + (void)lock_unlink(path, 1 /* force */, dbenv); + return (ret); + } + + return (0); +} + +int +lock_open(path, flags, mode, dbenv, ltp) + const char *path; + int flags, mode; + DB_ENV *dbenv; + DB_LOCKTAB **ltp; +{ + DB_LOCKTAB *lt; + int ret, retry_cnt; + + /* Validate arguments. */ +#ifdef HAVE_SPINLOCKS +#define OKFLAGS (DB_CREATE | DB_THREAD) +#else +#define OKFLAGS (DB_CREATE) +#endif + if ((ret = __db_fchk(dbenv, "lock_open", flags, OKFLAGS)) != 0) + return (ret); + + /* + * Create the lock table structure. + */ + if ((lt = (DB_LOCKTAB *)calloc(1, sizeof(DB_LOCKTAB))) == NULL) { + __db_err(dbenv, "%s", strerror(errno)); + return (ENOMEM); + } + lt->dbenv = dbenv; + + /* + * Now, create the lock region if it doesn't already exist. + */ + retry_cnt = 0; +retry: if (LF_ISSET(DB_CREATE) && + (ret = __lock_create(path, mode, dbenv)) != 0) + if (ret == EAGAIN && ++retry_cnt < 3) { + (void)__db_sleep(1, 0); + goto retry; + } else if (ret == EEXIST) /* We did not create the region */ + LF_CLR(DB_CREATE); + else + goto out; + + /* + * Finally, open the region, map it in, and increment the + * reference count. + */ + retry_cnt = 0; +retry1: if ((ret = __db_ropen(dbenv, DB_APP_NONE, path, DB_DEFAULT_LOCK_FILE, + LF_ISSET(~(DB_CREATE | DB_THREAD)), <->fd, <->region)) != 0) { + if (ret == EAGAIN && ++retry_cnt < 3) { + (void)__db_sleep(1, 0); + goto retry1; + } + goto out; + } + + if (lt->region->magic != DB_LOCKMAGIC) { + __db_err(dbenv, "lock_open: Bad magic number"); + ret = EINVAL; + goto out; + } + + /* Check for automatic deadlock detection. */ + if (dbenv->lk_detect != DB_LOCK_NORUN) { + if (lt->region->detect != DB_LOCK_NORUN && + dbenv->lk_detect != DB_LOCK_DEFAULT && + lt->region->detect != dbenv->lk_detect) { + __db_err(dbenv, + "lock_open: incompatible deadlock detector mode"); + ret = EINVAL; + goto out; + } + if (lt->region->detect == DB_LOCK_NORUN) + lt->region->detect = dbenv->lk_detect; + } + + /* Set up remaining pointers into region. */ + lt->conflicts = (u_int8_t *)lt->region + sizeof(DB_LOCKREGION); + lt->hashtab = + (DB_HASHTAB *)((u_int8_t *)lt->region + lt->region->hash_off); + lt->mem = (void *)((u_int8_t *)lt->region + lt->region->mem_off); + lt->reg_size = lt->region->hdr.size; + + *ltp = lt; + return (0); + +/* Error handling. */ +out: if (lt->region != NULL) + (void)__db_rclose(lt->dbenv, lt->fd, lt->region); + if (LF_ISSET(DB_CREATE)) + (void)lock_unlink(path, 1, lt->dbenv); + free(lt); + return (ret); +} + +int +lock_id (lt, idp) + DB_LOCKTAB *lt; + u_int32_t *idp; +{ + u_int32_t id; + + LOCK_LOCKREGION(lt); + if (lt->region->id >= DB_LOCK_MAXID) + lt->region->id = 0; + id = ++lt->region->id; + UNLOCK_LOCKREGION(lt); + + *idp = id; + return (0); +} + +int +lock_vec(lt, locker, flags, list, nlist, elistp) + DB_LOCKTAB *lt; + u_int32_t locker; + int flags, nlist; + DB_LOCKREQ *list, **elistp; +{ + struct __db_lock *lp; + DB_LOCKOBJ *sh_obj, *sh_locker; + int i, ret, run_dd; + + /* Validate arguments. */ + if ((ret = + __db_fchk(lt->dbenv, "lock_vec", flags, DB_LOCK_NOWAIT)) != 0) + return (ret); + + LOCK_LOCKREGION(lt); + + if ((ret = __lock_validate_region(lt)) != 0) { + UNLOCK_LOCKREGION(lt); + return (ret); + } + + ret = 0; + for (i = 0; i < nlist && ret == 0; i++) { + switch (list[i].op) { + case DB_LOCK_GET: + ret = __lock_get_internal(lt, locker, flags, + list[i].obj, list[i].mode, &lp); + if (ret == 0) + list[i].lock = LOCK_TO_OFFSET(lt, lp); + break; + case DB_LOCK_PUT: + lp = OFFSET_TO_LOCK(lt, list[i].lock); + if (lp->holder != locker) { + ret = DB_LOCK_NOTHELD; + break; + } + list[i].mode = lp->mode; + + /* XXX Need to copy the object. ??? */ + ret = __lock_put_internal(lt, lp, 0); + break; + case DB_LOCK_PUT_ALL: + /* Find the locker. */ + if ((ret = __lock_getobj(lt, locker, + NULL, DB_LOCK_LOCKER, &sh_locker)) != 0) + break; + + for (lp = SH_LIST_FIRST(&sh_locker->heldby, __db_lock); + lp != NULL; + lp = SH_LIST_FIRST(&sh_locker->heldby, __db_lock)) { + if ((ret = __lock_put_internal(lt, lp, 0)) != 0) + break; + } + __lock_freeobj(lt, sh_locker); + lt->region->nlockers--; + break; + case DB_LOCK_PUT_OBJ: + + /* Look up the object in the hash table. */ + __db_hashlookup(lt->hashtab, __db_lockobj, links, + list[i].obj, sh_obj, lt->region->table_size, + __lock_ohash, __lock_cmp); + if (sh_obj == NULL) { + ret = EINVAL; + break; + } + /* + * Release waiters first, because they won't cause + * anyone else to be awakened. If we release the + * lockers first, all the waiters get awakened + * needlessly. + */ + for (lp = SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock); + lp != NULL; + lp = SH_TAILQ_FIRST(&sh_obj->waiters, __db_lock)) { + lt->region->nreleases += lp->refcount; + __lock_remove_waiter(lt, sh_obj, lp, + DB_LSTAT_NOGRANT); + __lock_checklocker(lt, lp, 1); + } + + for (lp = SH_TAILQ_FIRST(&sh_obj->holders, __db_lock); + lp != NULL; + lp = SH_TAILQ_FIRST(&sh_obj->holders, __db_lock)) { + + lt->region->nreleases += lp->refcount; + SH_LIST_REMOVE(lp, locker_links, __db_lock); + SH_TAILQ_REMOVE(&sh_obj->holders, lp, links, + __db_lock); + lp->status = DB_LSTAT_FREE; + SH_TAILQ_INSERT_HEAD(<->region->free_locks, + lp, links, __db_lock); + } + + /* Now free the object. */ + __lock_freeobj(lt, sh_obj); + break; +#ifdef DEBUG + case DB_LOCK_DUMP: + /* Find the locker. */ + if ((ret = __lock_getobj(lt, locker, + NULL, DB_LOCK_LOCKER, &sh_locker)) != 0) + break; + + for (lp = SH_LIST_FIRST(&sh_locker->heldby, __db_lock); + lp != NULL; + lp = SH_LIST_NEXT(lp, locker_links, __db_lock)) { + __lock_printlock(lt, lp, 1); + ret = EINVAL; + } + if (ret == 0) { + __lock_freeobj(lt, sh_locker); + lt->region->nlockers--; + } + break; +#endif + default: + ret = EINVAL; + break; + } + } + + if (lt->region->need_dd && lt->region->detect != DB_LOCK_NORUN) { + run_dd = 1; + lt->region->need_dd = 0; + } else + run_dd = 0; + + UNLOCK_LOCKREGION(lt); + + if (ret == 0 && run_dd) + lock_detect(lt, 0, lt->region->detect); + + if (elistp && ret != 0) + *elistp = &list[i - 1]; + return (ret); +} + +int +lock_get(lt, locker, flags, obj, lock_mode, lock) + DB_LOCKTAB *lt; + u_int32_t locker; + int flags; + const DBT *obj; + db_lockmode_t lock_mode; + DB_LOCK *lock; +{ + struct __db_lock *lockp; + int ret; + + /* Validate arguments. */ + if ((ret = + __db_fchk(lt->dbenv, "lock_get", flags, DB_LOCK_NOWAIT)) != 0) + return (ret); + + LOCK_LOCKREGION(lt); + + ret = __lock_validate_region(lt); + if (ret == 0 && (ret = __lock_get_internal(lt, + locker, flags, obj, lock_mode, &lockp)) == 0) { + *lock = LOCK_TO_OFFSET(lt, lockp); + lt->region->nrequests++; + } + + UNLOCK_LOCKREGION(lt); + return (ret); +} + +int +lock_put(lt, lock) + DB_LOCKTAB *lt; + DB_LOCK lock; +{ + struct __db_lock *lockp; + int ret, run_dd; + + LOCK_LOCKREGION(lt); + + if ((ret = __lock_validate_region(lt)) != 0) + return (ret); + else { + lockp = OFFSET_TO_LOCK(lt, lock); + ret = __lock_put_internal(lt, lockp, 0); + } + + __lock_checklocker(lt, lockp, 0); + + if (lt->region->need_dd && lt->region->detect != DB_LOCK_NORUN) { + run_dd = 1; + lt->region->need_dd = 0; + } else + run_dd = 0; + + UNLOCK_LOCKREGION(lt); + + if (ret == 0 && run_dd) + lock_detect(lt, 0, lt->region->detect); + + return (ret); +} + +int +lock_close(lt) + DB_LOCKTAB *lt; +{ + int ret; + + if ((ret = __db_rclose(lt->dbenv, lt->fd, lt->region)) != 0) + return (ret); + + /* Free lock table. */ + free(lt); + return (0); +} + +int +lock_unlink(path, force, dbenv) + const char *path; + int force; + DB_ENV *dbenv; +{ + return (__db_runlink(dbenv, + DB_APP_NONE, path, DB_DEFAULT_LOCK_FILE, force)); +} + +/* + * XXX This looks like it could be void, but I'm leaving it returning + * an int because I think it will have to when we go through and add + * the appropriate error checking for the EINTR on mutexes. + */ +static int +__lock_put_internal(lt, lockp, do_all) + DB_LOCKTAB *lt; + struct __db_lock *lockp; + int do_all; +{ + struct __db_lock *lp_w, *lp_h, *next_waiter; + DB_LOCKOBJ *sh_obj; + int state_changed; + + if (lockp->refcount == 0 || (lockp->status != DB_LSTAT_HELD && + lockp->status != DB_LSTAT_WAITING) || lockp->obj == 0) { + __db_err(lt->dbenv, "lock_put: invalid lock %lu", + (u_long)((u_int8_t *)lockp - (u_int8_t *)lt->region)); + return (EINVAL); + } + + if (do_all) + lt->region->nreleases += lockp->refcount; + else + lt->region->nreleases++; + if (do_all == 0 && lockp->refcount > 1) { + lockp->refcount--; + return (0); + } + + /* Get the object associated with this lock. */ + sh_obj = (DB_LOCKOBJ *)((u_int8_t *)lockp + lockp->obj); + + /* Remove lock from locker list. */ + SH_LIST_REMOVE(lockp, locker_links, __db_lock); + + /* Remove this lock from its holders/waitlist. */ + if (lockp->status != DB_LSTAT_HELD) + __lock_remove_waiter(lt, sh_obj, lockp, DB_LSTAT_FREE); + else + SH_TAILQ_REMOVE(&sh_obj->holders, lockp, links, __db_lock); + + /* + * We need to do lock promotion. We also need to determine if + * we're going to need to run the deadlock detector again. If + * we release locks, and there are waiters, but no one gets promoted, + * then we haven't fundamentally changed the lockmgr state, so + * we may still have a deadlock and we have to run again. However, + * if there were no waiters, or we actually promoted someone, then + * we are OK and we don't have to run it immediately. + */ + for (lp_w |
