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.
|
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 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.
|
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
|
#### 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);
|
UNIT *uptr, int32 dfltinc);
|
||||||
void fprint_fields (FILE *stream, t_value before, t_value after, BITFIELD* bitdefs);
|
void fprint_fields (FILE *stream, t_value before, t_value after, BITFIELD* bitdefs);
|
||||||
t_stat step_svc (UNIT *ptr);
|
t_stat step_svc (UNIT *ptr);
|
||||||
|
t_stat runlimit_svc (UNIT *ptr);
|
||||||
t_stat expect_svc (UNIT *ptr);
|
t_stat expect_svc (UNIT *ptr);
|
||||||
t_stat flush_svc (UNIT *ptr);
|
t_stat flush_svc (UNIT *ptr);
|
||||||
t_stat shift_args (char *do_arg[], size_t arg_count);
|
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_brk_ins = 0;
|
||||||
int32 sim_quiet = 0;
|
int32 sim_quiet = 0;
|
||||||
int32 sim_step = 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 = NULL; /* Copy of pre-substitution buffer contents */
|
||||||
char *sim_sub_instr_buf = NULL; /* Buffer address that substitutions were saved in */
|
char *sim_sub_instr_buf = NULL; /* Buffer address that substitutions were saved in */
|
||||||
size_t sim_sub_instr_size = 0; /* substitution buffer size */
|
size_t sim_sub_instr_size = 0; /* substitution buffer size */
|
||||||
|
@ -662,6 +667,31 @@ DEVICE sim_step_dev = {
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL,
|
NULL, NULL, NULL, NULL, NULL, NULL,
|
||||||
sim_int_step_description};
|
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)
|
static const char *sim_int_expect_description (DEVICE *dptr)
|
||||||
{
|
{
|
||||||
return "Expect facility";
|
return "Expect facility";
|
||||||
|
@ -764,6 +794,7 @@ const struct scp_error {
|
||||||
{"INVEXPR", "invalid expression"},
|
{"INVEXPR", "invalid expression"},
|
||||||
{"SIGTERM", "SIGTERM received"},
|
{"SIGTERM", "SIGTERM received"},
|
||||||
{"FSSIZE", "File System size larger than disk size"},
|
{"FSSIZE", "File System size larger than disk size"},
|
||||||
|
{"RUNTIME", "Run time limit exhausted"},
|
||||||
};
|
};
|
||||||
|
|
||||||
const size_t size_map[] = { sizeof (int8),
|
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"
|
" \"SET NODEBUG\" commands. Additionally, support is provided that is\n"
|
||||||
" equivalent to the \"SET <dev> DEBUG=opt1{;opt2}\" and\n"
|
" equivalent to the \"SET <dev> DEBUG=opt1{;opt2}\" and\n"
|
||||||
" \"SET <dev> NODEBUG=opt1{;opt2}\" commands.\n\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 *************************/
|
/***************** 80 character line width template *************************/
|
||||||
"2Connecting and Disconnecting Devices\n"
|
"2Connecting and Disconnecting Devices\n"
|
||||||
" Except for main memory and network devices, units are simulated as\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"
|
" Invalid remote console command\n"
|
||||||
"5 AMBREG\n"
|
"5 AMBREG\n"
|
||||||
" Ambiguous register\n"
|
" Ambiguous register\n"
|
||||||
|
"5 RUNTIME\n"
|
||||||
|
" Run time limit exhausted\n"
|
||||||
#define HLP_SHIFT "*Commands Executing_Command_Files SHIFT"
|
#define HLP_SHIFT "*Commands Executing_Command_Files SHIFT"
|
||||||
"3SHIFT\n"
|
"3SHIFT\n"
|
||||||
"++shift shift the command file's positional parameters\n"
|
"++shift shift the command file's positional parameters\n"
|
||||||
|
@ -2389,6 +2436,8 @@ static CTAB cmd_table[] = {
|
||||||
#if defined(USE_SIM_VIDEO)
|
#if defined(USE_SIM_VIDEO)
|
||||||
{ "SCREENSHOT", &screenshot_cmd,0, HLP_SCREENSHOT, NULL, NULL },
|
{ "SCREENSHOT", &screenshot_cmd,0, HLP_SCREENSHOT, NULL, NULL },
|
||||||
#endif
|
#endif
|
||||||
|
{ "RUNLIMIT", &runlimit_cmd, 1, HLP_RUNLIMIT, NULL, NULL },
|
||||||
|
{ "NORUNLIMIT", &runlimit_cmd, 0, HLP_RUNLIMIT, NULL, NULL },
|
||||||
{ NULL, NULL, 0, NULL, 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_expect_dev);
|
||||||
sim_register_internal_device (&sim_step_dev);
|
sim_register_internal_device (&sim_step_dev);
|
||||||
sim_register_internal_device (&sim_flush_dev);
|
sim_register_internal_device (&sim_flush_dev);
|
||||||
|
sim_register_internal_device (&sim_runlimit_dev);
|
||||||
|
|
||||||
if ((stat = sim_ttinit ()) != SCPE_OK) {
|
if ((stat = sim_ttinit ()) != SCPE_OK) {
|
||||||
fprintf (stderr, "Fatal terminal initialization error\n%s\n",
|
fprintf (stderr, "Fatal terminal initialization error\n%s\n",
|
||||||
|
@ -6827,6 +6877,69 @@ if (dptr->reset != NULL)
|
||||||
else return SCPE_OK;
|
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
|
/* Reset devices start..end
|
||||||
|
|
||||||
Inputs:
|
Inputs:
|
||||||
|
@ -7950,6 +8063,11 @@ t_stat r;
|
||||||
DEVICE *dptr;
|
DEVICE *dptr;
|
||||||
UNIT *uptr;
|
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 */
|
GET_SWITCHES (cptr); /* get switches */
|
||||||
sim_step = 0;
|
sim_step = 0;
|
||||||
if ((flag == RU_RUN) || (flag == RU_GO)) { /* run or go */
|
if ((flag == RU_RUN) || (flag == RU_GO)) { /* run or go */
|
||||||
|
@ -8168,6 +8286,13 @@ if ((SCPE_BARE_STATUS(r) == SCPE_STOP) &&
|
||||||
sigterm_received)
|
sigterm_received)
|
||||||
r = SCPE_SIGTERM;
|
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() */
|
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][SCPE_STOP] == NULL) &&/* without a handler for a STOP condition */
|
||||||
(sim_on_actions[sim_do_depth][0] == NULL))
|
(sim_on_actions[sim_do_depth][0] == NULL))
|
||||||
|
@ -8298,6 +8423,14 @@ t_stat step_svc (UNIT *uptr)
|
||||||
return SCPE_STEP;
|
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.
|
/* Unit service to facilitate expect matching to stop simulation.
|
||||||
Return expect SCP code, will cause simulation to stop */
|
Return expect SCP code, will cause simulation to stop */
|
||||||
|
|
||||||
|
@ -10900,6 +11033,7 @@ do {
|
||||||
(bare_reason != SCPE_MTRLNT) &&
|
(bare_reason != SCPE_MTRLNT) &&
|
||||||
(bare_reason != SCPE_STOP) &&
|
(bare_reason != SCPE_STOP) &&
|
||||||
(bare_reason != SCPE_STEP) &&
|
(bare_reason != SCPE_STEP) &&
|
||||||
|
(bare_reason != SCPE_RUNTIME) &&
|
||||||
(bare_reason != SCPE_EXIT))
|
(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));
|
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) &&
|
} 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 echo_cmd (int32 flag, CONST char *ptr);
|
||||||
t_stat echof_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 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 */
|
/* Allow compiler to help validate printf style format arguments */
|
||||||
#if !defined __GNUC__
|
#if !defined __GNUC__
|
||||||
|
|
|
@ -413,8 +413,9 @@ typedef uint32 t_addr;
|
||||||
#define SCPE_INVEXPR (SCPE_BASE + 47) /* invalid expression */
|
#define SCPE_INVEXPR (SCPE_BASE + 47) /* invalid expression */
|
||||||
#define SCPE_SIGTERM (SCPE_BASE + 48) /* SIGTERM has been received */
|
#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_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_KFLAG 0x10000000 /* tti data flag */
|
||||||
#define SCPE_BREAK 0x20000000 /* tti break flag */
|
#define SCPE_BREAK 0x20000000 /* tti break flag */
|
||||||
#define SCPE_NOMESSAGE 0x40000000 /* message display supression flag */
|
#define SCPE_NOMESSAGE 0x40000000 /* message display supression flag */
|
||||||
|
|
Loading…
Add table
Reference in a new issue