Fixed bug under Asynch I/O where I/O completion did not delay the appropriate time before passing back device status to a simulator. Found by Sergey Oboguev.

This commit is contained in:
Mark Pizzolato 2012-04-02 14:05:12 -07:00
parent 6e6fdd02ae
commit 7ac3557524
8 changed files with 34 additions and 25 deletions

View file

@ -89,7 +89,7 @@ example there now exists the routines:
t_stat sim_tape_rdrecf_a (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max, TAPE_PCALLBACK callback);
The Purpose of the callback function is to record the I/O completion status
and then to schedule the activation of the unit.
and then to schedule the activation of the unit.
Considerations:
Avoiding multiple concurrent users of the unit structure. While asynch
@ -108,7 +108,13 @@ The callback routine must save the I/O completion status in a place
which the next invocation of the unit service routine will reference
and act on it. This allows device code to return error conditions
back to scp in a consistent way without regard to how the callback
routine (and the actual I/O) may have been executed.
routine (and the actual I/O) may have been executed. When the callback
routine is called, it will already be on the simulator event queue with
an event time which was specified when the unit was attached or via a
call to sim_disk_set_async. If no value has been specified then it
will have been scheduled with a delay time of 0. If a different event
firing time is desired, then the callback completion routine should
call sim_activate_abs to schedule the event at the appropriate time.
Required change in device coding.
Devices which wish to leverage the benefits of asynch I/O must rearrange

View file

@ -782,7 +782,6 @@ void rp_io_complete (UNIT *uptr, t_stat status)
{
uptr->io_status = status;
uptr->io_complete = 1;
sim_activate (uptr, 0);
}
/* Service unit timeout
@ -1030,7 +1029,7 @@ t_stat r;
uptr->capac = drv_tab[GET_DTYPE (uptr->flags)].size;
r = sim_disk_attach (uptr, cptr, RP_NUMWD * sizeof (uint16),
sizeof (uint16), TRUE, 0,
drv_tab[GET_DTYPE (uptr->flags)].name, drv_tab[GET_DTYPE (uptr->flags)].sect);
drv_tab[GET_DTYPE (uptr->flags)].name, drv_tab[GET_DTYPE (uptr->flags)].sect, 0);
if (r != SCPE_OK) /* error? */
return r;
drv = (int32) (uptr - rp_dev.units); /* get drv number */

View file

@ -1800,10 +1800,9 @@ sim_debug (DBG_TRC, rq_devmap[cp->cnum], "rq_io_complete(status=%d)\n", status);
uptr->io_status = status;
uptr->io_complete = 1;
if (elapsed > rq_xtime)
sim_activate (uptr, 0);
else
sim_activate (uptr, rq_xtime-elapsed);
/* Reschedule for the appropriate delay */
if (elapsed <= rq_xtime)
sim_activate_abs (uptr, rq_xtime-elapsed);
}
/* Unit service for data transfer commands */
@ -2487,7 +2486,7 @@ t_stat rq_attach (UNIT *uptr, char *cptr)
MSC *cp = rq_ctxmap[uptr->cnum];
t_stat r;
r = sim_disk_attach (uptr, cptr, RQ_NUMBY, sizeof (uint16), (uptr->flags & UNIT_NOAUTO), DBG_DSK, drv_tab[GET_DTYPE (uptr->flags)].name, 0);
r = sim_disk_attach (uptr, cptr, RQ_NUMBY, sizeof (uint16), (uptr->flags & UNIT_NOAUTO), DBG_DSK, drv_tab[GET_DTYPE (uptr->flags)].name, 0, 0);
if (r != SCPE_OK)
return r;

View file

