mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-05 16:46:26 +00:00
404 lines
9.2 KiB
C
404 lines
9.2 KiB
C
|
/*-
|
||
|
* See the file LICENSE for redistribution information.
|
||
|
*
|
||
|
* Copyright (c) 1996, 1997, 1998
|
||
|
* Sleepycat Software. All rights reserved.
|
||
|
*/
|
||
|
|
||
|
#include "config.h"
|
||
|
|
||
|
#ifndef lint
|
||
|
static const char sccsid[] = "@(#)tcl_lock.c 10.10 (Sleepycat) 4/10/98";
|
||
|
#endif /* not lint */
|
||
|
|
||
|
/*
|
||
|
* This file is divided up into 4 sets of functions:
|
||
|
* 1. The lock command and its support functions.
|
||
|
* 2. The lock_unlink command.
|
||
|
* 3. The lock manager widget commands.
|
||
|
* 4. The lock widget commands.
|
||
|
*/
|
||
|
|
||
|
#ifndef NO_SYSTEM_INCLUDES
|
||
|
#include <sys/types.h>
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <errno.h>
|
||
|
#endif
|
||
|
#include <tcl.h>
|
||
|
|
||
|
#include "db_int.h"
|
||
|
#include "dbtest.h"
|
||
|
#include "test_ext.h"
|
||
|
|
||
|
/* Internal functions */
|
||
|
|
||
|
static int do_lockvec __P((Tcl_Interp *, DB_LOCKTAB *, int, char **));
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
void __lock_dump_region __P((DB_LOCKTAB *, unsigned long));
|
||
|
#endif
|
||
|
typedef struct _mgr_data {
|
||
|
DB_LOCKTAB *tabp;
|
||
|
DB_ENV *env;
|
||
|
} mgr_data;
|
||
|
typedef struct _lock_data {
|
||
|
DB_LOCKTAB *tabp;
|
||
|
DB_LOCK lock;
|
||
|
} lock_data;
|
||
|
|
||
|
/*
|
||
|
* lock_cmd --
|
||
|
* Implements lock_open for dbtest. Lock_open creates a lock
|
||
|
* manager and all the necessary files in the file system. It then
|
||
|
* creates a command that implements the other lock functions.
|
||
|
*/
|
||
|
|
||
|
#define LOCKMGR_USAGE "lock_open path flags mode [options]\n\toptions:\n"
|
||
|
|
||
|
int
|
||
|
lockmgr_cmd(notused, interp, argc, argv)
|
||
|
ClientData notused;
|
||
|
Tcl_Interp *interp;
|
||
|
int argc;
|
||
|
char *argv[];
|
||
|
{
|
||
|
static int mgr_number = 0;
|
||
|
DB_LOCKTAB *mgrp;
|
||
|
DB_ENV *env;
|
||
|
mgr_data *md;
|
||
|
u_int32_t flags;
|
||
|
int mode, ret, tclint;
|
||
|
char mgrname[50];
|
||
|
|
||
|
notused = NULL;
|
||
|
|
||
|
debug_check();
|
||
|
|
||
|
/* Check number of arguments. */
|
||
|
USAGE_GE(argc, 4, LOCKMGR_USAGE, DO_ENV);
|
||
|
if (Tcl_GetInt(interp, argv[2], &tclint) != TCL_OK ||
|
||
|
Tcl_GetInt(interp, argv[3], &mode) != TCL_OK)
|
||
|
return (TCL_ERROR);
|
||
|
flags = (u_int32_t)tclint;
|
||
|
|
||
|
/*
|
||
|
* Call lock_open.
|
||
|
*/
|
||
|
if (process_env_options(interp, argc, argv, &env)) {
|
||
|
Tcl_PosixError(interp);
|
||
|
Tcl_SetResult(interp, "NULL", TCL_STATIC);
|
||
|
return (TCL_OK);
|
||
|
}
|
||
|
|
||
|
if (F_ISSET(env, DB_ENV_STANDALONE))
|
||
|
mgrp = env->lk_info;
|
||
|
else if ((ret = lock_open(argv[1], flags, mode, env, &mgrp)) != 0) {
|
||
|
errno = ret;
|
||
|
Tcl_PosixError(interp);
|
||
|
Tcl_SetResult(interp, "NULL", TCL_STATIC);
|
||
|
return (TCL_OK);
|
||
|
} else
|
||
|
env->lk_info = mgrp;
|
||
|
|
||
|
/* Create new command name. */
|
||
|
if ((md = (mgr_data *)malloc(sizeof(mgr_data))) == NULL) {
|
||
|
if (!F_ISSET(env, DB_ENV_STANDALONE)) {
|
||
|
(void)db_appexit(env);
|
||
|
if (env->lk_conflicts)
|
||
|
free(env->lk_conflicts);
|
||
|
free(env);
|
||
|
}
|
||
|
Tcl_SetResult(interp, "lock_open: ", TCL_STATIC);
|
||
|
errno = ENOMEM;
|
||
|
Tcl_AppendResult(interp, Tcl_PosixError(interp), 0);
|
||
|
return (TCL_ERROR);
|
||
|
}
|
||
|
md->tabp = mgrp;
|
||
|
md->env = env;
|
||
|
sprintf(&mgrname[0], "lockmgr%d", mgr_number);
|
||
|
mgr_number++;
|
||
|
|
||
|
/* Create widget command. */
|
||
|
Tcl_CreateCommand(interp, mgrname, lockwidget_cmd, (int *)md, NULL);
|
||
|
Tcl_SetResult(interp, mgrname, TCL_VOLATILE);
|
||
|
return (TCL_OK);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* lockunlink_cmd --
|
||
|
* Implements lock_unlink for dbtest.
|
||
|
*/
|
||
|
|
||
|
#define LOCKUNLINK_USAGE "lock_unlink path force"
|
||
|
|
||
|
int
|
||
|
lockunlink_cmd(notused, interp, argc, argv)
|
||
|
ClientData notused;
|
||
|
Tcl_Interp *interp;
|
||
|
int argc;
|
||
|
char *argv[];
|
||
|
{
|
||
|
int force;
|
||
|
|
||
|
notused = NULL;
|
||
|
|
||
|
debug_check();
|
||
|
|
||
|
USAGE_GE(argc, 3, LOCKUNLINK_USAGE, 0);
|
||
|
|
||
|
if (Tcl_GetInt(interp, argv[2], &force) != TCL_OK)
|
||
|
return (TCL_ERROR);
|
||
|
|
||
|
if (lock_unlink(argv[1], force, NULL) != 0) {
|
||
|
Tcl_SetResult(interp, "-1", TCL_STATIC);
|
||
|
return (TCL_OK);
|
||
|
}
|
||
|
Tcl_SetResult(interp, "0", TCL_STATIC);
|
||
|
return (TCL_OK);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* lockwidget --
|
||
|
* This is that command that implements the lock widget. If we
|
||
|
* ever add new "methods" we add new widget commands here.
|
||
|
*/
|
||
|
#define LOCKWIDGET_USAGE "lockmgrN option ?arg arg ...?"
|
||
|
#define LOCKCLOSE_USAGE "lockmgrN close"
|
||
|
#define LOCKDUMP_USAGE "lockmgrN dump flags"
|
||
|
#define LOCKGET_USAGE "lockmgrN get locker obj mode flags"
|
||
|
#define LOCKVEC_USAGE \
|
||
|
"lockmgrN vec locker flags ?{obj mode op} {obj mode op}...?"
|
||
|
/* Not yet implemented. */
|
||
|
|
||
|
int
|
||
|
lockwidget_cmd(cd_mgr, interp, argc, argv)
|
||
|
ClientData cd_mgr;
|
||
|
Tcl_Interp *interp;
|
||
|
int argc;
|
||
|
char *argv[];
|
||
|
{
|
||
|
static int id = 0;
|
||
|
DB_LOCKTAB *mgr;
|
||
|
DB_LOCK lock;
|
||
|
DBT obj_dbt;
|
||
|
DB_ENV *env;
|
||
|
db_lockmode_t mode;
|
||
|
lock_data *ld;
|
||
|
u_int32_t locker, flags;
|
||
|
int ret, tclint;
|
||
|
char lockname[128];
|
||
|
|
||
|
debug_check();
|
||
|
|
||
|
mgr = ((mgr_data *)cd_mgr)->tabp;
|
||
|
|
||
|
USAGE_GE(argc, 2, LOCKWIDGET_USAGE, 0);
|
||
|
|
||
|
if (strcmp(argv[1], "close") == 0) {
|
||
|
USAGE(argc, 2, LOCKCLOSE_USAGE, 0);
|
||
|
env = ((mgr_data *)cd_mgr)->env;
|
||
|
if (!F_ISSET(env, DB_ENV_STANDALONE)) {
|
||
|
(void)db_appexit(env);
|
||
|
if (env->lk_conflicts)
|
||
|
free(env->lk_conflicts);
|
||
|
free(env);
|
||
|
}
|
||
|
Tcl_DeleteCommand(interp, argv[0]);
|
||
|
Tcl_SetResult(interp, "0", TCL_STATIC);
|
||
|
return (TCL_OK);
|
||
|
} else if (strcmp(argv[1], "get") == 0) {
|
||
|
USAGE(argc, 6, LOCKGET_USAGE, 0);
|
||
|
if (Tcl_GetInt(interp, argv[2], &tclint) != TCL_OK) {
|
||
|
Tcl_PosixError(interp);
|
||
|
return (TCL_ERROR);
|
||
|
}
|
||
|
locker = (u_int32_t)tclint;
|
||
|
obj_dbt.data = argv[3];
|
||
|
obj_dbt.size = strlen(argv[3]) + 1;
|
||
|
if (Tcl_GetInt(interp, argv[4], &tclint) != TCL_OK)
|
||
|
return (TCL_ERROR);
|
||
|
mode = tclint;
|
||
|
if (Tcl_GetInt(interp, argv[5], &tclint) != TCL_OK)
|
||
|
return (TCL_ERROR);
|
||
|
flags = (u_int32_t)tclint;
|
||
|
|
||
|
ret = lock_get(mgr, locker, flags, &obj_dbt, mode, &lock);
|
||
|
|
||
|
switch (ret) {
|
||
|
case 0: /* Success */
|
||
|
sprintf(&lockname[0], "%s.lock%d", argv[0], id);
|
||
|
id++;
|
||
|
if ((ld =
|
||
|
(lock_data *)malloc(sizeof(lock_data))) == NULL) {
|
||
|
Tcl_PosixError(interp);
|
||
|
return (TCL_OK);
|
||
|
}
|
||
|
|
||
|
ld->tabp = mgr;
|
||
|
ld->lock = lock;
|
||
|
|
||
|
Tcl_CreateCommand(interp,
|
||
|
lockname, lock_cmd, (int *)ld, NULL);
|
||
|
Tcl_SetResult(interp, lockname, TCL_VOLATILE);
|
||
|
break;
|
||
|
case DB_LOCK_NOTGRANTED:
|
||
|
Tcl_SetResult(interp, "BLOCKED", TCL_STATIC);
|
||
|
return (TCL_OK);
|
||
|
case DB_LOCK_DEADLOCK:
|
||
|
Tcl_SetResult(interp, "DEADLOCK", TCL_STATIC);
|
||
|
return (TCL_OK);
|
||
|
default:
|
||
|
Tcl_PosixError(interp);
|
||
|
return (TCL_ERROR);
|
||
|
}
|
||
|
} else if (strcmp(argv[1], "vec") == 0) {
|
||
|
USAGE(argc, 5, LOCKVEC_USAGE, 0);
|
||
|
return (do_lockvec(interp, mgr, argc, argv));
|
||
|
#ifdef DEBUG
|
||
|
} else if (strcmp(argv[1], "dump") == 0) {
|
||
|
USAGE(argc, 3, LOCKDUMP_USAGE, 0);
|
||
|
if (Tcl_GetInt(interp, argv[2], &tclint) != TCL_OK)
|
||
|
flags = 0xffff;
|
||
|
else
|
||
|
flags = (u_int32_t)tclint;
|
||
|
__lock_dump_region(mgr, flags);
|
||
|
return (TCL_OK);
|
||
|
#endif
|
||
|
} else {
|
||
|
Tcl_SetResult(interp, LOCKWIDGET_USAGE, TCL_STATIC);
|
||
|
return (TCL_ERROR);
|
||
|
}
|
||
|
return (TCL_OK);
|
||
|
}
|
||
|
|
||
|
#define LOCK_USAGE "lockmgrN.lockM cmd ?arg arg ...?"
|
||
|
#define LOCKPUT_USAGE "lockmgrN.lockM put"
|
||
|
int
|
||
|
lock_cmd(cd_lock, interp, argc, argv)
|
||
|
ClientData cd_lock;
|
||
|
Tcl_Interp *interp;
|
||
|
int argc;
|
||
|
char *argv[];
|
||
|
{
|
||
|
DB_LOCK lock;
|
||
|
DB_LOCKTAB *tab;
|
||
|
lock_data *ld;
|
||
|
int ret;
|
||
|
|
||
|
debug_check();
|
||
|
|
||
|
USAGE_GE(argc, 2, LOCK_USAGE, 0);
|
||
|
|
||
|
ld = (lock_data *)cd_lock;
|
||
|
lock = ld->lock;
|
||
|
tab = ld->tabp;
|
||
|
free(ld);
|
||
|
|
||
|
if (strcmp(argv[1], "put") == 0) {
|
||
|
USAGE(argc, 2, LOCKPUT_USAGE, 0);
|
||
|
Tcl_DeleteCommand(interp, argv[0]);
|
||
|
if ((ret = lock_put(tab, lock)) != 0) {
|
||
|
errno = ret;
|
||
|
Tcl_PosixError(interp);
|
||
|
return (TCL_OK);
|
||
|
}
|
||
|
} else {
|
||
|
Tcl_SetResult(interp, LOCK_USAGE, TCL_STATIC);
|
||
|
return (TCL_ERROR);
|
||
|
}
|
||
|
Tcl_SetResult(interp, "0", TCL_STATIC);
|
||
|
return (TCL_OK);
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
do_lockvec(interp, mgr, argc, argv)
|
||
|
Tcl_Interp *interp;
|
||
|
DB_LOCKTAB *mgr;
|
||
|
int argc;
|
||
|
char **argv;
|
||
|
{
|
||
|
DB_LOCKREQ *reqlist, *err;
|
||
|
DBT *dblist;
|
||
|
db_lockmode_t mode;
|
||
|
db_lockop_t iop;
|
||
|
u_int32_t flags, locker;
|
||
|
int i, ntup, nreqs, ret, tclint;
|
||
|
char **ap, **tuplist;
|
||
|
|
||
|
/* Get the locker id and the flags. */
|
||
|
if (Tcl_GetInt(interp, argv[2], &tclint) != TCL_OK)
|
||
|
return (TCL_ERROR);
|
||
|
locker = (u_int32_t)tclint;
|
||
|
if (Tcl_GetInt(interp, argv[3], &tclint) != TCL_OK)
|
||
|
return (TCL_ERROR);
|
||
|
flags = (u_int32_t)tclint;
|
||
|
|
||
|
/* The first three args are command, the rest are tuples. */
|
||
|
nreqs = argc - 4;
|
||
|
if ((reqlist =
|
||
|
(DB_LOCKREQ *)calloc(sizeof(DB_LOCKREQ), nreqs)) == NULL ||
|
||
|
(dblist = (DBT *)calloc(sizeof(DBT), nreqs)) == NULL) {
|
||
|
Tcl_PosixError(interp);
|
||
|
return (TCL_ERROR);
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < nreqs; i++)
|
||
|
reqlist[i].obj = &dblist[i];
|
||
|
|
||
|
for (ap = &argv[4], i = 0; i < nreqs; i++) {
|
||
|
tuplist = NULL;
|
||
|
if (Tcl_SplitList(interp, *ap, &ntup, &tuplist) != TCL_OK)
|
||
|
break;
|
||
|
if (Tcl_GetInt(interp, tuplist[1], &tclint) != TCL_OK)
|
||
|
break;
|
||
|
mode = (db_lockmode_t)tclint;
|
||
|
if (Tcl_GetInt(interp, tuplist[2], &tclint) != TCL_OK)
|
||
|
break;
|
||
|
iop = (db_lockop_t)tclint;
|
||
|
|
||
|
reqlist[i].op = iop;
|
||
|
reqlist[i].obj->data = (char *)strdup(tuplist[0]);
|
||
|
reqlist[i].obj->size = strlen(tuplist[0]);
|
||
|
reqlist[i].mode = mode;
|
||
|
|
||
|
free(tuplist);
|
||
|
}
|
||
|
|
||
|
if (tuplist == NULL || i != nreqs)
|
||
|
ret = TCL_ERROR;
|
||
|
else if ((ret =
|
||
|
lock_vec(mgr, locker, flags, reqlist, nreqs, &err)) != 0) {
|
||
|
Tcl_SetResult(interp, "lock_vec failed, returned ", TCL_STATIC);
|
||
|
switch (ret) {
|
||
|
case DB_LOCK_DEADLOCK:
|
||
|
Tcl_AppendResult(interp, "DEADLOCK", 0);
|
||
|
break;
|
||
|
case DB_LOCK_NOTHELD:
|
||
|
Tcl_AppendResult(interp, "NOTHELD", 0);
|
||
|
break;
|
||
|
case DB_LOCK_NOTGRANTED:
|
||
|
Tcl_AppendResult(interp, "NOTGRANTED", 0);
|
||
|
break;
|
||
|
default:
|
||
|
errno = ret;
|
||
|
Tcl_AppendResult(interp, Tcl_PosixError(interp), 0);
|
||
|
break;
|
||
|
}
|
||
|
Tcl_AppendResult(interp, " on request ",
|
||
|
argv[4 + (err - reqlist)], NULL);
|
||
|
ret = TCL_ERROR;
|
||
|
} else {
|
||
|
Tcl_SetResult(interp, "0", TCL_STATIC);
|
||
|
ret = TCL_OK;
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < nreqs; i++)
|
||
|
if (reqlist[i].obj->data != NULL)
|
||
|
free(reqlist[i].obj->data);
|
||
|
free(reqlist);
|
||
|
free(dblist);
|
||
|
return (ret);
|
||
|
}
|