SCP: Add a RUNLIMIT command to bound simulator execution time
This commit is contained in:
parent
35252369eb
commit
7581b92f9d
5 changed files with 145 additions and 8 deletions
|
@ -405,6 +405,7 @@ Device simulator authors can easily schedule their device polling activities to
|
|||
RUN UNTIL "output-string" ... Establish the specified "output-string" as an EXPECT and run until it is encountered.
|
||||
GO UNTIL breakpoint Establish the breakpoint specified and go until it is encountered
|
||||
GO UNTIL "output-string" ... Establish the specified "output-string" as an EXPECT and go until it is encountered.
|
||||
RUNLIMIT Bound simulator execution time
|
||||
|
||||
#### Command Processing Enhancements
|
||||
|
||||
|
|
BIN
doc/simh_doc.doc
BIN
doc/simh_doc.doc
Binary file not shown.
134
scp.c
134
scp.c
|
@ -545,6 +545,7 @@ t_stat dep_addr (int32 flag, const char *cptr, t_addr addr, DEVICE *dptr,
|
|||
UNIT *uptr, int32 dfltinc);
|
||||
void fprint_fields (FILE *stream, t_value before, t_value after, BITFIELD* bitdefs);
|
||||
t_stat step_svc (UNIT *ptr);
|
||||
t_stat runlimit_svc (UNIT *ptr);
|
||||
t_stat expect_svc (UNIT *ptr);
|
||||
t_stat flush_svc (UNIT *ptr);
|
||||
t_stat shift_args (char *do_arg[], size_t arg_count);
|
||||
|
@ -596,6 +597,10 @@ int32 sim_brk_lnt = 0;
|
|||
int32 sim_brk_ins = 0;
|
||||
int32 sim_quiet = 0;
|
||||
int32 sim_step = 0;
|
||||
int32 sim_runlimit = 0;
|
||||
double sim_runlimit_d = 0.0;
|
||||
int32 sim_runlimit_switches = 0;
|
||||
t_bool sim_runlimit_enabled = FALSE;
|
||||
char *sim_sub_instr = NULL; /* Copy of pre-substitution buffer contents */
|
||||
char *sim_sub_instr_buf = NULL; /* Buffer address that substitutions were saved in */
|
||||
size_t sim_sub_instr_size = 0; /* substitution buffer size */
|
||||
|
@ -662,6 +667,31 @@ DEVICE sim_step_dev = {
|
|||
NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
sim_int_step_description};
|
||||
|
||||
static const char *sim_int_runlimit_description (DEVICE *dptr)
|
||||
{
|
||||
return "Run time limit facility";
|
||||
}
|
||||
|
||||
static t_stat sim_int_runlimit_reset (DEVICE *dptr)
|
||||
{
|
||||
if (sim_runlimit_enabled) {
|
||||
if (sim_runlimit_switches & SWMASK ('T'))
|
||||
return sim_activate_after_d (dptr->units, sim_runlimit_d);
|
||||
else
|
||||
return sim_activate (dptr->units, sim_runlimit);
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
static UNIT sim_runlimit_unit = { UDATA (&runlimit_svc, UNIT_IDLE, 0) };
|
||||
DEVICE sim_runlimit_dev = {
|
||||
"INT-RUNLIMIT", &sim_runlimit_unit, NULL, NULL,
|
||||
1, 0, 0, 0, 0, 0,
|
||||
NULL, NULL, &sim_int_runlimit_reset, NULL, NULL, NULL,
|
||||
NULL, DEV_NOSAVE, 0,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
sim_int_runlimit_description};
|
||||
|
||||
static const char *sim_int_expect_description (DEVICE *dptr)
|
||||
{
|
||||
return "Expect facility";
|
||||
|
@ -764,6 +794,7 @@ const struct scp_error {
|
|||
{"INVEXPR", "invalid expression"},
|
||||
{"SIGTERM", "SIGTERM received"},
|
||||
{"FSSIZE", "File System size larger than disk size"},
|
||||
{"RUNTIME", "Run time limit exhausted"},
|
||||
};
|
||||
|
||||
const size_t size_map[] = { sizeof (int8),
|
||||
|
@ -1072,6 +1103,20 @@ static const char simh_help[] =
|
|||
" \"SET NODEBUG\" commands. Additionally, support is provided that is\n"
|
||||
" equivalent to the \"SET <dev> DEBUG=opt1{;opt2}\" and\n"
|
||||
" \"SET <dev> NODEBUG=opt1{;opt2}\" commands.\n\n"
|
||||
#define HLP_RUNLIMIT "*Commands Stopping_The_Simulator User_Specified_Stop_Conditions RUNLIMIT"
|
||||
"4RUNLIMIT\n"
|
||||
" A simulator user may want to limit the maximum execution time that a\n"
|
||||
" simulator may run for. This might be appropriate to limit a runaway\n"
|
||||
" diagnostic which didn't achieve explicit success or failure within\n"
|
||||
" some user specified time. The RUNLIMIT command provides ways to\n"
|
||||
" limit execution.\n\n"
|
||||
"++RUNLIMIT n {CYCLES|MICROSECONDS|SECONDS|MINUTES|HOURS}\n"
|
||||
"++NORUNLIMIT\n\n"
|
||||
" If the units of the run limit are not specified, the default units are\n"
|
||||
" cycles. Once an execution run limit has beenn reached, any subsequent\n"
|
||||
" GO, RUN, CONTINUE, STEP or BOOT commands will cause the simulator to\n"
|
||||
" exit. A previously defined RUNLIMIT can be cleared with the NORUNLIMIT\n"
|
||||
" command or the establishment of a new run limit.\n"
|
||||
/***************** 80 character line width template *************************/
|
||||
"2Connecting and Disconnecting Devices\n"
|
||||
" Except for main memory and network devices, units are simulated as\n"
|
||||
|
@ -1802,6 +1847,8 @@ static const char simh_help[] =
|
|||
" Invalid remote console command\n"
|
||||
"5 AMBREG\n"
|
||||
" Ambiguous register\n"
|
||||
"5 RUNTIME\n"
|
||||
" Run time limit exhausted\n"
|
||||
#define HLP_SHIFT "*Commands Executing_Command_Files SHIFT"
|
||||
"3SHIFT\n"
|
||||
"++shift shift the command file's positional parameters\n"
|
||||
|
@ -2389,6 +2436,8 @@ static CTAB cmd_table[] = {
|
|||
#if defined(USE_SIM_VIDEO)
|
||||
{ "SCREENSHOT", &screenshot_cmd,0, HLP_SCREENSHOT, NULL, NULL },
|
||||
#endif
|
||||
{ "RUNLIMIT", &runlimit_cmd, 1, HLP_RUNLIMIT, NULL, NULL },
|
||||
{ "NORUNLIMIT", &runlimit_cmd, 0, HLP_RUNLIMIT, NULL, NULL },
|
||||
{ NULL, NULL, 0, NULL, NULL, NULL }
|
||||
};
|
||||
|
||||
|
@ -2596,6 +2645,7 @@ sim_register_internal_device (&sim_scp_dev);
|
|||
sim_register_internal_device (&sim_expect_dev);
|
||||
sim_register_internal_device (&sim_step_dev);
|
||||
sim_register_internal_device (&sim_flush_dev);
|
||||
sim_register_internal_device (&sim_runlimit_dev);
|
||||
|
||||
if ((stat = sim_ttinit ()) != SCPE_OK) {
|
||||
fprintf (stderr, "Fatal terminal initialization error\n%s\n",
|
||||
|
@ -6827,6 +6877,69 @@ if (dptr->reset != NULL)
|
|||
else return SCPE_OK;
|
||||
}
|
||||
|
||||
t_stat runlimit_cmd (int32 flag, CONST char *cptr)
|
||||
{
|
||||
char gbuf[CBUFSIZE];
|
||||
int32 num;
|
||||
t_stat r;
|
||||
double usec_factor = 1.0;
|
||||
|
||||
GET_SWITCHES (cptr); /* get switches */
|
||||
if (0 == flag) {
|
||||
if (*cptr)
|
||||
return sim_messagef (SCPE_ARG, "NORUNLIMIT expects no arguments: %s\n", cptr);
|
||||
sim_runlimit = 0;
|
||||
sim_runlimit_switches = 0;
|
||||
sim_runlimit_enabled = FALSE;
|
||||
sim_cancel (&sim_runlimit_unit);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */
|
||||
num = (int32) get_uint (gbuf, 10, INT_MAX, &r);
|
||||
if ((r != SCPE_OK) || (num == 0)) /* error? */
|
||||
return sim_messagef (SCPE_ARG, "Invalid argument: %s\n", gbuf);
|
||||
cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */
|
||||
if (MATCH_CMD (gbuf, "CYCLES") == 0)
|
||||
sim_switches &= ~SWMASK ('T');
|
||||
else {
|
||||
int i;
|
||||
struct {
|
||||
const char *name;
|
||||
double usec_factor;
|
||||
} time_units[] = {
|
||||
{"MICROSECONDS", 1.0},
|
||||
{"USECONDS", 1.0},
|
||||
{"SECONDS", 1000000.0},
|
||||
{"MINUTES", 60*1000000.0},
|
||||
{"HOURS", 60*60*1000000.0},
|
||||
{NULL, 0.0}};
|
||||
|
||||
for (i=0; time_units[i].name; i++) {
|
||||
if (MATCH_CMD (gbuf, time_units[i].name) == 0) {
|
||||
sim_switches |= SWMASK ('T');
|
||||
usec_factor = time_units[i].usec_factor;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (time_units[i].name == NULL)
|
||||
return sim_messagef (SCPE_2MARG, "Too many arguments: %s %s\n", gbuf, cptr);
|
||||
}
|
||||
if (*cptr)
|
||||
return sim_messagef (SCPE_2MARG, "Too many arguments: %s\n", cptr);
|
||||
sim_runlimit_enabled = TRUE;
|
||||
sim_cancel (&sim_runlimit_unit);
|
||||
sim_runlimit_switches = sim_switches;
|
||||
if (sim_runlimit_switches & SWMASK ('T')) {
|
||||
sim_runlimit_d = num * usec_factor;
|
||||
return sim_activate_after_d (&sim_runlimit_unit, sim_runlimit_d);
|
||||
}
|
||||
else {
|
||||
sim_runlimit = num;
|
||||
return sim_activate (&sim_runlimit_unit, sim_runlimit);
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset devices start..end
|
||||
|
||||
Inputs:
|
||||
|
@ -7950,6 +8063,11 @@ t_stat r;
|
|||
DEVICE *dptr;
|
||||
UNIT *uptr;
|
||||
|
||||
if (sim_runlimit_enabled && /* If the run limit has been hit? */
|
||||
(!sim_is_active (&sim_runlimit_unit))) {
|
||||
sim_messagef (SCPE_RUNTIME, "Execution limit exceeded, can't proceed. Exiting...\n");
|
||||
exit (SCPE_RUNTIME); /* Execution can't proceed */
|
||||
}
|
||||
GET_SWITCHES (cptr); /* get switches */
|
||||
sim_step = 0;
|
||||
if ((flag == RU_RUN) || (flag == RU_GO)) { /* run or go */
|
||||
|
@ -8168,6 +8286,13 @@ if ((SCPE_BARE_STATUS(r) == SCPE_STOP) &&
|
|||
sigterm_received)
|
||||
r = SCPE_SIGTERM;
|
||||
|
||||
if (sim_runlimit_enabled) {
|
||||
if (sim_runlimit_switches & SWMASK ('T'))
|
||||
sim_runlimit_d = sim_activate_time_usecs (&sim_runlimit_unit);
|
||||
else
|
||||
sim_runlimit = sim_activate_time (&sim_runlimit_unit);
|
||||
}
|
||||
|
||||
if ((SCPE_BARE_STATUS(r) == SCPE_STOP) && /* WRU exit from sim_instr() */
|
||||
(sim_on_actions[sim_do_depth][SCPE_STOP] == NULL) &&/* without a handler for a STOP condition */
|
||||
(sim_on_actions[sim_do_depth][0] == NULL))
|
||||
|
@ -8298,6 +8423,14 @@ t_stat step_svc (UNIT *uptr)
|
|||
return SCPE_STEP;
|
||||
}
|
||||
|
||||
/* Unit service for run for timeout, originally scheduled by RUNFOR n command
|
||||
Return runlimit timeout SCP code, will cause simulation to stop */
|
||||
|
||||
t_stat runlimit_svc (UNIT *uptr)
|
||||
{
|
||||
return SCPE_RUNTIME;
|
||||
}
|
||||
|
||||
/* Unit service to facilitate expect matching to stop simulation.
|
||||
Return expect SCP code, will cause simulation to stop */
|
||||
|
||||
|
@ -10900,6 +11033,7 @@ do {
|
|||
(bare_reason != SCPE_MTRLNT) &&
|
||||
(bare_reason != SCPE_STOP) &&
|
||||
(bare_reason != SCPE_STEP) &&
|
||||
(bare_reason != SCPE_RUNTIME) &&
|
||||
(bare_reason != SCPE_EXIT))
|
||||
sim_messagef (reason, "\nUnexpected internal error while processing event for %s which returned %d - %s\n", sim_uname (uptr), reason, sim_error_text (reason));
|
||||
} while ((reason == SCPE_OK) &&
|
||||
|
|
1
scp.h
1
scp.h
|
@ -116,6 +116,7 @@ t_stat spawn_cmd (int32 flag, CONST char *ptr);
|
|||
t_stat echo_cmd (int32 flag, CONST char *ptr);
|
||||
t_stat echof_cmd (int32 flag, CONST char *ptr);
|
||||
t_stat debug_cmd (int32 flag, CONST char *ptr);
|
||||
t_stat runlimit_cmd (int32 flag, CONST char *ptr);
|
||||
|
||||
/* Allow compiler to help validate printf style format arguments */
|
||||
#if !defined __GNUC__
|
||||
|
|
|
@ -413,8 +413,9 @@ typedef uint32 t_addr;
|
|||
#define SCPE_INVEXPR (SCPE_BASE + 47) /* invalid expression */
|
||||
#define SCPE_SIGTERM (SCPE_BASE + 48) /* SIGTERM has been received */
|
||||
#define SCPE_FSSIZE (SCPE_BASE + 49) /* File System size larger than disk size */
|
||||
#define SCPE_RUNTIME (SCPE_BASE + 50) /* Run Time Limit Exhausted */
|
||||
|
||||
#define SCPE_MAX_ERR (SCPE_BASE + 49) /* Maximum SCPE Error Value */
|
||||
#define SCPE_MAX_ERR (SCPE_BASE + 50) /* Maximum SCPE Error Value */
|
||||
#define SCPE_KFLAG 0x10000000 /* tti data flag */
|
||||
#define SCPE_BREAK 0x20000000 /* tti break flag */
|
||||
#define SCPE_NOMESSAGE 0x40000000 /* message display supression flag */
|
||||
|
|
Loading…
Add table
Reference in a new issue