@ -1286,10 +1286,9 @@ sim_debug(DBG_TRC, &tq_dev, "tq_io_complete(status=%d)\n", status);
res->io_status = status;
res->io_complete = 1;
if (elapsed > tq_xtime)
sim_activate (uptr, 0);
else
sim_activate (uptr, tq_xtime-elapsed);
/* Reschedule for the appropriate delay */
if (elapsed <= tq_xtime)
sim_activate_abs (uptr, tq_xtime-elapsed);
}
@ -2025,7 +2024,7 @@ t_stat tq_attach (UNIT *uptr, char *cptr)
{
t_stat r;
r = sim_tape_attach_ex (uptr, cptr, DBG_TAP);
r = sim_tape_attach_ex (uptr, cptr, DBG_TAP, 0);
if (r != SCPE_OK)
return r;
if (tq_csta == CST_UP)

View file

@ -733,9 +733,11 @@ static void _sim_disk_io_flush (UNIT *uptr)
uint32 f = DK_GET_FMT (uptr);
#if defined (SIM_ASYNCH_IO)
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
sim_disk_clr_async (uptr);
if (sim_asynch_enabled)
sim_disk_set_async (uptr, 0);
sim_disk_set_async (uptr, ctx->asynch_io_latency);
#endif
switch (f) { /* case on format */
case DKUF_F_STD: /* Simh */
@ -760,7 +762,8 @@ return stat;
}
t_stat sim_disk_attach (UNIT *uptr, char *cptr, size_t sector_size, size_t xfer_element_size, t_bool dontautosize, uint32 dbit, const char *dtype, uint32 pdp11tracksize)
t_stat sim_disk_attach (UNIT *uptr, char *cptr, size_t sector_size, size_t xfer_element_size, t_bool dontautosize,
uint32 dbit, const char *dtype, uint32 pdp11tracksize, int completion_delay)
{
struct disk_context *ctx;
DEVICE *dptr;
@ -797,7 +800,7 @@ if (sim_switches & SWMASK ('D')) { /* create difference dis
vhd = sim_vhd_disk_create_diff (gbuf, cptr);
if (vhd) {
sim_vhd_disk_close (vhd);
return sim_disk_attach (uptr, gbuf, sector_size, xfer_element_size, dontautosize, dbit, dtype, pdp11tracksize);
return sim_disk_attach (uptr, gbuf, sector_size, xfer_element_size, dontautosize, dbit, dtype, pdp11tracksize, completion_delay);
}
return SCPE_ARG;
}
@ -816,7 +819,7 @@ if (sim_switches & SWMASK ('C')) { /* create vhd disk & cop
sim_switches |= SWMASK ('R') | SWMASK ('E');
sim_quiet = TRUE;
/* First open the source of the copy operation */
r = sim_disk_attach (uptr, cptr, sector_size, xfer_element_size, dontautosize, dbit, dtype, pdp11tracksize);
r = sim_disk_attach (uptr, cptr, sector_size, xfer_element_size, dontautosize, dbit, dtype, pdp11tracksize, completion_delay);
sim_quiet = saved_sim_quiet;
if (r != SCPE_OK) {
sim_switches = saved_sim_switches;
@ -1013,7 +1016,7 @@ if (capac && (capac != (t_addr)-1))
uptr->capac = capac/ctx->capac_factor;
#if defined (SIM_ASYNCH_IO)
sim_disk_set_async (uptr, 0);
sim_disk_set_async (uptr, completion_delay);
#endif
uptr->io_flush = _sim_disk_io_flush;

View file

@ -64,7 +64,8 @@ typedef void (*DISK_PCALLBACK)(UNIT *unit, t_stat status);
/* Prototypes */
t_stat sim_disk_attach (UNIT *uptr, char *cptr, size_t sector_size, size_t xfer_element_size, t_bool dontautosize, uint32 debugbit, const char *drivetype, uint32 pdp11_tracksize);
t_stat sim_disk_attach (UNIT *uptr, char *cptr, size_t sector_size, size_t xfer_element_size, t_bool dontautosize,
uint32 debugbit, const char *drivetype, uint32 pdp11_tracksize, int completion_delay);
t_stat sim_disk_detach (UNIT *uptr);
t_stat sim_disk_rdsect (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects);
t_stat sim_disk_rdsect_a (UNIT *uptr, t_lba lba, uint8 *buf, t_seccnt *sectsread, t_seccnt sects, DISK_PCALLBACK callback);

View file

@ -367,9 +367,11 @@ return SCPE_OK;
static void _sim_tape_io_flush (UNIT *uptr)
{
#if defined (SIM_ASYNCH_IO)
struct tape_context *ctx = (struct tape_context *)uptr->tape_ctx;
sim_tape_clr_async (uptr);
if (sim_asynch_enabled)
sim_tape_set_async (uptr, 0);
sim_tape_set_async (uptr, ctx->asynch_io_latency);
#endif
fflush (uptr->fileref);
}
@ -378,10 +380,10 @@ fflush (uptr->fileref);
t_stat sim_tape_attach (UNIT *uptr, char *cptr)
{
return sim_tape_attach_ex (uptr, cptr, 0);
return sim_tape_attach_ex (uptr, cptr, 0, 0);
}
t_stat sim_tape_attach_ex (UNIT *uptr, char *cptr, uint32 dbit)
t_stat sim_tape_attach_ex (UNIT *uptr, char *cptr, uint32 dbit, int completion_delay)
{
struct tape_context *ctx;
uint32 objc;
@ -429,7 +431,7 @@ ctx->dbit = dbit; /* save debug bit */
sim_tape_rewind (uptr);
#if defined (SIM_ASYNCH_IO)
sim_tape_set_async (uptr, 0);
sim_tape_set_async (uptr, completion_delay);
#endif
uptr->io_flush = _sim_tape_io_flush;

View file

@ -121,7 +121,7 @@ typedef void (*TAPE_PCALLBACK)(UNIT *unit, t_stat status);
/* Prototypes */
t_stat sim_tape_attach_ex (UNIT *uptr, char *cptr, uint32 dbit);
t_stat sim_tape_attach_ex (UNIT *uptr, char *cptr, uint32 dbit, int completion_delay);
t_stat sim_tape_attach (UNIT *uptr, char *cptr);
t_stat sim_tape_detach (UNIT *uptr);
t_stat sim_tape_rdrecf (UNIT *uptr, uint8 *buf, t_mtrlnt *bc, t_mtrlnt max);