/*- * See the file LICENSE for redistribution information. * * Copyright (c) 1996, 1997 * Sleepycat Software. All rights reserved. */ #include "config.h" #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1997\n\ Sleepycat Software Inc. All rights reserved.\n"; static const char sccsid[] = "@(#)db_deadlock.c 10.14 (Sleepycat) 8/27/97"; #endif #ifndef NO_SYSTEM_INCLUDES #include #include #include #include #include #include #include #include #endif #include "db_int.h" #include "clib_ext.h" #include "common_ext.h" #define BAD_KILLID 0xffffffff DB_ENV *db_init __P((char *, int)); int logpid __P((char *, int)); int main __P((int, char *[])); void onint __P((int)); void siginit __P((void)); void usage __P((void)); int interrupted; const char *progname = "db_deadlock"; /* Program name. */ int main(argc, argv) int argc; char *argv[]; { extern char *optarg; extern int optind; DB_ENV *dbenv; u_int32_t atype; time_t now; long seconds; int ch, flags, verbose; char *home, *logfile; atype = DB_LOCK_DEFAULT; home = logfile = NULL; seconds = 0; flags = verbose = 0; while ((ch = getopt(argc, argv, "a:h:L:t:vw")) != EOF) switch (ch) { case 'a': switch (optarg[0]) { case 'o': atype = DB_LOCK_OLDEST; break; case 'y': atype = DB_LOCK_YOUNGEST; break; default: usage(); /* NOTREACHED */ } if (optarg[1] != '\0') usage(); break; case 'h': home = optarg; break; case 'L': logfile = optarg; break; case 't': get_long(optarg, 1, LONG_MAX, &seconds); break; case 'v': verbose = 1; break; case 'w': LF_SET(DB_LOCK_CONFLICT); break; case '?': default: usage(); } argc -= optind; argv += optind; if (argc != 0) usage(); if (seconds == 0 && !LF_ISSET(DB_LOCK_CONFLICT)) { warnx("at least one of -t and -w must be specified"); usage(); } /* * We detect every second when we're running in DB_LOCK_CONFLICT mode. */ if (seconds == 0) seconds = 1; /* Initialize the deadlock detector by opening the lock manager. */ dbenv = db_init(home, verbose); if (logfile != NULL && logpid(logfile, 1)) { (void)db_appexit(dbenv); return (1); } while (!interrupted) { if (dbenv->db_verbose != 0) { time(&now); __db_err(dbenv, "Running at %s", ctime(&now)); } if ((errno = lock_detect(dbenv->lk_info, flags, atype)) != 0) break; /* Make a pass every "seconds" seconds. */ (void)__db_sleep(seconds, 0); } if (logfile != NULL) (void)logpid(logfile, 0); if (interrupted) { (void)signal(interrupted, SIG_DFL); (void)raise(interrupted); /* NOTREACHED */ } return (db_appexit(dbenv)); } DB_ENV * db_init(home, verbose) char *home; int verbose; { DB_ENV *dbenv; if ((dbenv = (DB_ENV *)calloc(sizeof(DB_ENV), 1)) == NULL) { errno = ENOMEM; err(1, NULL); } dbenv->db_errfile = stderr; dbenv->db_errpfx = progname; dbenv->db_verbose = verbose; if ((errno = db_appinit(home, NULL, dbenv, DB_INIT_LOCK | DB_USE_ENVIRON)) != 0) err(1, "db_appinit"); siginit(); return (dbenv); } /* * logpid -- * Log that we're running. */ int logpid(fname, is_open) char *fname; int is_open; { FILE *fp; time_t now; if (is_open) { if ((fp = fopen(fname, "w")) == NULL) { warn("%s", fname); return (1); } (void)time(&now); fprintf(fp, "%s: %lu %s", progname, (u_long)getpid(), ctime(&now)); fclose(fp); } else (void)remove(fname); return (0); } /* * siginit -- * Initialize the set of signals for which we want to clean up. * Generally, we try not to leave the shared regions locked if * we can. */ void siginit() { #ifdef SIGHUP (void)signal(SIGHUP, onint); #endif (void)signal(SIGINT, onint); #ifdef SIGKILL (void)signal(SIGKILL, onint); #endif (void)signal(SIGTERM, onint); } /* * oninit -- * Interrupt signal handler. */ void onint(signo) int signo; { if ((interrupted = signo) == 0) interrupted = SIGINT; } void usage() { (void)fprintf(stderr, "usage: db_deadlock [-vw] [-a m | o | y] [-h home] [-L file] [-t sec]\n"); exit(1); }