/*
Timequeue event code by Foxen
*/
#include "copyright.h"
#include "config.h"
#include "params.h"
#include "match.h"
#include "db.h"
#include "tune.h"
#include "mpi.h"
#include "props.h"
#include "interface.h"
#include "externs.h"
#include "mufevent.h"
#include "interp.h"
#include <stdio.h>
#include <sys/types.h>
#include <time.h>
#define TQ_MUF_TYP 0
#define TQ_MPI_TYP 1
#define TQ_MUF_QUEUE 0x0
#define TQ_MUF_DELAY 0x1
#define TQ_MUF_LISTEN 0x2
#define TQ_MUF_READ 0x3
#define TQ_MUF_TREAD 0x4
#define TQ_MUF_TIMER 0x5
#define TQ_MPI_QUEUE 0x0
#define TQ_MPI_DELAY 0x1
#define TQ_MPI_SUBMASK 0x7
#define TQ_MPI_LISTEN 0x8
#define TQ_MPI_OMESG 0x10
#define TQ_MPI_BLESSED 0x20
/*
* Events types and data:
* What, typ, sub, when, user, where, trig, prog, frame, str1, cmdstr, str3
* qmpi 1 0 1 user loc trig -- -- mpi cmd arg
* dmpi 1 1 when user loc trig -- -- mpi cmd arg
* lmpi 1 8 1 spkr loc lstnr -- -- mpi cmd heard
* oqmpi 1 16 1 user loc trig -- -- mpi cmd arg
* odmpi 1 17 when user loc trig -- -- mpi cmd arg
* olmpi 1 24 1 spkr loc lstnr -- -- mpi cmd heard
* qmuf 0 0 0 user loc trig prog -- stk_s cmd@ --
* lmuf 0 1 0 spkr loc lstnr prog -- heard cmd@ --
* dmuf 0 2 when user loc trig prog frame mode -- --
* rmuf 0 3 -1 user loc trig prog frame mode -- --
* trmuf 0 4 when user loc trig prog frame mode -- --
* tevmuf 0 5 when user loc trig prog frame mode event --
*/
typedef struct timenode {
struct timenode *next;
int typ;
int subtyp;
time_t when;
int descr;
dbref called_prog;
char *called_data;
char *command;
char *str3;
dbref uid;
dbref loc;
dbref trig;
struct frame *fr;
struct inst *where;
int eventnum;
} *timequeue;
static timequeue tqhead = NULL;
void prog_clean(struct frame *fr);
static int
valid_objref(dbref obj)
{
return (!((obj >= db_top)
|| (obj >= 0 && Typeof(obj) == TYPE_GARBAGE)
|| (obj < 0)));
}
extern int top_pid;
int process_count = 0;
static timequeue free_timenode_list = NULL;
static int free_timenode_count = 0;
static timequeue
alloc_timenode(int typ, int subtyp, time_t mytime, int descr, dbref player,
dbref loc, dbref trig, dbref program, struct frame *fr,
const char *strdata, const char *strcmd, const char *str3, timequeue nextone)
{
timequeue ptr;
if (free_timenode_list) {
ptr = free_timenode_list;
free_timenode_list = ptr->next;
free_timenode_count--;
} else {
ptr = (timequeue) malloc(sizeof(struct timenode));
}
ptr->typ = typ;
ptr->subtyp = subtyp;
ptr->when = mytime;
ptr->uid = player;
ptr->loc = loc;
ptr->trig = trig;
ptr->descr = descr;
ptr->fr = fr;
ptr->called_prog = program;
ptr->called_data = (char *) string_dup((char *) strdata);
ptr->command = alloc_string(strcmd);
ptr->str3 = alloc_string(str3);
ptr->eventnum = (fr) ? fr->pid : top_pid++;
ptr->next = nextone;
return (ptr);
}
static void
free_timenode(timequeue ptr)
{
if (ptr->command)
free(ptr->command);
if (ptr->called_data)
free(ptr->called_data);
if (ptr->str3)
free(ptr->str3);
if (ptr->fr) {
if (ptr->typ != TQ_MUF_TYP || ptr->subtyp != TQ_MUF_TIMER) {
if (ptr->fr->multitask != BACKGROUND)
PLAYER_SET_BLOCK(ptr->uid, 0);
prog_clean(ptr->fr);
}
if (ptr->typ == TQ_MUF_TYP && (ptr->subtyp == TQ_MUF_READ ||
ptr->subtyp == TQ_MUF_TREAD)) {
FLAGS(ptr->uid) &= ~INTERACTIVE;
FLAGS(ptr->uid) &= ~READMODE;
notify_nolisten(ptr->uid, "Data input aborted. The command you were using was killed.", 1);
}
}
if (free_timenode_count < tp_free_frames_pool) {
ptr->next = free_timenode_list;
free_timenode_list = ptr;
free_timenode_count++;
} else {
free(ptr);
}
}
void
purge_timenode_free_pool()
{
timequeue ptr = free_timenode_list;
timequeue nxt = NULL;
while (ptr) {
nxt = ptr->next;
free((void*)ptr);
ptr = nxt;
}
free_timenode_count = 0;
free_timenode_list = NULL;
}
int
control_process(dbref player, int pid)
{
timequeue tmp, ptr = tqhead;
tmp = ptr;
while ((ptr) && (pid != ptr->eventnum)) {
tmp = ptr;
ptr = ptr->next;
}
if (!ptr) {
return muf_event_controls(player, pid);
}
if (!controls(player, ptr->called_prog) && !controls(player, ptr->trig)) {
return 0;
}
return 1;
}
int
add_event(int event_typ, int subtyp, int dtime, int descr, dbref player, dbref loc,
dbref trig, dbref program, struct frame *fr,
const char *strdata, const char *strcmd, const char *str3)
{
timequeue ptr = tqhead;
timequeue lastevent = NULL;
time_t rtime = time((time_t *) NULL) + (time_t) dtime;
int mypids = 0;
for (ptr = tqhead, mypids = 0; ptr; ptr = ptr->next) {
if (ptr->uid == player)
mypids++;
lastevent = ptr;
}
if (event_typ == TQ_MUF_TYP && subtyp == TQ_MUF_READ) {
process_count++;
if (lastevent) {
lastevent->next = alloc_timenode(event_typ, subtyp, rtime, descr,
player, loc, trig, program, fr,
strdata, strcmd, str3, NULL);
return (lastevent->next->eventnum);
} else {
tqhead = alloc_timenode(event_typ, subtyp, rtime, descr,
player, loc, trig, program, fr,
strdata, strcmd, str3, NULL);
return (tqhead->eventnum);
}
}
if (!(event_typ == TQ_MUF_TYP && subtyp == TQ_MUF_TREAD)) {
if (process_count > tp_max_process_limit ||
(mypids > tp_max_plyr_processes && !Wizard(OWNER(player)))) {
if (fr) {
if (fr->multitask != BACKGROUND)
PLAYER_SET_BLOCK(player, 0);
prog_clean(fr);
}
notify_nolisten(player, "Event killed. Timequeue table full.", 1);
return 0;
}
}
process_count++;
if (!tqhead) {
tqhead = alloc_timenode(event_typ, subtyp, rtime, descr, player, loc, trig,
program, fr, strdata, strcmd, str3, NULL);
return (tqhead->eventnum);
}
if (rtime < tqhead->when || (tqhead->typ == TQ_MUF_TYP && tqhead->subtyp == TQ_MUF_READ)
) {
tqhead = alloc_timenode(event_typ, subtyp, rtime, descr, player, loc, trig,
program, fr, strdata, strcmd, str3, tqhead);
return (tqhead->eventnum);
}
ptr = tqhead;
while ((ptr->next) && (rtime >= ptr->next->when) &&
!(ptr->next->typ == TQ_MUF_TYP && ptr->next->subtyp == TQ_MUF_READ)
) {
ptr = ptr->next;
}
ptr->next = alloc_timenode(event_typ, subtyp, rtime, descr, player, loc, trig,
program, fr, strdata, strcmd, str3, ptr->next);
return (ptr->next->eventnum);
}
int
add_mpi_event(int delay, int descr, dbref player, dbref loc, dbref trig,
const char *mpi, const char *cmdstr, const char *argstr,
int listen_p, int omesg_p, int blessed_p)
{
int subtyp = TQ_MPI_QUEUE;
if (delay >= 1) {
subtyp = TQ_MPI_DELAY;
}
if (blessed_p) {
subtyp |= TQ_MPI_BLESSED;
}
if (listen_p) {
subtyp |= TQ_MPI_LISTEN;
}
if (omesg_p) {
subtyp |= TQ_MPI_OMESG;
}
return add_event(TQ_MPI_TYP, subtyp, delay, descr, player, loc, trig,
NOTHING, NULL, mpi, cmdstr, argstr);
}
int
add_muf_queue_event(int descr, dbref player, dbref loc, dbref trig, dbref prog,
const char *argstr, const char *cmdstr, int listen_p)
{
return add_event(TQ_MUF_TYP, (listen_p ? TQ_MUF_LISTEN : TQ_MUF_QUEUE), 0,
descr, player, loc, trig, prog, NULL, argstr, cmdstr, NULL);
}
int
add_muf_delayq_event(int delay, int descr, dbref player, dbref loc, dbref trig,
dbref prog, const char *argstr, const char *cmdstr, int listen_p)
{
return add_event(TQ_MUF_TYP, (listen_p ? TQ_MUF_LISTEN : TQ_MUF_QUEUE),
delay, descr, player, loc, trig, prog, NULL, argstr, cmdstr, NULL);
}
int
add_muf_read_event(int descr, dbref player, dbref prog, struct frame *fr)
{
FLAGS(player) |= (INTERACTIVE | READMODE);
return add_event(TQ_MUF_TYP, TQ_MUF_READ, -1, descr, player, -1, fr->trig,
prog, fr, "READ", NULL, NULL);
}
int
add_muf_tread_event(int descr, dbref player, dbref prog, struct frame *fr, int delay)
{
FLAGS(player) |= (INTERACTIVE | READMODE);
return add_event(TQ_MUF_TYP, TQ_MUF_TREAD, delay, descr, player, -1, fr->trig,
prog, fr, "READ", NULL, NULL);
}
int
add_muf_timer_event(int descr, dbref player, dbref prog, struct frame *fr, int delay, char *id)
{
char buf[40];
snprintf(buf, sizeof(buf), "TIMER.%.32s", id);
fr->timercount++;
return add_event(TQ_MUF_TYP, TQ_MUF_TIMER, delay, descr, player, -1, fr->trig,
prog, fr, buf, NULL, NULL);
}
int
add_muf_delay_event(int delay, int descr, dbref player, dbref loc, dbref trig, dbref prog,
struct frame *fr, const char *mode)
{
return add_event(TQ_MUF_TYP, TQ_MUF_DELAY, delay, descr, player, loc, trig,
prog, fr, mode, NULL, NULL);
}
int
read_event_notify(int descr, dbref player, const char* cmd)
{
timequeue ptr;
if (muf_event_read_notify(descr, player, cmd)) {
return 1;
}
ptr = tqhead;
while (ptr) {
if (ptr->uid == player) {
if (ptr->fr && ptr->fr->multitask != BACKGROUND) {
if (*cmd || ptr->fr->wantsblanks) {
struct inst temp;
temp.type = PROG_INTEGER;
temp.data.number = descr;
muf_event_add(ptr->fr, "READ", &temp, 1);
return 1;
}
}
}
ptr = ptr->next;
}
return 0;
}
void
handle_read_event(int descr, dbref player, const char *command)
{
struct frame *fr;
timequeue ptr, lastevent;
int flag, typ, nothing_flag;
int oldflags;
dbref prog;
nothing_flag = 0;
if (command == NULL) {
nothing_flag = 1;
}
oldflags = FLAGS(player);
FLAGS(player) &= ~(INTERACTIVE | READMODE);
ptr = tqhead;
lastevent = NULL;
while (ptr) {
if (ptr->typ == TQ_MUF_TYP && (ptr->subtyp == TQ_MUF_READ ||
ptr->subtyp == TQ_MUF_TREAD) && ptr->uid == player) {
break;
}
lastevent = ptr;
ptr = ptr->next;
}
/*
* When execution gets to here, either ptr will point to the
* READ event for the player, or else ptr will be NULL.
*/
if (ptr) {
/* remember our program, and our execution frame. */
fr = ptr->fr;
if (!fr->brkpt.debugging || fr->brkpt.isread) {
if (!fr->wantsblanks && command && !*command) {
FLAGS(player) = oldflags;
return;
}
}
typ = ptr->subtyp;
prog = ptr->called_prog;
if (command) {
/* remove the READ timequeue node from the timequeue */
process_count--;
if (lastevent) {
lastevent->next = ptr->next;
} else {
tqhead = ptr->next;
}
}
/* remember next timequeue node, to check for more READs later */
lastevent = ptr;
ptr = ptr->next;
/* Make SURE not to let the program frame get freed. We need it. */
lastevent->fr = NULL;
if (command) {
/*
* Free up the READ timequeue node
* we just removed from the queue.
*/
free_timenode(lastevent);
}
if (fr->brkpt.debugging && !fr->brkpt.isread) {
/* We're in the MUF debugger! Call it with the input line. */
if (command) {
if (muf_debugger(descr, player, prog, command, fr)) {
/* MUF Debugger exited. Free up the program frame & exit */
prog_clean(fr);
return;
}
} else {
if (muf_debugger(descr, player, prog, "", fr)) {
/* MUF Debugger exited. Free up the program frame & exit */
prog_clean(fr);
return;
}
}
} else {
/* This is a MUF READ event. */
if (command && !string_compare(command, BREAK_COMMAND)) {
/* Whoops! The user typed @Q. Free the frame and exit. */
prog_clean(fr);
return;
}
if ((fr->argument.top >= STACK_SIZE) ||
(nothing_flag && fr->argument.top >= STACK_SIZE - 1)) {
/*
* Uh oh! That MUF program's stack is full!
* Print an error, free the frame, and exit.
*/
notify_nolisten(player, "Program stack overflow.", 1);
prog_clean(fr);
return;
}
/*
* Everything looks okay. Lets stuff the input line
* on the program's argument stack as a string item.
*/
fr->argument.st[fr->argument.top].type = PROG_STRING;
fr->argument.st[fr->argument.top++].data.string =
alloc_prog_string(command ? command : "");
if (typ == TQ_MUF_TREAD) {
if (nothing_flag) {
fr->argument.st[fr->argument.top].type = PROG_INTEGER;
fr->argument.st[fr->argument.top++].data.number = 0;
} else {
fr->argument.st[fr->argument.top].type = PROG_INTEGER;
fr->argument.st[fr->argument.top++].data.number = 1;
}
}
}
/*
* When using the MUF Debugger, the debugger will set the
* INTERACTIVE bit on the user, if it does NOT want the MUF
* program to resume executing.
*/
flag = (FLAGS(player) & INTERACTIVE);
if (!flag && fr) {
interp_loop(player, prog, fr, 0);
/* WORK: if more input is pending, send the READ mufevent again. */
/* WORK: if no input is pending, clear READ mufevent from all of this player's programs. */
}
/*
* Check for any other READ events for this player.
* If there are any, set the READ related flags.
*/
while (ptr) {
if (ptr->typ == TQ_MUF_TYP && (ptr->subtyp == TQ_MUF_READ ||
ptr->subtyp == TQ_MUF_TREAD)) {
if (ptr->uid == player) {
FLAGS(player) |= (INTERACTIVE | READMODE);
}
}
ptr = ptr->next;
}
}
}
void
next_timequeue_event(void)
{
struct frame *tmpfr;
dbref tmpcp;
int tmpbl, tmpfg;
timequeue lastevent, event;
int maxruns = 0;
int forced_pid = 0;
time_t rtime;
time(&rtime);
lastevent = tqhead;
while ((lastevent) && (rtime >= lastevent->when) && (maxruns < 10)) {
lastevent = lastevent->next;
maxruns++;
}
while (tqhead && (tqhead != lastevent) && (maxruns--)) {
if (tqhead->typ == TQ_MUF_TYP && tqhead->subtyp == TQ_MUF_READ) {
break;
}
event = tqhead;
tqhead = tqhead->next;
process_count--;
forced_pid = event->eventnum;
event->eventnum = 0;
if (event->typ == TQ_MPI_TYP) {
char cbuf[BUFFER_LEN];
int ival;
strcpy(match_args, event->str3 ? event->str3 : "");
strcpy(match_cmdname, event->command ? event->command : "");
ival = (event->subtyp & TQ_MPI_OMESG) ? MPI_ISPUBLIC : MPI_ISPRIVATE;
if (event->subtyp & TQ_MPI_BLESSED) {
ival |= MPI_ISBLESSED;
}
if (event->subtyp & TQ_MPI_LISTEN) {
ival |= MPI_ISLISTENER;
do_parse_mesg(event->descr, event->uid, event->trig, event->called_data,
"(MPIlisten)", cbuf, ival);
} else if ((event->subtyp & TQ_MPI_SUBMASK) == TQ_MPI_DELAY) {
do_parse_mesg(event->descr, event->uid, event->trig, event->called_data,
"(MPIdelay)", cbuf, ival);
} else {
do_parse_mesg(event->descr, event->uid, event->trig, event->called_data,
"(MPIqueue)", cbuf, ival);
}
if (*cbuf) {
if (!(event->subtyp & TQ_MPI_OMESG)) {
notify_filtered(event->uid, event->uid, cbuf, 1);
} else {
char bbuf[BUFFER_LEN];
dbref plyr;
snprintf(bbuf, sizeof(bbuf), ">> %.4000s %.*s",
NAME(event->uid),
(int)(4000 - strlen(NAME(event->uid))),
pronoun_substitute(event->descr, event->uid, cbuf));
plyr = DBFETCH(event->loc)->contents;
for (; plyr != NOTHING; plyr = DBFETCH(plyr)->next) {
if (Typeof(plyr) == TYPE_PLAYER && plyr != event->uid)
notify_filtered(event->uid, plyr, bbuf, 0);
}
}
}
} else if (event->typ == TQ_MUF_TYP) {
if (Typeof(event->called_prog) == TYPE_PROGRAM) {
if (event->subtyp == TQ_MUF_DELAY) {
tmpcp = PLAYER_CURR_PROG(event->uid);
tmpbl = PLAYER_BLOCK(event->uid);
tmpfg = (event->fr->multitask != BACKGROUND);
interp_loop(event->uid, event->called_prog, event->fr, 0);
if (!tmpfg) {
PLAYER_SET_BLOCK(event->uid, tmpbl);
}
} else if (event->subtyp == TQ_MUF_TIMER) {
struct inst temp;
temp.type = PROG_INTEGER;
temp.data.number = event->when;
event->fr->timercount--;
muf_event_add(event->fr, event->called_data, &temp, 0);
} else if (event->subtyp == TQ_MUF_TREAD) {
handle_read_event(event->descr, event->uid, NULL);
} else {
strcpy(match_args, event->called_data ? event->called_data : "");
strcpy(match_cmdname, event->command ? event->command : "");
tmpfr = interp(event->descr, event->uid, event->loc, event->called_prog,
event->trig, BACKGROUND, STD_HARDUID, forced_pid);
if (tmpfr) {
interp_loop(event->uid, event->called_prog, tmpfr, 0);
}
}
}
}
event->fr = NULL;
free_timenode(event);
}
}
int
in_timequeue(int pid)
{
timequeue ptr = tqhead;
if (!pid)
return 0;
if (muf_event_pid_frame(pid))
return 1;
if (!tqhead)
return 0;
while ((ptr) && (ptr->eventnum != pid))
ptr = ptr->next;
if (ptr)
return 1;
return 0;
}
struct frame*
timequeue_pid_frame(int pid)
{
struct frame *out = NULL;
timequeue ptr = tqhead;
if (!pid)
return NULL;
out = muf_event_pid_frame(pid);
if (out != NULL)
return out;
if (!tqhead)
return NULL;
while ((ptr) && (ptr->eventnum != pid))
ptr = ptr->next;
if (ptr)
return ptr->fr;
return NULL;
}
long
next_event_time(void)
{
time_t rtime = time((time_t *) NULL);
if (tqhead) {
if (tqhead->when == -1) {
return (-1L);
} else if (rtime >= tqhead->when) {
return (0L);
} else {
return ((long) (tqhead->when - rtime));
}
}
return (-1L);
}
/* Checks the MUF timequeue for address references on the stack or */
/* dbref references on the callstack */
static int
has_refs(dbref program, timequeue ptr)
{
int loop;
if (ptr->typ != TQ_MUF_TYP || !(ptr->fr) ||
Typeof(program) != TYPE_PROGRAM || !(PROGRAM_INSTANCES(program)))
return 0;
for (loop = 1; loop < ptr->fr->caller.top; loop++) {
if (ptr->fr->caller.st[loop] == program)
return 1;
}
for (loop = 0; loop < ptr->fr->argument.top; loop++) {
if (ptr->fr->argument.st[loop].type == PROG_ADD &&
ptr->fr->argument.st[loop].data.addr->progref == program)
return 1;
}
return 0;
}
extern char *time_format_2(long dt);
void
list_events(dbref player)
{
char buf[BUFFER_LEN];
char pidstr[128];
char duestr[128];
char runstr[128];
char inststr[128];
char cpustr[128];
char progstr[128];
char prognamestr[128];
int count = 0;
timequeue ptr = tqhead;
time_t rtime = time((time_t *) NULL);
time_t etime;
double pcnt;
const char* strfmt = "%10s %4s %4s %6s %4s %7s %-10.10s %-12s %.512s";
(void)snprintf(buf, sizeof(buf), strfmt, "PID", "Next", "Run", "KInst", "%CPU", "Prog#", "ProgName", "Player", "");
notify_nolisten(player, buf, 1);
while (ptr) {
snprintf(pidstr, sizeof(pidstr), "%d", ptr->eventnum);
strcpy(duestr, ((ptr->when - rtime) > 0) ?
time_format_2((long) (ptr->when - rtime)) : "Due");
strcpy(runstr, ptr->fr ?
time_format_2((long) (rtime - ptr->fr->started)): "0s");
snprintf(inststr, sizeof(inststr), "%d", ptr->fr? (ptr->fr->instcnt / 1000) : 0);
if (ptr->fr) {
etime = rtime - ptr->fr->started;
if (etime > 0) {
pcnt = ptr->fr->totaltime.tv_sec;
pcnt += ptr->fr->totaltime.tv_usec / 1000000;
pcnt = pcnt * 100 / etime;
if (pcnt > 99.9) {
pcnt = 99.9;
}
} else {
pcnt = 0.0;
}
} else {
pcnt = 0.0;
}
snprintf(cpustr, sizeof(cpustr), "%4.1f", pcnt);
if (ptr->fr) {
snprintf(progstr, sizeof(progstr), "#%d", ptr->fr->caller.st[1]);
snprintf(prognamestr, sizeof(prognamestr), "%s", NAME(ptr->fr->caller.st[1]));
} else if (ptr->typ == TQ_MPI_TYP) {
snprintf(progstr, sizeof(progstr), "#%d", ptr->trig);
snprintf(prognamestr, sizeof(prognamestr), "%s", "");
} else {
snprintf(progstr, sizeof(progstr), "#%d", ptr->called_prog);
snprintf(prognamestr, sizeof(prognamestr), "%s", NAME(ptr->called_prog));
}
if (ptr->typ == TQ_MUF_TYP && ptr->subtyp == TQ_MUF_READ) {
strcpy(duestr, "--");
} else if (ptr->typ == TQ_MUF_TYP && ptr->subtyp == TQ_MUF_TIMER) {
snprintf(pidstr, sizeof(pidstr), "(%d)", ptr->eventnum);
} else if (ptr->typ == TQ_MPI_TYP) {
strcpy(runstr, "--");
strcpy(inststr, "MPI");
strcpy(cpustr, "--");
}
(void) snprintf(buf, sizeof(buf), strfmt, pidstr, duestr, runstr, inststr,
cpustr, progstr, prognamestr, NAME(ptr->uid),
ptr->called_data? ptr->called_data : "");
if (Wizard(OWNER(player)) || ptr->uid == player) {
notify_nolisten(player, buf, 1);
} else if (ptr->called_prog != NOTHING && OWNER(ptr->called_prog) == OWNER(player)) {
notify_nolisten(player, buf, 1);
}
ptr = ptr->next;
count++;
}
count += muf_event_list(player, strfmt);
snprintf(buf, sizeof(buf), "%d events.", count);
notify_nolisten(player, buf, 1);
}
stk_array *
get_pids(dbref ref)
{
struct inst temp1, temp2;
stk_array *nw;
int count = 0;
timequeue ptr = tqhead;
nw = new_array_packed(0);
while (ptr) {
if (((ptr->typ != TQ_MPI_TYP) ? (ptr->called_prog == ref) : (ptr->trig == ref)) ||
(ptr->uid == ref) || (ref < 0) ) {
temp2.type = PROG_INTEGER;
temp2.data.number = ptr->eventnum;
temp1.type = PROG_INTEGER;
temp1.data.number = count++;
array_setitem(&nw, &temp1, &temp2);
CLEAR(&temp1);
CLEAR(&temp2);
}
ptr = ptr->next;
}
nw = get_mufevent_pids(nw, ref);
return nw;
}
stk_array *
get_pidinfo(int pid)
{
struct inst temp1, temp2;
stk_array *nw;
time_t rtime = time(NULL);
time_t etime = 0;
double pcnt = 0.0;
timequeue ptr = tqhead;
nw = new_array_dictionary();
while (ptr) {
if (ptr->eventnum == pid) {
if (ptr->typ != TQ_MUF_TYP || ptr->subtyp != TQ_MUF_TIMER) {
break;
}
}
ptr = ptr->next;
}
if (ptr && (ptr->eventnum == pid) &&
(ptr->typ != TQ_MUF_TYP || ptr->subtyp != TQ_MUF_TIMER)) {
if (ptr->fr) {
etime = rtime - ptr->fr->started;
if (etime > 0) {
pcnt = ptr->fr->totaltime.tv_sec;
pcnt += ptr->fr->totaltime.tv_usec / 1000000;
pcnt = pcnt * 100 / etime;
if (pcnt > 100.0) {
pcnt = 100.0;
}
} else {
pcnt = 0.0;
}
}
temp1.type = PROG_STRING;
temp1.data.string = alloc_prog_string("PID");
temp2.type = PROG_INTEGER;
temp2.data.number = ptr->eventnum;
array_setitem(&nw, &temp1, &temp2);
CLEAR(&temp1);
CLEAR(&temp2);
temp1.type = PROG_STRING;
temp1.data.string = alloc_prog_string("CALLED_PROG");
temp2.type = PROG_OBJECT;
temp2.data.objref = ptr->called_prog;
array_setitem(&nw, &temp1, &temp2);
CLEAR(&temp1);
CLEAR(&temp2);
temp1.type = PROG_STRING;
temp1.data.string = alloc_prog_string("TRIG");
temp2.type = PROG_OBJECT;
temp2.data.objref = ptr->trig;
array_setitem(&nw, &temp1, &temp2);
CLEAR(&temp1);
CLEAR(&temp2);
temp1.type = PROG_STRING;
temp1.data.string = alloc_prog_string("PLAYER");
temp2.type = PROG_OBJECT;
temp2.data.objref = ptr->uid;
array_setitem(&nw, &temp1, &temp2);
CLEAR(&temp1);
CLEAR(&temp2);
temp1.type = PROG_STRING;
temp1.data.string = alloc_prog_string("CALLED_DATA");
temp2.type = PROG_STRING;
temp2.data.string = alloc_prog_string(ptr->called_data);
array_setitem(&nw, &temp1, &temp2);
CLEAR(&temp1);
CLEAR(&temp2);
temp1.type = PROG_STRING;
temp1.data.string = alloc_prog_string("INSTCNT");
temp2.type = PROG_INTEGER;
temp2.data.number = ptr->fr->instcnt;
array_setitem(&nw, &temp1, &temp2);
CLEAR(&temp1);
CLEAR(&temp2);
temp1.type = PROG_STRING;
temp1.data.string = alloc_prog_string("DESCR");
temp2.type = PROG_INTEGER;
temp2.data.number = ptr->descr;
array_setitem(&nw, &temp1, &temp2);
CLEAR(&temp1);
CLEAR(&temp2);
temp1.type = PROG_STRING;
temp1.data.string = alloc_prog_string("CPU");
temp2.type = PROG_FLOAT;
temp2.data.fnumber = pcnt;
array_setitem(&nw, &temp1, &temp2);
CLEAR(&temp1);
CLEAR(&temp2);
temp1.type = PROG_STRING;
temp1.data.string = alloc_prog_string("NEXTRUN");
temp2.type = PROG_INTEGER;
temp2.data.number = (int) ptr->when;
array_setitem(&nw, &temp1, &temp2);
CLEAR(&temp1);
CLEAR(&temp2);
temp1.type = PROG_STRING;
temp1.data.string = alloc_prog_string("STARTED");
temp2.type = PROG_INTEGER;
temp2.data.number = (int) ptr->fr->started;
array_setitem(&nw, &temp1, &temp2);
CLEAR(&temp1);
CLEAR(&temp2);
temp1.type = PROG_STRING;
temp1.data.string = alloc_prog_string("TYPE");
temp2.type = PROG_STRING;
temp2.data.string = (ptr->typ == TQ_MUF_TYP) ? alloc_prog_string("MUF") :
(ptr->typ == TQ_MPI_TYP) ? alloc_prog_string("MPI") : alloc_prog_string("UNK") ;
array_setitem(&nw, &temp1, &temp2);
CLEAR(&temp1);
CLEAR(&temp2);
temp1.type = PROG_STRING;
temp1.data.string = alloc_prog_string("SUBTYPE");
temp2.type = PROG_STRING;
if (ptr->typ == TQ_MUF_TYP) {
temp2.data.string = (ptr->subtyp == TQ_MUF_READ) ? alloc_prog_string("READ") :
(ptr->subtyp == TQ_MUF_TREAD) ? alloc_prog_string("TREAD") :
(ptr->subtyp == TQ_MUF_QUEUE) ? alloc_prog_string("QUEUE") :
(ptr->subtyp == TQ_MUF_LISTEN) ? alloc_prog_string("LISTEN") :
(ptr->subtyp == TQ_MUF_TIMER) ? alloc_prog_string("TIMER") :
(ptr->subtyp == TQ_MUF_DELAY) ? alloc_prog_string("DELAY") :
alloc_prog_string("");
} else if (ptr->typ == TQ_MPI_TYP) {
int subtyp = (ptr->subtyp & TQ_MPI_SUBMASK);
temp2.data.string = (subtyp == TQ_MPI_QUEUE) ? alloc_prog_string("QUEUE") :
(subtyp == TQ_MPI_DELAY) ? alloc_prog_string("DELAY") :
alloc_prog_string("");
} else {
temp2.data.string = alloc_prog_string("");
}
array_setitem(&nw, &temp1, &temp2);
CLEAR(&temp1);
CLEAR(&temp2);
} else {
nw = get_mufevent_pidinfo(nw, pid);
}
return nw;
}
/*
* killmode values:
* 0: kill all matching processes, MUF or MPI
* 1: kill all matching MUF processes
* 2: kill all matching foreground MUF processes
*/
int
dequeue_prog(dbref program, int killmode)
{
int count = 0;
timequeue tmp, ptr;
while (tqhead) {
if (tqhead->called_prog != program && !has_refs(program, tqhead) && tqhead->uid != program) {
break;
}
if (killmode == 2) {
if (tqhead->fr && tqhead->fr->multitask == BACKGROUND) {
break;
}
} else if (killmode == 1) {
if (!tqhead->fr) {
break;
}
}
ptr = tqhead;
tqhead = tqhead->next;
free_timenode(ptr);
process_count--;
count++;
}
if (tqhead) {
for (tmp = tqhead, ptr = tqhead->next; ptr; tmp = ptr, ptr = ptr->next) {
if (ptr->called_prog != program && !has_refs(program, ptr) && ptr->uid != program) {
continue;
}
if (killmode == 2) {
if (ptr->fr && ptr->fr->multitask == BACKGROUND) {
continue;
}
} else if (killmode == 1) {
if (!ptr->fr) {
continue;
}
}
tmp->next = ptr->next;
free_timenode(ptr);
process_count--;
count++;
ptr = tmp;
}
}
count += muf_event_dequeue(program, killmode);
for (ptr = tqhead; ptr; ptr = ptr->next) {
if (ptr->typ == TQ_MUF_TYP && (ptr->subtyp == TQ_MUF_READ ||
ptr->subtyp == TQ_MUF_TREAD)) {
FLAGS(ptr->uid) |= (INTERACTIVE | READMODE);
}
}
return (count);
}
int
dequeue_process(int pid)
{
timequeue tmp, ptr;
int deqflag = 0;
if (!pid)
return 0;
if (muf_event_dequeue_pid(pid)) {
process_count--;
deqflag = 1;
}
tmp = ptr = tqhead;
while (ptr) {
if (pid == ptr->eventnum) {
if (tmp == ptr) {
tqhead = tmp = tmp->next;
free_timenode(ptr);
ptr = tmp;
} else {
tmp->next = ptr->next;
free_timenode(ptr);
ptr = tmp->next;
}
process_count--;
deqflag = 1;
} else {
tmp = ptr;
ptr = ptr->next;
}
}
if (!deqflag) {
return 0;
}
for (ptr = tqhead; ptr; ptr = ptr->next) {
if (ptr->typ == TQ_MUF_TYP && (ptr->subtyp == TQ_MUF_READ ||
ptr->subtyp == TQ_MUF_TREAD)) {
FLAGS(ptr->uid) |= (INTERACTIVE | READMODE);
}
}
return 1;
}
int
dequeue_timers(int pid, char* id)
{
char buf[40];
timequeue tmp, ptr;
int deqflag = 0;
if (!pid)
return 0;
if (id)
snprintf(buf, sizeof(buf), "TIMER.%.30s", id);
tmp = ptr = tqhead;
while (ptr) {
if (pid == ptr->eventnum &&
ptr->typ == TQ_MUF_TYP && ptr->subtyp == TQ_MUF_TIMER &&
(!id || !strcmp(ptr->called_data, buf)))
{
if (tmp == ptr) {
tqhead = tmp = tmp->next;
ptr->fr->timercount--;
ptr->fr = NULL;
free_timenode(ptr);
ptr = tmp;
} else {
tmp->next = ptr->next;
ptr->fr->timercount--;
ptr->fr = NULL;
free_timenode(ptr);
ptr = tmp->next;
}
process_count--;
deqflag = 1;
} else {
tmp = ptr;
ptr = ptr->next;
}
}
return deqflag;
}
void
do_dequeue(int descr, dbref player, const char *arg1)
{
char buf[BUFFER_LEN];
int count;
dbref match;
struct match_data md;
timequeue tmp, ptr = tqhead;
if (*arg1 == '\0') {
notify_nolisten(player, "What event do you want to dequeue?", 1);
} else {
if (!string_compare(arg1, "all")) {
if (!Wizard(OWNER(player))) {
notify_nolisten(player, "Permission denied", 1);
return;
}
while (ptr) {
tmp = ptr;
tqhead = ptr = ptr->next;
free_timenode(tmp);
process_count--;
}
tqhead = NULL;
muf_event_dequeue(NOTHING, 0);
notify_nolisten(player, "Time queue cleared.", 1);
} else {
if (!number(arg1)) {
init_match(descr, player, arg1, NOTYPE, &md);
match_absolute(&md);
match_everything(&md);
match = noisy_match_result(&md);
if (match == NOTHING) {
notify_nolisten(player, "I don't know what you want to dequeue!", 1);
return;
}
if (!valid_objref(match)) {
notify_nolisten(player, "I don't recognize that object.", 1);
return;
}
if ((!Wizard(OWNER(player))) && (OWNER(match) != OWNER(player))) {
notify_nolisten(player, "Permission denied.", 1);
return;
}
count = dequeue_prog(match, 0);
if (!count) {
notify_nolisten(player, "That program wasn't in the time queue.", 1);
return;
}
if (count > 1) {
snprintf(buf, sizeof(buf), "%d processes dequeued.", count);
} else {
snprintf(buf, sizeof(buf), "Process dequeued.");
}
notify_nolisten(player, buf, 1);
} else {
if ((count = atoi(arg1))) {
if (!(control_process(player, count))) {
notify_nolisten(player, "Permission denied.", 1);
return;
}
if (!(dequeue_process(count))) {
notify_nolisten(player, "No such process!", 1);
return;
}
process_count--;
notify_nolisten(player, "Process dequeued.", 1);
} else {
notify_nolisten(player, "What process do you want to dequeue?", 1);
}
}
}
}
return;
}
int
scan_instances(dbref program)
{
timequeue tq = tqhead;
int i = 0, loop;
while (tq) {
if (tq->typ == TQ_MUF_TYP && tq->fr) {
if (tq->called_prog == program) {
i++;
}
for (loop = 1; loop < tq->fr->caller.top; loop++) {
if (tq->fr->caller.st[loop] == program)
i++;
}
for (loop = 0; loop < tq->fr->argument.top; loop++) {
if (tq->fr->argument.st[loop].type == PROG_ADD &&
tq->fr->argument.st[loop].data.addr->progref == program)
i++;
}
}
tq = tq->next;
}
return i;
}
static int propq_level = 0;
void
propqueue(int descr, dbref player, dbref where, dbref trigger, dbref what, dbref xclude,
const char *propname, const char *toparg, int mlev, int mt)
{
const char *tmpchar;
const char *pname;
dbref the_prog;
char buf[BUFFER_LEN];
char exbuf[BUFFER_LEN];
the_prog = NOTHING;
tmpchar = NULL;
/* queue up program referred to by the given property */
if (((the_prog = get_property_dbref(what, propname)) != NOTHING) ||
(tmpchar = get_property_class(what, propname))) {
#ifdef COMPRESS
if (tmpchar)
tmpchar = uncompress(tmpchar);
#endif
if ((tmpchar && *tmpchar) || the_prog != NOTHING) {
if (tmpchar) {
if (*tmpchar == '&') {
the_prog = AMBIGUOUS;
} else if (*tmpchar == NUMBER_TOKEN && number(tmpchar + 1)) {
the_prog = (dbref) atoi(++tmpchar);
} else if (*tmpchar == REGISTERED_TOKEN) {
the_prog = find_registered_obj(what, tmpchar);
} else if (number(tmpchar)) {
the_prog = (dbref) atoi(tmpchar);
} else {
the_prog = NOTHING;
}
} else {
if (the_prog == AMBIGUOUS)
the_prog = NOTHING;
}
if (the_prog != AMBIGUOUS) {
if (the_prog < 0 || the_prog >= db_top) {
the_prog = NOTHING;
} else if (Typeof(the_prog) != TYPE_PROGRAM) {
the_prog = NOTHING;
} else if ((OWNER(the_prog) != OWNER(player)) && !(FLAGS(the_prog) & LINK_OK)) {
the_prog = NOTHING;
} else if (MLevel(the_prog) < mlev) {
the_prog = NOTHING;
} else if (MLevel(OWNER(the_prog)) < mlev) {
the_prog = NOTHING;
} else if (the_prog == xclude) {
the_prog = NOTHING;
}
}
if (propq_level < 8) {
propq_level++;
if (the_prog == AMBIGUOUS) {
char cbuf[BUFFER_LEN];
int ival;
strcpy(match_args, "");
strcpy(match_cmdname, toparg);
ival = (mt == 0) ? MPI_ISPUBLIC : MPI_ISPRIVATE;
if (Prop_Blessed(what, propname))
ival |= MPI_ISBLESSED;
do_parse_mesg(descr, player, what, tmpchar + 1, "(MPIqueue)", cbuf, ival);
if (*cbuf) {
if (mt) {
notify_filtered(player, player, cbuf, 1);
} else {
char bbuf[BUFFER_LEN];
dbref plyr;
snprintf(bbuf, sizeof(bbuf), ">> %.4000s",
pronoun_substitute(descr, player, cbuf));
plyr = DBFETCH(where)->contents;
while (plyr != NOTHING) {
if (Typeof(plyr) == TYPE_PLAYER && plyr != player)
notify_filtered(player, plyr, bbuf, 0);
plyr = DBFETCH(plyr)->next;
}
}
}
} else if (the_prog != NOTHING) {
struct frame *tmpfr;
strcpy(match_args, toparg ? toparg : "");
strcpy(match_cmdname, "Queued event.");
tmpfr = interp(descr, player, where, the_prog, trigger,
BACKGROUND, STD_HARDUID, 0);
if (tmpfr) {
interp_loop(player, the_prog, tmpfr, 0);
}
}
propq_level--;
} else {
notify_nolisten(player, "Propqueue stopped to prevent infinite loop.", 1);
}
}
}
strcpyn(buf, sizeof(buf), propname);
if (is_propdir(what, buf)) {
strcatn(buf, sizeof(buf), "/");
while ((pname = next_prop_name(what, exbuf, sizeof(exbuf), buf))) {
strcpy(buf, pname);
propqueue(descr, player, where, trigger, what, xclude, buf, toparg, mlev, mt);
}
}
}
void
envpropqueue(int descr, dbref player, dbref where, dbref trigger, dbref what, dbref xclude,
const char *propname, const char *toparg, int mlev, int mt)
{
while (what != NOTHING) {
propqueue(descr, player, where, trigger, what, xclude, propname, toparg, mlev, mt);
what = getparent(what);
}
}
void
listenqueue(int descr, dbref player, dbref where, dbref trigger, dbref what, dbref xclude,
const char *propname, const char *toparg, int mlev, int mt, int mpi_p)
{
const char *tmpchar;
const char *pname, *sep, *ptr;
dbref the_prog = NOTHING;
char buf[BUFFER_LEN];
char exbuf[BUFFER_LEN];
char *ptr2;
if (!(FLAGS(what) & LISTENER) && !(FLAGS(OWNER(what)) & ZOMBIE))
return;
the_prog = NOTHING;
tmpchar = NULL;
/* queue up program referred to by the given property */
if (((the_prog = get_property_dbref(what, propname)) != NOTHING) ||
(tmpchar = get_property_class(what, propname))) {
if (tmpchar) {
#ifdef COMPRESS
tmpchar = uncompress(tmpchar);
#endif
sep = tmpchar;
while (*sep) {
if (*sep == '\\') {
sep++;
} else if (*sep == '=') {
break;
}
if (*sep)
sep++;
}
if (*sep == '=') {
for (ptr = tmpchar, ptr2 = buf; ptr < sep; *ptr2++ = *ptr++) ;
*ptr2 = '\0';
strcpy(exbuf, toparg);
if (!equalstr(buf, exbuf)) {
tmpchar = NULL;
} else {
tmpchar = ++sep;
}
}
}
if ((tmpchar && *tmpchar) || the_prog != NOTHING) {
if (tmpchar) {
if (*tmpchar == '&') {
the_prog = AMBIGUOUS;
} else if (*tmpchar == NUMBER_TOKEN && number(tmpchar + 1)) {
the_prog = (dbref) atoi(++tmpchar);
} else if (*tmpchar == REGISTERED_TOKEN) {
the_prog = find_registered_obj(what, tmpchar);
} else if (number(tmpchar)) {
the_prog = (dbref) atoi(tmpchar);
} else {
the_prog = NOTHING;
}
} else {
if (the_prog == AMBIGUOUS)
the_prog = NOTHING;
}
if (the_prog != AMBIGUOUS) {
if (the_prog < 0 || the_prog >= db_top) {
the_prog = NOTHING;
} else if (Typeof(the_prog) != TYPE_PROGRAM) {
the_prog = NOTHING;
} else if (OWNER(the_prog) != OWNER(player) && !(FLAGS(the_prog) & LINK_OK)) {
the_prog = NOTHING;
} else if (MLevel(the_prog) < mlev) {
the_prog = NOTHING;
} else if (MLevel(OWNER(the_prog)) < mlev) {
the_prog = NOTHING;
} else if (the_prog == xclude) {
the_prog = NOTHING;
}
}
if (the_prog == AMBIGUOUS) {
if (mpi_p) {
add_mpi_event(1, descr, player, where, trigger, tmpchar + 1,
(mt ? "Listen" : "Olisten"), toparg, 1, (mt == 0),
Prop_Blessed(what, propname));
}
} else if (the_prog != NOTHING) {
add_muf_queue_event(descr, player, where, trigger, the_prog, toparg,
"(_Listen)", 1);
}
}
}
strcpyn(buf, sizeof(buf), propname);
if (is_propdir(what, buf)) {
strcatn(buf, sizeof(buf), "/");
while ((pname = next_prop_name(what, exbuf, sizeof(exbuf), buf))) {
*buf = '\0';
strcatn(buf, sizeof(buf), pname);
listenqueue(descr, player, where, trigger, what, xclude, buf,
toparg, mlev, mt, mpi_p);
}
}
}