00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "db_config.h"
00011
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014
00015 #include <stdlib.h>
00016 #include <string.h>
00017 #include <tcl.h>
00018 #endif
00019
00020 #include "db_int.h"
00021 #include "dbinc/tcl_db.h"
00022
00023
00024
00025
00026 #ifdef CONFIG_TEST
00027 static int lock_Cmd __P((ClientData, Tcl_Interp *, int, Tcl_Obj * CONST*));
00028 static int _LockMode __P((Tcl_Interp *, Tcl_Obj *, db_lockmode_t *));
00029 static int _GetThisLock __P((Tcl_Interp *, DB_ENV *, u_int32_t,
00030 u_int32_t, DBT *, db_lockmode_t, char *));
00031 static void _LockPutInfo __P((Tcl_Interp *, db_lockop_t, DB_LOCK *,
00032 u_int32_t, DBT *));
00033
00034
00035
00036
00037
00038
00039
00040 int
00041 tcl_LockDetect(interp, objc, objv, envp)
00042 Tcl_Interp *interp;
00043 int objc;
00044 Tcl_Obj *CONST objv[];
00045 DB_ENV *envp;
00046 {
00047 static const char *ldopts[] = {
00048 "default",
00049 "expire",
00050 "maxlocks",
00051 "maxwrites",
00052 "minlocks",
00053 "minwrites",
00054 "oldest",
00055 "random",
00056 "youngest",
00057 NULL
00058 };
00059 enum ldopts {
00060 LD_DEFAULT,
00061 LD_EXPIRE,
00062 LD_MAXLOCKS,
00063 LD_MAXWRITES,
00064 LD_MINLOCKS,
00065 LD_MINWRITES,
00066 LD_OLDEST,
00067 LD_RANDOM,
00068 LD_YOUNGEST
00069 };
00070 u_int32_t flag, policy;
00071 int i, optindex, result, ret;
00072
00073 result = TCL_OK;
00074 flag = policy = 0;
00075 i = 2;
00076 while (i < objc) {
00077 if (Tcl_GetIndexFromObj(interp, objv[i],
00078 ldopts, "option", TCL_EXACT, &optindex) != TCL_OK)
00079 return (IS_HELP(objv[i]));
00080 i++;
00081 switch ((enum ldopts)optindex) {
00082 case LD_DEFAULT:
00083 FLAG_CHECK(policy);
00084 policy = DB_LOCK_DEFAULT;
00085 break;
00086 case LD_EXPIRE:
00087 FLAG_CHECK(policy);
00088 policy = DB_LOCK_EXPIRE;
00089 break;
00090 case LD_MAXLOCKS:
00091 FLAG_CHECK(policy);
00092 policy = DB_LOCK_MAXLOCKS;
00093 break;
00094 case LD_MAXWRITES:
00095 FLAG_CHECK(policy);
00096 policy = DB_LOCK_MAXWRITE;
00097 break;
00098 case LD_MINLOCKS:
00099 FLAG_CHECK(policy);
00100 policy = DB_LOCK_MINLOCKS;
00101 break;
00102 case LD_MINWRITES:
00103 FLAG_CHECK(policy);
00104 policy = DB_LOCK_MINWRITE;
00105 break;
00106 case LD_OLDEST:
00107 FLAG_CHECK(policy);
00108 policy = DB_LOCK_OLDEST;
00109 break;
00110 case LD_RANDOM:
00111 FLAG_CHECK(policy);
00112 policy = DB_LOCK_RANDOM;
00113 break;
00114 case LD_YOUNGEST:
00115 FLAG_CHECK(policy);
00116 policy = DB_LOCK_YOUNGEST;
00117 break;
00118 }
00119 }
00120
00121 _debug_check();
00122 ret = envp->lock_detect(envp, flag, policy, NULL);
00123 result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "lock detect");
00124 return (result);
00125 }
00126
00127
00128
00129
00130
00131
00132
00133 int
00134 tcl_LockGet(interp, objc, objv, envp)
00135 Tcl_Interp *interp;
00136 int objc;
00137 Tcl_Obj *CONST objv[];
00138 DB_ENV *envp;
00139 {
00140 static const char *lgopts[] = {
00141 "-nowait",
00142 NULL
00143 };
00144 enum lgopts {
00145 LGNOWAIT
00146 };
00147 DBT obj;
00148 Tcl_Obj *res;
00149 void *otmp;
00150 db_lockmode_t mode;
00151 u_int32_t flag, lockid;
00152 int freeobj, optindex, result, ret;
00153 char newname[MSG_SIZE];
00154
00155 result = TCL_OK;
00156 freeobj = 0;
00157 memset(newname, 0, MSG_SIZE);
00158 if (objc != 5 && objc != 6) {
00159 Tcl_WrongNumArgs(interp, 2, objv, "?-nowait? mode id obj");
00160 return (TCL_ERROR);
00161 }
00162
00163
00164
00165
00166
00167
00168 memset(&obj, 0, sizeof(obj));
00169
00170 if ((result =
00171 _GetUInt32(interp, objv[objc-2], &lockid)) != TCL_OK)
00172 return (result);
00173
00174 ret = _CopyObjBytes(interp, objv[objc-1], &otmp,
00175 &obj.size, &freeobj);
00176 if (ret != 0) {
00177 result = _ReturnSetup(interp, ret,
00178 DB_RETOK_STD(ret), "lock get");
00179 return (result);
00180 }
00181 obj.data = otmp;
00182 if ((result = _LockMode(interp, objv[(objc - 3)], &mode)) != TCL_OK)
00183 goto out;
00184
00185
00186
00187
00188 flag = 0;
00189 if (objc == 6) {
00190 if (Tcl_GetIndexFromObj(interp, objv[(objc - 4)],
00191 lgopts, "option", TCL_EXACT, &optindex) != TCL_OK)
00192 return (IS_HELP(objv[(objc - 4)]));
00193 switch ((enum lgopts)optindex) {
00194 case LGNOWAIT:
00195 flag |= DB_LOCK_NOWAIT;
00196 break;
00197 }
00198 }
00199
00200 result = _GetThisLock(interp, envp, lockid, flag, &obj, mode, newname);
00201 if (result == TCL_OK) {
00202 res = NewStringObj(newname, strlen(newname));
00203 Tcl_SetObjResult(interp, res);
00204 }
00205 out:
00206 if (freeobj)
00207 __os_free(envp, otmp);
00208 return (result);
00209 }
00210
00211
00212
00213
00214
00215
00216
00217 int
00218 tcl_LockStat(interp, objc, objv, envp)
00219 Tcl_Interp *interp;
00220 int objc;
00221 Tcl_Obj *CONST objv[];
00222 DB_ENV *envp;
00223 {
00224 DB_LOCK_STAT *sp;
00225 Tcl_Obj *res;
00226 int result, ret;
00227
00228 result = TCL_OK;
00229
00230
00231
00232 if (objc != 2) {
00233 Tcl_WrongNumArgs(interp, 2, objv, NULL);
00234 return (TCL_ERROR);
00235 }
00236 _debug_check();
00237 ret = envp->lock_stat(envp, &sp, 0);
00238 result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "lock stat");
00239 if (result == TCL_ERROR)
00240 return (result);
00241
00242
00243
00244
00245 res = Tcl_NewObj();
00246
00247
00248
00249 MAKE_STAT_LIST("Region size", sp->st_regsize);
00250 MAKE_STAT_LIST("Last allocated locker ID", sp->st_id);
00251 MAKE_STAT_LIST("Current maximum unused locker ID", sp->st_cur_maxid);
00252 MAKE_STAT_LIST("Maximum locks", sp->st_maxlocks);
00253 MAKE_STAT_LIST("Maximum lockers", sp->st_maxlockers);
00254 MAKE_STAT_LIST("Maximum objects", sp->st_maxobjects);
00255 MAKE_STAT_LIST("Lock modes", sp->st_nmodes);
00256 MAKE_STAT_LIST("Current number of locks", sp->st_nlocks);
00257 MAKE_STAT_LIST("Maximum number of locks so far", sp->st_maxnlocks);
00258 MAKE_STAT_LIST("Current number of lockers", sp->st_nlockers);
00259 MAKE_STAT_LIST("Maximum number of lockers so far", sp->st_maxnlockers);
00260 MAKE_STAT_LIST("Current number of objects", sp->st_nobjects);
00261 MAKE_STAT_LIST("Maximum number of objects so far", sp->st_maxnobjects);
00262 MAKE_STAT_LIST("Lock requests", sp->st_nrequests);
00263 MAKE_STAT_LIST("Lock releases", sp->st_nreleases);
00264 MAKE_STAT_LIST("Lock upgrades", sp->st_nupgrade);
00265 MAKE_STAT_LIST("Lock downgrades", sp->st_ndowngrade);
00266 MAKE_STAT_LIST("Number of conflicted locks for which we waited",
00267 sp->st_lock_wait);
00268 MAKE_STAT_LIST("Number of conflicted locks for which we did not wait",
00269 sp->st_lock_nowait);
00270 MAKE_STAT_LIST("Deadlocks detected", sp->st_ndeadlocks);
00271 MAKE_STAT_LIST("Number of region lock waits", sp->st_region_wait);
00272 MAKE_STAT_LIST("Number of region lock nowaits", sp->st_region_nowait);
00273 MAKE_STAT_LIST("Lock timeout value", sp->st_locktimeout);
00274 MAKE_STAT_LIST("Number of lock timeouts", sp->st_nlocktimeouts);
00275 MAKE_STAT_LIST("Transaction timeout value", sp->st_txntimeout);
00276 MAKE_STAT_LIST("Number of transaction timeouts", sp->st_ntxntimeouts);
00277 Tcl_SetObjResult(interp, res);
00278 error:
00279 __os_ufree(envp, sp);
00280 return (result);
00281 }
00282
00283
00284
00285
00286
00287
00288
00289 int
00290 tcl_LockTimeout(interp, objc, objv, envp)
00291 Tcl_Interp *interp;
00292 int objc;
00293 Tcl_Obj *CONST objv[];
00294 DB_ENV *envp;
00295 {
00296 long timeout;
00297 int result, ret;
00298
00299
00300
00301
00302 if (objc != 3) {
00303 Tcl_WrongNumArgs(interp, 2, objv, "?timeout?");
00304 return (TCL_ERROR);
00305 }
00306 result = Tcl_GetLongFromObj(interp, objv[2], &timeout);
00307 if (result != TCL_OK)
00308 return (result);
00309 _debug_check();
00310 ret = envp->set_timeout(envp, (u_int32_t)timeout, DB_SET_LOCK_TIMEOUT);
00311 result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "lock timeout");
00312 return (result);
00313 }
00314
00315
00316
00317
00318
00319 static int
00320 lock_Cmd(clientData, interp, objc, objv)
00321 ClientData clientData;
00322 Tcl_Interp *interp;
00323 int objc;
00324 Tcl_Obj *CONST objv[];
00325 {
00326 static const char *lkcmds[] = {
00327 "put",
00328 NULL
00329 };
00330 enum lkcmds {
00331 LKPUT
00332 };
00333 DB_ENV *env;
00334 DB_LOCK *lock;
00335 DBTCL_INFO *lkip;
00336 int cmdindex, result, ret;
00337
00338 Tcl_ResetResult(interp);
00339 lock = (DB_LOCK *)clientData;
00340 lkip = _PtrToInfo((void *)lock);
00341 result = TCL_OK;
00342
00343 if (lock == NULL) {
00344 Tcl_SetResult(interp, "NULL lock", TCL_STATIC);
00345 return (TCL_ERROR);
00346 }
00347 if (lkip == NULL) {
00348 Tcl_SetResult(interp, "NULL lock info pointer", TCL_STATIC);
00349 return (TCL_ERROR);
00350 }
00351
00352 env = NAME_TO_ENV(lkip->i_parent->i_name);
00353
00354
00355
00356 if (objc != 2) {
00357 Tcl_WrongNumArgs(interp, 2, objv, NULL);
00358 return (TCL_ERROR);
00359 }
00360
00361
00362
00363
00364 if (Tcl_GetIndexFromObj(interp,
00365 objv[1], lkcmds, "command", TCL_EXACT, &cmdindex) != TCL_OK)
00366 return (IS_HELP(objv[1]));
00367
00368 switch ((enum lkcmds)cmdindex) {
00369 case LKPUT:
00370 _debug_check();
00371 ret = env->lock_put(env, lock);
00372 result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
00373 "lock put");
00374 (void)Tcl_DeleteCommand(interp, lkip->i_name);
00375 _DeleteInfo(lkip);
00376 __os_free(env, lock);
00377 break;
00378 }
00379 return (result);
00380 }
00381
00382
00383
00384
00385
00386
00387 int
00388 tcl_LockVec(interp, objc, objv, envp)
00389 Tcl_Interp *interp;
00390 int objc;
00391 Tcl_Obj *CONST objv[];
00392 DB_ENV *envp;
00393 {
00394 static const char *lvopts[] = {
00395 "-nowait",
00396 NULL
00397 };
00398 enum lvopts {
00399 LVNOWAIT
00400 };
00401 static const char *lkops[] = {
00402 "get",
00403 "put",
00404 "put_all",
00405 "put_obj",
00406 "timeout",
00407 NULL
00408 };
00409 enum lkops {
00410 LKGET,
00411 LKPUT,
00412 LKPUTALL,
00413 LKPUTOBJ,
00414 LKTIMEOUT
00415 };
00416
00417 DB_LOCK *lock;
00418 DB_LOCKREQ list;
00419 DBT obj;
00420 Tcl_Obj **myobjv, *res, *thisop;
00421 void *otmp;
00422 u_int32_t flag, lockid;
00423 int freeobj, i, myobjc, optindex, result, ret;
00424 char *lockname, msg[MSG_SIZE], newname[MSG_SIZE];
00425
00426 result = TCL_OK;
00427 memset(newname, 0, MSG_SIZE);
00428 memset(&list, 0, sizeof(DB_LOCKREQ));
00429 flag = 0;
00430 freeobj = 0;
00431 otmp = NULL;
00432
00433
00434
00435
00436 if (Tcl_GetIndexFromObj(interp, objv[2],
00437 lvopts, "option", TCL_EXACT, &optindex) == TCL_OK) {
00438 switch ((enum lvopts)optindex) {
00439 case LVNOWAIT:
00440 flag |= DB_LOCK_NOWAIT;
00441 break;
00442 }
00443 i = 3;
00444 } else {
00445 if (IS_HELP(objv[2]) == TCL_OK)
00446 return (TCL_OK);
00447 Tcl_ResetResult(interp);
00448 i = 2;
00449 }
00450
00451
00452
00453
00454 result = _GetUInt32(interp, objv[i++], &lockid);
00455 if (result != TCL_OK)
00456 return (result);
00457
00458
00459
00460
00461
00462
00463 res = Tcl_NewListObj(0, NULL);
00464 while (i < objc) {
00465
00466
00467
00468 lock = NULL;
00469 result = Tcl_ListObjGetElements(interp, objv[i],
00470 &myobjc, &myobjv);
00471 if (result == TCL_OK)
00472 i++;
00473 else
00474 break;
00475
00476
00477
00478
00479
00480
00481 if (Tcl_GetIndexFromObj(interp, myobjv[0],
00482 lkops, "option", TCL_EXACT, &optindex) != TCL_OK) {
00483 result = IS_HELP(myobjv[0]);
00484 goto error;
00485 }
00486 switch ((enum lkops)optindex) {
00487 case LKGET:
00488 if (myobjc != 3) {
00489 Tcl_WrongNumArgs(interp, 1, myobjv,
00490 "{get obj mode}");
00491 result = TCL_ERROR;
00492 goto error;
00493 }
00494 result = _LockMode(interp, myobjv[2], &list.mode);
00495 if (result != TCL_OK)
00496 goto error;
00497 ret = _CopyObjBytes(interp, myobjv[1], &otmp,
00498 &obj.size, &freeobj);
00499 if (ret != 0) {
00500 result = _ReturnSetup(interp, ret,
00501 DB_RETOK_STD(ret), "lock vec");
00502 return (result);
00503 }
00504 obj.data = otmp;
00505 ret = _GetThisLock(interp, envp, lockid, flag,
00506 &obj, list.mode, newname);
00507 if (ret != 0) {
00508 result = _ReturnSetup(interp, ret,
00509 DB_RETOK_STD(ret), "lock vec");
00510 thisop = Tcl_NewIntObj(ret);
00511 (void)Tcl_ListObjAppendElement(interp, res,
00512 thisop);
00513 goto error;
00514 }
00515 thisop = NewStringObj(newname, strlen(newname));
00516 (void)Tcl_ListObjAppendElement(interp, res, thisop);
00517 if (freeobj && otmp != NULL) {
00518 __os_free(envp, otmp);
00519 freeobj = 0;
00520 }
00521 continue;
00522 case LKPUT:
00523 if (myobjc != 2) {
00524 Tcl_WrongNumArgs(interp, 1, myobjv,
00525 "{put lock}");
00526 result = TCL_ERROR;
00527 goto error;
00528 }
00529 list.op = DB_LOCK_PUT;
00530 lockname = Tcl_GetStringFromObj(myobjv[1], NULL);
00531 lock = NAME_TO_LOCK(lockname);
00532 if (lock == NULL) {
00533 snprintf(msg, MSG_SIZE, "Invalid lock: %s\n",
00534 lockname);
00535 Tcl_SetResult(interp, msg, TCL_VOLATILE);
00536 result = TCL_ERROR;
00537 goto error;
00538 }
00539 list.lock = *lock;
00540 break;
00541 case LKPUTALL:
00542 if (myobjc != 1) {
00543 Tcl_WrongNumArgs(interp, 1, myobjv,
00544 "{put_all}");
00545 result = TCL_ERROR;
00546 goto error;
00547 }
00548 list.op = DB_LOCK_PUT_ALL;
00549 break;
00550 case LKPUTOBJ:
00551 if (myobjc != 2) {
00552 Tcl_WrongNumArgs(interp, 1, myobjv,
00553 "{put_obj obj}");
00554 result = TCL_ERROR;
00555 goto error;
00556 }
00557 list.op = DB_LOCK_PUT_OBJ;
00558 ret = _CopyObjBytes(interp, myobjv[1], &otmp,
00559 &obj.size, &freeobj);
00560 if (ret != 0) {
00561 result = _ReturnSetup(interp, ret,
00562 DB_RETOK_STD(ret), "lock vec");
00563 return (result);
00564 }
00565 obj.data = otmp;
00566 list.obj = &obj;
00567 break;
00568 case LKTIMEOUT:
00569 list.op = DB_LOCK_TIMEOUT;
00570 break;
00571
00572 }
00573
00574
00575
00576
00577 _debug_check();
00578 ret = envp->lock_vec(envp, lockid, flag, &list, 1, NULL);
00579
00580
00581
00582
00583 thisop = Tcl_NewIntObj(ret);
00584 result = Tcl_ListObjAppendElement(interp, res, thisop);
00585 if (ret != 0 && result == TCL_OK)
00586 result = _ReturnSetup(interp, ret,
00587 DB_RETOK_STD(ret), "lock put");
00588 if (freeobj && otmp != NULL) {
00589 __os_free(envp, otmp);
00590 freeobj = 0;
00591 }
00592
00593
00594
00595
00596
00597 _LockPutInfo(interp, list.op, lock, lockid, &obj);
00598 }
00599
00600 if (result == TCL_OK && res)
00601 Tcl_SetObjResult(interp, res);
00602 error:
00603 return (result);
00604 }
00605
00606 static int
00607 _LockMode(interp, obj, mode)
00608 Tcl_Interp *interp;
00609 Tcl_Obj *obj;
00610 db_lockmode_t *mode;
00611 {
00612 static const char *lkmode[] = {
00613 "ng",
00614 "read",
00615 "write",
00616 "iwrite",
00617 "iread",
00618 "iwr",
00619 NULL
00620 };
00621 enum lkmode {
00622 LK_NG,
00623 LK_READ,
00624 LK_WRITE,
00625 LK_IWRITE,
00626 LK_IREAD,
00627 LK_IWR
00628 };
00629 int optindex;
00630
00631 if (Tcl_GetIndexFromObj(interp, obj, lkmode, "option",
00632 TCL_EXACT, &optindex) != TCL_OK)
00633 return (IS_HELP(obj));
00634 switch ((enum lkmode)optindex) {
00635 case LK_NG:
00636 *mode = DB_LOCK_NG;
00637 break;
00638 case LK_READ:
00639 *mode = DB_LOCK_READ;
00640 break;
00641 case LK_WRITE:
00642 *mode = DB_LOCK_WRITE;
00643 break;
00644 case LK_IREAD:
00645 *mode = DB_LOCK_IREAD;
00646 break;
00647 case LK_IWRITE:
00648 *mode = DB_LOCK_IWRITE;
00649 break;
00650 case LK_IWR:
00651 *mode = DB_LOCK_IWR;
00652 break;
00653 }
00654 return (TCL_OK);
00655 }
00656
00657 static void
00658 _LockPutInfo(interp, op, lock, lockid, objp)
00659 Tcl_Interp *interp;
00660 db_lockop_t op;
00661 DB_LOCK *lock;
00662 u_int32_t lockid;
00663 DBT *objp;
00664 {
00665 DBTCL_INFO *p, *nextp;
00666 int found;
00667
00668 for (p = LIST_FIRST(&__db_infohead); p != NULL; p = nextp) {
00669 found = 0;
00670 nextp = LIST_NEXT(p, entries);
00671 if ((op == DB_LOCK_PUT && (p->i_lock == lock)) ||
00672 (op == DB_LOCK_PUT_ALL && p->i_locker == lockid) ||
00673 (op == DB_LOCK_PUT_OBJ && p->i_lockobj.data &&
00674 memcmp(p->i_lockobj.data, objp->data, objp->size) == 0))
00675 found = 1;
00676 if (found) {
00677 (void)Tcl_DeleteCommand(interp, p->i_name);
00678 __os_free(NULL, p->i_lock);
00679 _DeleteInfo(p);
00680 }
00681 }
00682 }
00683
00684 static int
00685 _GetThisLock(interp, envp, lockid, flag, objp, mode, newname)
00686 Tcl_Interp *interp;
00687 DB_ENV *envp;
00688 u_int32_t lockid;
00689 u_int32_t flag;
00690 DBT *objp;
00691 db_lockmode_t mode;
00692 char *newname;
00693 {
00694 DB_LOCK *lock;
00695 DBTCL_INFO *envip, *ip;
00696 int result, ret;
00697
00698 result = TCL_OK;
00699 envip = _PtrToInfo((void *)envp);
00700 if (envip == NULL) {
00701 Tcl_SetResult(interp, "Could not find env info\n", TCL_STATIC);
00702 return (TCL_ERROR);
00703 }
00704 snprintf(newname, MSG_SIZE, "%s.lock%d",
00705 envip->i_name, envip->i_envlockid);
00706 ip = _NewInfo(interp, NULL, newname, I_LOCK);
00707 if (ip == NULL) {
00708 Tcl_SetResult(interp, "Could not set up info",
00709 TCL_STATIC);
00710 return (TCL_ERROR);
00711 }
00712 ret = __os_malloc(envp, sizeof(DB_LOCK), &lock);
00713 if (ret != 0) {
00714 Tcl_SetResult(interp, db_strerror(ret), TCL_STATIC);
00715 return (TCL_ERROR);
00716 }
00717 _debug_check();
00718 ret = envp->lock_get(envp, lockid, flag, objp, mode, lock);
00719 result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "lock get");
00720 if (result == TCL_ERROR) {
00721 __os_free(envp, lock);
00722 _DeleteInfo(ip);
00723 return (result);
00724 }
00725
00726
00727
00728
00729 ret = __os_malloc(envp, objp->size, &ip->i_lockobj.data);
00730 if (ret != 0) {
00731 Tcl_SetResult(interp, "Could not duplicate obj",
00732 TCL_STATIC);
00733 (void)envp->lock_put(envp, lock);
00734 __os_free(envp, lock);
00735 _DeleteInfo(ip);
00736 result = TCL_ERROR;
00737 goto error;
00738 }
00739 memcpy(ip->i_lockobj.data, objp->data, objp->size);
00740 ip->i_lockobj.size = objp->size;
00741 envip->i_envlockid++;
00742 ip->i_parent = envip;
00743 ip->i_locker = lockid;
00744 _SetInfoData(ip, lock);
00745 (void)Tcl_CreateObjCommand(interp, newname,
00746 (Tcl_ObjCmdProc *)lock_Cmd, (ClientData)lock, NULL);
00747 error:
00748 return (result);
00749 }
00750 #endif