Implement a "kill" DDB command which is an interface to psignal() that

respects locks.  Before SMPng, one was able to call psignal()
using the "call" command, but this is no longer possible because it
does not respect locks by itself.  This is very useful when one has
gotten their machine into a state where it is impossible to spawn
ps/kill or su to root.

In this case, respecting locks essentially means trying to aquire the
proc lock before calling psignal().  We can't block in the debugger,
so if trylock fails, the operation fails.  This also means that we
can't use pfind(), since that will attempt to lock the process for us.

Reviewed by:	jhb
This commit is contained in:
Dima Dorfman 2001-11-27 19:56:28 +00:00
parent 629c25d4a9
commit 19d2c78f34

View File

@ -36,7 +36,11 @@
*/
#include <sys/param.h>
#include <sys/linker_set.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/proc.h>
#include <sys/reboot.h>
#include <sys/signalvar.h>
#include <sys/systm.h>
#include <sys/cons.h>
@ -63,6 +67,7 @@ SET_DECLARE(db_show_cmd_set, struct command);
static db_cmdfcn_t db_fncall;
static db_cmdfcn_t db_gdb;
static db_cmdfcn_t db_kill;
static db_cmdfcn_t db_reset;
/* XXX this is actually forward-static. */
@ -418,6 +423,7 @@ static struct command db_command_table[] = {
{ "ps", db_ps, 0, 0 },
{ "gdb", db_gdb, 0, 0 },
{ "reset", db_reset, 0, 0 },
{ "kill", db_kill, CS_OWN, 0 },
{ (char *)0, }
};
@ -573,6 +579,59 @@ db_gdb (dummy1, dummy2, dummy3, dummy4)
: "DDB debugger");
}
static void
db_kill(dummy1, dummy2, dummy3, dummy4)
db_expr_t dummy1;
boolean_t dummy2;
db_expr_t dummy3;
char * dummy4;
{
db_expr_t old_radix, pid, sig;
struct proc *p;
#define DB_ERROR(f) do { db_printf f; db_flush_lex(); goto out; } while (0)
/*
* PIDs and signal numbers are typically represented in base
* 10, so make that the default here. It can, of course, be
* overridden by specifying a prefix.
*/
old_radix = db_radix;
db_radix = 10;
/* Retrieve arguments. */
if (!db_expression(&sig))
DB_ERROR(("Missing signal number\n"));
if (!db_expression(&pid))
DB_ERROR(("Missing process ID\n"));
db_skip_to_eol();
if (sig < 0 || sig > _SIG_MAXSIG)
DB_ERROR(("Signal number out of range\n"));
/*
* Find the process in question. allproc_lock is not needed
* since we're in DDB.
*/
/* sx_slock(&allproc_lock); */
LIST_FOREACH(p, &allproc, p_list)
if (p->p_pid == pid)
break;
/* sx_sunlock(&allproc_lock); */
if (p == NULL)
DB_ERROR(("Can't find process with pid %d\n", pid));
/* If it's already locked, bail; otherwise, do the deed. */
if (PROC_TRYLOCK(p) == 0)
DB_ERROR(("Can't lock process with pid %d\n", pid));
else {
psignal(p, sig);
PROC_UNLOCK(p);
}
out:
db_radix = old_radix;
#undef DB_ERROR
}
static void
db_reset(dummy1, dummy2, dummy3, dummy4)
db_expr_t dummy1;