From 2b5ceae2be18106dbb6414a44698051407e83c24 Mon Sep 17 00:00:00 2001 From: Mark Pizzolato Date: Wed, 12 Dec 2012 10:58:19 -0800 Subject: [PATCH] Added missing sim_cancel support for device simulation code using the sim_disk and sim_tape libraries and doing asynchronous I/O if asynchronous I/O is active --- scp.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++-- scp.h | 2 ++ sim_defs.h | 7 ++++++- sim_disk.c | 29 +++++++++++++++++++++++++++-- sim_tape.c | 27 ++++++++++++++++++++++++++- 5 files changed, 110 insertions(+), 6 deletions(-) diff --git a/scp.c b/scp.c index 79316e45..9f76b599 100644 --- a/scp.c +++ b/scp.c @@ -3144,7 +3144,7 @@ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru devices */ WRITE_I (dptr->flags); /* [V2.10] flags */ for (j = 0; j < dptr->numunits; j++) { uptr = dptr->units + j; - t = sim_is_active (uptr); + t = sim_activate_time (uptr); WRITE_I (j); /* unit number */ WRITE_I (t); /* activation time */ WRITE_I (uptr->u3); /* unit specific */ @@ -5221,6 +5221,7 @@ return SCPE_OK; sim_cancel remove entry from event queue sim_process_event process entries on event queue sim_is_active see if entry is on event queue + sim_activate_time return time until activation sim_atime return absolute time for an entry sim_gtime return global time sim_qcount return event queue entry count @@ -5357,7 +5358,6 @@ uint32 rtimenow, urtime = (uint32)rtime; AIO_ACTIVATE (sim_activate_notbefore, uptr, rtime); sim_cancel (uptr); rtimenow = sim_grtime(); -sim_cancel (uptr); if (0x80000000 <= urtime-rtimenow) return sim_activate (uptr, 0); else @@ -5378,9 +5378,13 @@ t_stat sim_cancel (UNIT *uptr) UNIT *cptr, *nptr; AIO_VALIDATE; +AIO_CANCEL(uptr); +AIO_UPDATE_QUEUE; if (sim_clock_queue == NULL) return SCPE_OK; UPDATE_SIM_TIME (sim_clock_queue->time); /* update sim time */ +if (!sim_is_active_bool (uptr)) + return SCPE_OK; nptr = NULL; if (sim_clock_queue == uptr) nptr = sim_clock_queue = uptr->next; @@ -5415,6 +5419,49 @@ int32 sim_is_active (UNIT *uptr) UNIT *cptr; int32 accum; +AIO_VALIDATE; +AIO_UPDATE_QUEUE; +accum = 0; +for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr->next) { + if (cptr == sim_clock_queue) { + if (sim_interval > 0) + accum = accum + sim_interval; + } + else accum = accum + cptr->time; + if (cptr == uptr) + return accum + 1; + } +return 0; +} + +/* sim_is_active_bool - test for entry in queue + + Inputs: + uptr = pointer to unit + Outputs: + result = TRUE if unit is busy, FALSE inactive +*/ + +t_bool sim_is_active_bool (UNIT *uptr) +{ +AIO_VALIDATE; +AIO_UPDATE_QUEUE; +return ((uptr->next) || AIO_IS_ACTIVE(uptr)); +} + +/* sim_activate_time - return activation time + + Inputs: + uptr = pointer to unit + Outputs: + result = absolute activation time + 1, 0 if inactive +*/ + +int32 sim_activate_time (UNIT *uptr) +{ +UNIT *cptr; +int32 accum; + AIO_VALIDATE; accum = 0; for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr->next) { diff --git a/scp.h b/scp.h index b52d7633..b564cf25 100644 --- a/scp.h +++ b/scp.h @@ -90,6 +90,8 @@ t_stat sim_activate_abs (UNIT *uptr, int32 interval); t_stat sim_activate_notbefore (UNIT *uptr, int32 rtime); t_stat sim_cancel (UNIT *uptr); int32 sim_is_active (UNIT *uptr); +t_bool sim_is_active_bool (UNIT *uptr); +int32 sim_activate_time (UNIT *uptr); double sim_gtime (void); uint32 sim_grtime (void); int32 sim_qcount (void); diff --git a/sim_defs.h b/sim_defs.h index fb187506..f1e97d72 100644 --- a/sim_defs.h +++ b/sim_defs.h @@ -368,6 +368,8 @@ struct sim_unit { void *up8; /* device specific */ #ifdef SIM_ASYNCH_IO void (*a_check_completion)(struct sim_unit *); + t_bool (*a_is_active)(struct sim_unit *); + void (*a_cancel)(struct sim_unit *); struct sim_unit *a_next; /* next asynch active */ int32 a_event_time; t_stat (*a_activate_call)(struct sim_unit *, int32); @@ -609,7 +611,8 @@ extern int32 sim_asynch_inst_latency; pthread_mutex_destroy(&sim_asynch_lock); \ pthread_cond_destroy(&sim_asynch_wake); \ } - +#define AIO_IS_ACTIVE(uptr) (((uptr)->a_is_active ? (uptr)->a_is_active (uptr) : FALSE) || ((uptr)->a_next)) +#define AIO_CANCEL(uptr) if ((uptr)->a_cancel) (uptr)->a_cancel (uptr); else (void)0 #if defined(__DECC_VER) #include #if defined(__IA64) @@ -750,6 +753,8 @@ extern int32 sim_asynch_inst_latency; #define AIO_CHECK_EVENT #define AIO_INIT #define AIO_CLEANUP +#define AIO_IS_ACTIVE(uptr) FALSE +#define AIO_CANCEL(uptr) #define AIO_SET_INTERRUPT_LATENCY(instpersec) #endif /* SIM_ASYNCH_IO */ diff --git a/sim_disk.c b/sim_disk.c index 8397c15b..7ada5cc4 100644 --- a/sim_disk.c +++ b/sim_disk.c @@ -108,6 +108,7 @@ struct disk_context { pthread_t io_thread; /* I/O Thread Id */ pthread_mutex_t io_lock; pthread_cond_t io_cond; + pthread_cond_t io_done; pthread_cond_t startup_cond; int io_dop; uint8 *buf; @@ -196,6 +197,7 @@ while (ctx->asynch_io) { } pthread_mutex_lock (&ctx->io_lock); ctx->io_dop = DOP_DONE; + pthread_cond_signal (&ctx->io_done); sim_activate (uptr, ctx->asynch_io_latency); } pthread_mutex_unlock (&ctx->io_lock); @@ -209,7 +211,7 @@ return NULL; processing events for any unit. It is only called when an asynchronous thread has called sim_activate() to activate a unit. The job of this routine is to put the unit in proper condition to digest what may have - occurred in the asynchrcondition thread. + occurred in the asynchrconous thread. Since disk processing only handles a single I/O at a time to a particular disk device (due to using stdio for the SimH Disk format @@ -231,6 +233,25 @@ if (ctx->callback && ctx->io_dop == DOP_DONE) { callback (uptr, ctx->io_status); } } + +static t_bool _disk_is_active (UNIT *uptr) +{ +struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; + +sim_debug (ctx->dbit, ctx->dptr, "_disk_is_active(unit=%d, dop=%d)\n", uptr-ctx->dptr->units, ctx->io_dop); +return (ctx->io_dop != DOP_DONE); +} + +static void _disk_cancel (UNIT *uptr) +{ +struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx; + +sim_debug (ctx->dbit, ctx->dptr, "_disk_cancel(unit=%d, dop=%d)\n", uptr-ctx->dptr->units, ctx->io_dop); +pthread_mutex_lock (&ctx->io_lock); +while (ctx->io_dop != DOP_DONE) + pthread_cond_wait (&ctx->io_done, &ctx->io_lock); +pthread_mutex_unlock (&ctx->io_lock); +} #else #define AIO_CALLSETUP #define AIO_CALL(op, _lba, _buf, _rsects, _sects, _callback) \ @@ -425,6 +446,7 @@ ctx->asynch_io_latency = latency; if (ctx->asynch_io) { pthread_mutex_init (&ctx->io_lock, NULL); pthread_cond_init (&ctx->io_cond, NULL); + pthread_cond_init (&ctx->io_done, NULL); pthread_cond_init (&ctx->startup_cond, NULL); pthread_attr_init(&attr); pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); @@ -434,8 +456,10 @@ if (ctx->asynch_io) { pthread_cond_wait (&ctx->startup_cond, &ctx->io_lock); /* Wait for thread to stabilize */ pthread_mutex_unlock (&ctx->io_lock); pthread_cond_destroy (&ctx->startup_cond); - uptr->a_check_completion = _disk_completion_dispatch; } +uptr->a_check_completion = _disk_completion_dispatch; +uptr->a_is_active = _disk_is_active; +uptr->a_cancel = _disk_cancel; #endif return SCPE_OK; } @@ -460,6 +484,7 @@ if (ctx->asynch_io) { pthread_join (ctx->io_thread, NULL); pthread_mutex_destroy (&ctx->io_lock); pthread_cond_destroy (&ctx->io_cond); + pthread_cond_destroy (&ctx->io_done); } return SCPE_OK; #endif diff --git a/sim_tape.c b/sim_tape.c index 91cf3032..2c5b946a 100644 --- a/sim_tape.c +++ b/sim_tape.c @@ -125,6 +125,7 @@ struct tape_context { pthread_t io_thread; /* I/O Thread Id */ pthread_mutex_t io_lock; pthread_cond_t io_cond; + pthread_cond_t io_done; pthread_cond_t startup_cond; int io_top; uint8 *buf; @@ -273,6 +274,7 @@ struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; } pthread_mutex_lock (&ctx->io_lock); ctx->io_top = TOP_DONE; + pthread_cond_signal (&ctx->io_done); sim_activate (uptr, ctx->asynch_io_latency); } pthread_mutex_unlock (&ctx->io_lock); @@ -286,7 +288,7 @@ struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; processing events for any unit. It is only called when an asynchronous thread has called sim_activate() to activate a unit. The job of this routine is to put the unit in proper condition to digest what may have - occurred in the asynchrcondition thread. + occurred in the asynchronous thread. Since tape processing only handles a single I/O at a time to a particular tape device, we have the opportunity to possibly detect @@ -306,6 +308,25 @@ if (ctx->callback && ctx->io_top == TOP_DONE) { callback (uptr, ctx->io_status); } } + +static t_bool _tape_is_active (UNIT *uptr) +{ +struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; + +sim_debug (ctx->dbit, ctx->dptr, "_tape_is_active(unit=%d, top=%d)\n", uptr-ctx->dptr->units, ctx->io_top); +return (ctx->io_top != TOP_DONE); +} + +static void _tape_cancel (UNIT *uptr) +{ +struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx; + +sim_debug (ctx->dbit, ctx->dptr, "_tape_cancel(unit=%d, top=%d)\n", uptr-ctx->dptr->units, ctx->io_top); +pthread_mutex_lock (&ctx->io_lock); +while (ctx->io_top != TOP_DONE) + pthread_cond_wait (&ctx->io_done, &ctx->io_lock); +pthread_mutex_unlock (&ctx->io_lock); +} #else #define AIO_CALLSETUP #define AIO_CALL(op, _buf, _fc, _bc, _max, _vbc, _gaplen, _bpi, _obj, _callback) \ @@ -333,6 +354,7 @@ ctx->asynch_io_latency = latency; if (ctx->asynch_io) { pthread_mutex_init (&ctx->io_lock, NULL); pthread_cond_init (&ctx->io_cond, NULL); + pthread_cond_init (&ctx->io_done, NULL); pthread_cond_init (&ctx->startup_cond, NULL); pthread_attr_init(&attr); pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); @@ -344,6 +366,8 @@ if (ctx->asynch_io) { pthread_cond_destroy (&ctx->startup_cond); } uptr->a_check_completion = _tape_completion_dispatch; +uptr->a_is_active = _tape_is_active; +uptr->a_cancel = _tape_cancel; #endif return SCPE_OK; } @@ -368,6 +392,7 @@ if (ctx->asynch_io) { pthread_join (ctx->io_thread, NULL); pthread_mutex_destroy (&ctx->io_lock); pthread_cond_destroy (&ctx->io_cond); + pthread_cond_destroy (&ctx->io_done); } return SCPE_OK; #endif