/* debug.c -- common debugging routines for runtime system and MPDX */
#include "rts.h"
int mpd_dbg_flags = 0; /* currently enabled debugging options */
static Mutex debug_mutex; /* for coordinating debug outputs */
static char status_tag[MAX_STATUS+1]; /* mnemonics for status values */
/* mpd_init_debug (s) - set debug flags according to hex string s.
* In MultiMPD, must be called before job servers are created.
*/
void
mpd_init_debug (s)
char *s;
{
#ifndef NDEBUG
int i;
/*SUPPRESS 442*/ /* (for Saber C) */
static char xci[] = /* maps hex characters into integer values */
"\0\12\13\14\15\16\17\0\0\0\0\0\0\0\0\0\0\1\2\3\4\5\6\7\10\11";
#ifdef MULTI_MPD
/* init mutex without using a macro that would call DEBUG */
multi_alloc_lock (debug_mutex.lock);
multi_reset_lock (debug_mutex.lock);
#endif
if (!s) /* if s is null, try env MPD_DEBUG */
s = getenv (ENV_DEBUG);
if (s)
while (*s)
mpd_dbg_flags = (mpd_dbg_flags << 4) | xci[*s++ & 037];
for (i = 0; i <= MAX_STATUS; i++)
status_tag[i] = '#';
status_tag[ACTIVE] = 'A';
status_tag[READY] = 'R';
status_tag[BLOCKED] = 'B';
status_tag[INFANT] = 'I';
status_tag[FREE] = 'F';
status_tag[DOING_IO] = 'D';
status_tag[BLOCKED_DOING_IO] = 'S';
status_tag[TO_BE_FREED] = 'T';
if (mpd_my_vm == MAIN_VM)
DEBUG (D_ALL_FLAGS, "debug flags set to %lX", mpd_dbg_flags, 0, 0);
#endif /* NDEBUG */
}
#ifndef NDEBUG
/* mpd_bugout(f,v1,v2,v3,v4,v5) -- print debugging value v under format f.
*
* We build the output line (boilerplate + formatted arguments) in an
* internal buffer, then issue a single unbuffered write() call.
* This simplifies synchronization and ensures a contiguous message.
*/
int
mpd_bugout (f, v1, v2, v3, v4, v5)
char *f;
long v1, v2, v3, v4, v5;
{
char obuf[300];
int n;
#ifdef MPDX
Proc cur = NULL;
#else
Proc cur = CUR_PROC;
#endif
#ifdef MULTI_MPD
/* format: [V.J] (T:qQ:IS) M
*
* upper case letters are substituted as indicated below
* lower case letters are printed verbatim as mnemonics
*
* V is VM number
* J is jobserver number
* T is current thread
* Q is the depth that this jobserver holds mpd_queue_mutex
* I is I if the current thread is an idle thread and N otherwise
* S is a code for the current thread's status. See array
* status_tag[] above for the code.
* M is debug message
*/
if (cur == NULL)
sprintf (obuf, "[%d.0] (------------) ", mpd_my_vm);
else {
sprintf (obuf, "[%d.%d] (%06lX:q%d:%c%c) ",
mpd_my_vm, PRIV (my_jobserver_id),
(long) cur, PRIV (js_queue_depth),
(cur->ptype == IDLE_PR ? 'I' : 'N'),
status_tag[cur->status]);
}
#else /* no MULTI_MPD */
/* format: [V] (T) M
*
* V is VM number
* T is current thread
* M is debug message
*/
sprintf (obuf, "[%d] (%06lX) ", mpd_my_vm, (long) cur);
#endif /* MULTI_MPD */
n = strlen (obuf);
sprintf (obuf + n, f, v1, v2, v3, v4, v5);
n += strlen (obuf + n);
obuf[n++] = '\n';
/*
* Write output, synchronized with debugs on other processors.
* Avoid LOCK/UNLOCK macros because they call debug recursively!
*/
#ifdef MULTI_MPD
multi_lock (debug_mutex.lock);
write (STDERR, obuf, n);
multi_unlock (debug_mutex.lock);
#else
write (STDERR, obuf, n);
#endif
return 0;
}
/*
* mpd_msgname (t) -- return a printable message type name.
*/
char *
mpd_msgname (t)
enum ms_type t;
{
static char buf[20]; /* not locked in MultiMPD; we'll chance it. */
switch (t) {
case MSG_BAD: return "MSG_BAD";
case MSG_NONE: return "MSG_NONE";
case MSG_SEOF: return "MSG_SEOF";
case MSG_HELLO: return "MSG_HELLO";
case MSG_STOP: return "MSG_STOP";
case MSG_IDLE: return "MSG_IDLE";
case MSG_QUIT: return "MSG_QUIT";
case MSG_EXIT: return "MSG_EXIT";
case MSG_RCVCALL: return "MSG_RCVCALL";
case REQ_LOCVM: return "REQ_LOCVM";
case ACK_LOCVM: return "ACK_LOCVM";
case REQ_CREVM: return "REQ_CREVM";
case ACK_CREVM: return "ACK_CREVM";
case REQ_FINDVM: return "REQ_FINDVM";
case ACK_FINDVM: return "ACK_FINDVM";
case REQ_CREATE: return "REQ_CREATE";
case ACK_CREATE: return "ACK_CREATE";
case REQ_DESTROY: return "REQ_DESTROY";
case ACK_DESTROY: return "ACK_DESTROY";
case REQ_COUNT: return "REQ_COUNT";
case ACK_COUNT: return "ACK_COUNT";
case REQ_INVOKE: return "REQ_INVOKE";
case ACK_INVOKE: return "ACK_INVOKE";
case REQ_RECEIVE: return "REQ_RECEIVE";
case ACK_RECEIVE: return "ACK_RECEIVE";
case REQ_DESTOP: return "REQ_DESTOP";
case ACK_DESTOP: return "ACK_DESTOP";
case REQ_DESTVM: return "REQ_DESTVM";
case ACK_DESTVM: return "ACK_DESTVM";
case REQ_CALLME: return "REQ_CALLME";
case ACK_CALLME: return "ACK_CALLME";
default:
sprintf (buf, "[?msg %d?]", t);
return buf;
}
}
#endif /* NDEBUG */
/*
* mpd_debug lets an MPD program print a debugging message.
*
* sample usage:
* external mpd_debug (s: string[*]; n1,n2,n3: int)
* mpd_debug ("i,j,k: %d %d %d", i, j, k)
*/
void
mpd_debug (s, n1, n2, n3)
char *s;
int n1, n2, n3;
{
DEBUG (D_PROG, s, n1, n2, n3);
}
/* mpd_get_debug returns the current debug value */
int
mpd_get_debug ()
{
return (int) mpd_dbg_flags;
}
/* mpd_set_debug (n) -- set debugging value */
void
mpd_set_debug (n)
int n;
{
mpd_dbg_flags = n;
DEBUG (D_ALL_FLAGS, "mpd_set_debug(%lX)", n, 0, 0);
}
syntax highlighted by Code2HTML, v. 0.9.1