diff --git a/0readmeAsynchIO.txt b/0readmeAsynchIO.txt index b41cf4f9..28a8205b 100644 --- a/0readmeAsynchIO.txt +++ b/0readmeAsynchIO.txt @@ -5,6 +5,9 @@ Theory of operation. Features. - Optional Use. Build with or without SIM_ASYNCH_IO defined and simulators will still build and perform correctly when run. + Additionmally, a simulator built with SIM_ASYNCH_IO defined can + dynamically disable and reenable asynchronous operation with + the scp commands SET NOASYNCH and SET ASYNCH respectively. - Consistent Save/Restore state. The state of a simulator saved on a simulator with (or without) Asynch support can be restored on any simulator of the same version with or without Asynch diff --git a/VAX/vax_stddev.c b/VAX/vax_stddev.c index 881fcefb..4aa97572 100644 --- a/VAX/vax_stddev.c +++ b/VAX/vax_stddev.c @@ -180,6 +180,7 @@ REG clk_reg[] = { { DRDATA (POLL, tmr_poll, 24), REG_NZ + PV_LEFT + REG_HRO }, { DRDATA (TPS, clk_tps, 8), REG_NZ + PV_LEFT }, #if defined (SIM_ASYNCH_IO) + { DRDATA (ASYNCH, sim_asynch_enabled, 1), PV_LEFT }, { DRDATA (LATENCY, sim_asynch_latency, 32), PV_LEFT }, { DRDATA (INST_LATENCY, sim_asynch_inst_latency, 32), PV_LEFT }, #endif diff --git a/scp.c b/scp.c index 47a70ca4..7e1e487b 100644 --- a/scp.c +++ b/scp.c @@ -23,6 +23,17 @@ used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 25-Sep-11 MP Added the ability for a simulator built with + SIM_ASYNCH_IO to change whether I/O is actually done + asynchronously by the new scp command SET ASYNCH and + SET NOASYNCH + 22-Sep-11 MP Added signal catching of SIGHUP and SIGTERM to cause + simulator STOP. This allows an externally signalled + event (i.e. system shutdown, or logoff) to signal a + running simulator of these events and to allow + reasonable actions to be taken. This will facilitate + running a simulator as a 'service' on *nix platforms, + given a sufficiently flexible simulator .ini file. 20-Apr-11 MP Added expansion of %STATUS% and %TSTATUS% in do command arguments. STATUS is the numeric value of the last command error status and TSTATUS is the text message @@ -271,6 +282,7 @@ pthread_mutex_t sim_asynch_lock = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t sim_asynch_wake = PTHREAD_COND_INITIALIZER; pthread_t sim_asynch_main_threadid; struct sim_unit *sim_asynch_queue = NULL; +t_bool sim_asynch_enabled = TRUE; int32 sim_asynch_check; int32 sim_asynch_latency = 4000; /* 4 usec interrupt latency */ int32 sim_asynch_inst_latency = 20; /* assume 5 mip simulator */ @@ -387,6 +399,7 @@ t_stat dep_addr (int32 flag, char *cptr, t_addr addr, DEVICE *dptr, t_stat step_svc (UNIT *ptr); void sub_args (char *instr, char *tmpbuf, int32 maxstr, char *do_arg[]); t_stat set_on (int32 flag, char *cptr); +t_stat set_asynch (int32 flag, char *cptr); /* Global data */ @@ -605,6 +618,8 @@ static CTAB cmd_table[] = { "set nobreak clear breakpoints\n" "set throttle x{M|K|%%} set simulation rate\n" "set nothrottle set simulation rate to maximum\n" + "set asynch enable asynchronous I/O\n" + "set noasynch disable asynchronous I/O\n" "set OCT|DEC|HEX set device display radix\n" "set ENABLED enable device\n" "set DISABLED disable device\n" @@ -628,6 +643,7 @@ static CTAB cmd_table[] = { "sh{ow} q{ueue} show event queue\n" "sh{ow} ti{me} show simulated time\n" "sh{ow} th{rottle} show simulation rate\n" + "sh{ow} a{synch} show asynchronouse I/O state\n" "sh{ow} ve{rsion} show simulator version\n" "sh{ow} RADIX show device display radix\n" "sh{ow} DEBUG show device debug flags\n" @@ -1281,6 +1297,61 @@ if ((sim_do_depth != 0) && return SCPE_OK; } +/* Set asynch/noasynch routine */ + +t_stat sim_set_asynch (int32 flag, char *cptr) +{ +if (cptr && (*cptr != 0)) /* now eol? */ + return SCPE_2MARG; +#ifdef SIM_ASYNCH_IO +if (flag == sim_asynch_enabled) /* already set correctly? */ + return SCPE_OK; +sim_asynch_enabled = flag; +if (1) { + uint32 i, j; + DEVICE *dptr; + UNIT *uptr; + + /* Call unit flush routines to report asynch status change to device layer */ + for (i = 1; (dptr = sim_devices[i]) != NULL; i++) { /* flush attached files */ + for (j = 0; j < dptr->numunits; j++) { /* if not buffered in mem */ + uptr = dptr->units + j; + if ((uptr->flags & UNIT_ATT) && /* attached, */ + !(uptr->flags & UNIT_BUF) && /* not buffered, */ + (uptr->fileref)) /* real file, */ + if (uptr->io_flush) /* unit specific flush routine */ + uptr->io_flush (uptr); + } + } + } +if (!sim_quiet) + printf ("Asynchronous I/O %sabled\n", sim_asynch_enabled ? "en" : "dis"); +if (sim_log) + fprintf (sim_log, "Asynchronous I/O %sabled\n", sim_asynch_enabled ? "en" : "dis"); +return SCPE_OK; +#else +if (!sim_quiet) + printf ("Asynchronous I/O is not available in this simulator\n"); +if (sim_log) + fprintf (sim_log, "Asynchronous I/O is not available in this simulator\n"); +return SCPE_NOFNC; +#endif +} + +/* Show asynch routine */ + +t_stat sim_show_asynch (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, char *cptr) +{ +if (cptr && (*cptr != 0)) + return SCPE_2MARG; +#ifdef SIM_ASYNCH_IO +fprintf (st, "Asynchronous I/O is %sabled\n", (sim_asynch_enabled) ? "en" : "dis"); +#else +fprintf (st, "Asynchronous I/O is not available in this simulator\n"); +#endif +return SCPE_OK; +} + /* Set command */ t_stat set_cmd (int32 flag, char *cptr) @@ -1305,6 +1376,8 @@ static CTAB set_glob_tab[] = { { "NODEBUG", &sim_set_deboff, 0 }, /* deprecated */ { "THROTTLE", &sim_set_throt, 1 }, { "NOTHROTTLE", &sim_set_throt, 0 }, + { "ASYNCH", &sim_set_asynch, 1 }, + { "NOASYNCH", &sim_set_asynch, 0 }, { "ON", &set_on, 1 }, { "NOON", &set_on, 0 }, { NULL, NULL, 0 } @@ -1570,6 +1643,7 @@ static SHTAB show_glob_tab[] = { { "TELNET", &sim_show_telnet, 0 }, /* deprecated */ { "DEBUG", &sim_show_debug, 0 }, /* deprecated */ { "THROTTLE", &sim_show_throt, 0 }, + { "ASYNCH", &sim_show_asynch, 0 }, { "ON", &show_on, 0 }, { NULL, NULL, 0 } }; diff --git a/sim_defs.h b/sim_defs.h index 91abc4ef..4df30c98 100644 --- a/sim_defs.h +++ b/sim_defs.h @@ -565,6 +565,7 @@ extern pthread_cond_t sim_asynch_wake; extern pthread_t sim_asynch_main_threadid; extern struct sim_unit *sim_asynch_queue; extern t_bool sim_idle_wait; +extern t_bool sim_asynch_enabled; extern int32 sim_asynch_check; extern int32 sim_asynch_latency; extern int32 sim_asynch_inst_latency; diff --git a/sim_disk.c b/sim_disk.c index 5dbbb012..f38c4b45 100644 --- a/sim_disk.c +++ b/sim_disk.c @@ -408,15 +408,17 @@ return SCPE_NOFNC; struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; pthread_attr_t attr; -ctx->asynch_io = 1; +ctx->asynch_io = sim_asynch_enabled; ctx->asynch_io_latency = latency; -pthread_mutex_init (&ctx->io_lock, NULL); -pthread_cond_init (&ctx->io_cond, NULL); -pthread_attr_init(&attr); -pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); -pthread_create (&ctx->io_thread, &attr, _disk_io, (void *)uptr); -pthread_attr_destroy(&attr); -uptr->a_check_completion = _disk_completion_dispatch; +if (ctx->asynch_io) { + pthread_mutex_init (&ctx->io_lock, NULL); + pthread_cond_init (&ctx->io_cond, NULL); + pthread_attr_init(&attr); + pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); + pthread_create (&ctx->io_thread, &attr, _disk_io, (void *)uptr); + pthread_attr_destroy(&attr); + uptr->a_check_completion = _disk_completion_dispatch; + } #endif return SCPE_OK; } @@ -723,7 +725,8 @@ uint32 f = DK_GET_FMT (uptr); #if defined (SIM_ASYNCH_IO) sim_disk_clr_async (uptr); -sim_disk_set_async (uptr, 0); +if (sim_asynch_enabled) + sim_disk_set_async (uptr, 0); #endif switch (f) { /* case on format */ case DKUF_F_STD: /* Simh */ diff --git a/sim_tape.c b/sim_tape.c index d50a4887..a71aa54b 100644 --- a/sim_tape.c +++ b/sim_tape.c @@ -320,14 +320,16 @@ return SCPE_NOFNC; struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; pthread_attr_t attr; -ctx->asynch_io = 1; +ctx->asynch_io = sim_asynch_enabled; ctx->asynch_io_latency = latency; -pthread_mutex_init (&ctx->io_lock, NULL); -pthread_cond_init (&ctx->io_cond, NULL); -pthread_attr_init(&attr); -pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); -pthread_create (&ctx->io_thread, &attr, _tape_io, (void *)uptr); -pthread_attr_destroy(&attr); +if (ctx->asynch_io) { + pthread_mutex_init (&ctx->io_lock, NULL); + pthread_cond_init (&ctx->io_cond, NULL); + pthread_attr_init(&attr); + pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); + pthread_create (&ctx->io_thread, &attr, _tape_io, (void *)uptr); + pthread_attr_destroy(&attr); + } uptr->a_check_completion = _tape_completion_dispatch; #endif return SCPE_OK; @@ -362,7 +364,8 @@ static void _sim_tape_io_flush (UNIT *uptr) { #if defined (SIM_ASYNCH_IO) sim_tape_clr_async (uptr); -sim_tape_set_async (uptr, 0); +if (sim_asynch_enabled) + sim_tape_set_async (uptr, 0); #endif fflush (uptr->fileref); }