TMXR: Fix MUX transmit scheduling when buffer is empty

Also:
- Enhance SHOW MUX to support "SHOW MUX <dev>"
- Fix potential null pointer dereference with unusual ATTACH combinations
- Allow BPS factor to change without specifying an explicit speed.
This commit is contained in:
Mark Pizzolato 2018-06-23 11:30:02 -07:00
parent c73f56cc5a
commit d3da865e9b
2 changed files with 140 additions and 100 deletions

2
scp.c
View file

@ -1381,7 +1381,7 @@ static const char simh_help[] =
"+sh{ow} <unit> {arg,...} show unit parameters\n" "+sh{ow} <unit> {arg,...} show unit parameters\n"
"+sh{ow} ethernet show ethernet devices\n" "+sh{ow} ethernet show ethernet devices\n"
"+sh{ow} serial show serial devices\n" "+sh{ow} serial show serial devices\n"
"+sh{ow} multiplexer show open multiplexer devices\n" "+sh{ow} multiplexer {dev} show open multiplexer device info\n"
#if defined(USE_SIM_VIDEO) #if defined(USE_SIM_VIDEO)
"+sh{ow} video show video capabilities\n" "+sh{ow} video show video capabilities\n"
#endif #endif

View file

@ -872,6 +872,8 @@ if (mp->port) /* copy port */
sprintf (growstring(&tptr, 13 + strlen (mp->port)), "%s%s", mp->port, mp->notelnet ? ";notelnet" : ""); sprintf (growstring(&tptr, 13 + strlen (mp->port)), "%s%s", mp->port, mp->notelnet ? ";notelnet" : "");
if (mp->logfiletmpl[0]) /* logfile info */ if (mp->logfiletmpl[0]) /* logfile info */
sprintf (growstring(&tptr, 7 + strlen (mp->logfiletmpl)), ",Log=%s", mp->logfiletmpl); sprintf (growstring(&tptr, 7 + strlen (mp->logfiletmpl)), ",Log=%s", mp->logfiletmpl);
if (mp->buffered)
sprintf (growstring(&tptr, 10 + 10), ",Buffered=%d", mp->buffered);
while ((*tptr == ',') || (*tptr == ' ')) while ((*tptr == ',') || (*tptr == ' '))
memmove (tptr, tptr+1, strlen(tptr+1)+1); memmove (tptr, tptr+1, strlen(tptr+1)+1);
for (i=0; i<mp->lines; ++i) { for (i=0; i<mp->lines; ++i) {
@ -2483,21 +2485,25 @@ t_stat tmxr_set_line_speed (TMLN *lp, CONST char *speed)
UNIT *uptr; UNIT *uptr;
CONST char *cptr; CONST char *cptr;
t_stat r; t_stat r;
uint32 rxbps;
if (!speed || !*speed) if (!speed || !*speed)
return SCPE_2FARG; return SCPE_2FARG;
if (_tmln_speed_delta (speed) < 0) if (_tmln_speed_delta (speed) < 0)
return SCPE_ARG; return SCPE_ARG;
lp->rxbps = (uint32)strtotv (speed, &cptr, 10); rxbps = (uint32)strtotv (speed, &cptr, 10);
if (*cptr == '*') { if (*cptr == '*') {
uint32 bpsfactor = (uint32) get_uint (cptr+1, 10, 32, &r); uint32 bpsfactor = (uint32) get_uint (cptr+1, 10, 32, &r);
if (r != SCPE_OK) if (r != SCPE_OK)
return r; return r;
lp->bpsfactor = bpsfactor; lp->bpsfactor = bpsfactor;
if (speed == cptr) /* just changing bps factor? */
return SCPE_OK; /* Done now */
} }
lp->rxbps = rxbps; /* use supplied speed */
if ((lp->serport) && (lp->bpsfactor != 0.0)) if ((lp->serport) && (lp->bpsfactor != 0.0))
lp->bpsfactor = 1.0; lp->bpsfactor = 1.0; /* Ignore bps factor for serial ports */
lp->rxdeltausecs = (uint32)(_tmln_speed_delta (speed) / lp->bpsfactor); lp->rxdeltausecs = (uint32)(_tmln_speed_delta (speed) / lp->bpsfactor);
lp->rxnexttime = 0.0; lp->rxnexttime = 0.0;
uptr = lp->uptr; uptr = lp->uptr;
@ -3073,6 +3079,8 @@ t_stat tmxr_set_line_unit (TMXR *mp, int line, UNIT *uptr_poll)
{ {
if ((line < 0) || (line >= mp->lines)) if ((line < 0) || (line >= mp->lines))
return SCPE_ARG; return SCPE_ARG;
if (mp->ldsc[line].uptr)
mp->ldsc[line].uptr->dynflags &= ~UNIT_TM_POLL;
mp->ldsc[line].uptr = uptr_poll; mp->ldsc[line].uptr = uptr_poll;
return SCPE_OK; return SCPE_OK;
} }
@ -3104,6 +3112,8 @@ t_stat tmxr_set_line_output_unit (TMXR *mp, int line, UNIT *uptr_poll)
{ {
if ((line < 0) || (line >= mp->lines)) if ((line < 0) || (line >= mp->lines))
return SCPE_ARG; return SCPE_ARG;
if (mp->ldsc[line].o_uptr)
mp->ldsc[line].o_uptr->dynflags &= ~UNIT_TM_POLL;
mp->ldsc[line].o_uptr = uptr_poll; mp->ldsc[line].o_uptr = uptr_poll;
return SCPE_OK; return SCPE_OK;
} }
@ -3857,11 +3867,14 @@ int32 i;
if (mp->dptr == NULL) /* has device been set? */ if (mp->dptr == NULL) /* has device been set? */
mp->dptr = find_dev_from_unit (uptr); /* no, so set device now */ mp->dptr = find_dev_from_unit (uptr); /* no, so set device now */
if (mp->uptr == NULL) /* has polling unit been set? */
mp->uptr = uptr; /* save unit for polling */ mp->uptr = uptr; /* save unit for polling */
r = tmxr_open_master (mp, cptr); /* open master socket */ r = tmxr_open_master (mp, cptr); /* open master socket */
if (r != SCPE_OK) /* error? */ if (r != SCPE_OK) /* error? */
return r; return r;
uptr->filename = tmxr_mux_attach_string (uptr->filename, mp);/* save */ uptr->filename = tmxr_mux_attach_string (uptr->filename, mp);/* save */
if (uptr->filename == NULL) /* avoid dangling NULL pointer */
uptr->filename = (char *)calloc (1, 1); /* provide an emptry string */
uptr->flags = uptr->flags | UNIT_ATT; /* no more errors */ uptr->flags = uptr->flags | UNIT_ATT; /* no more errors */
uptr->tmxr = (void *)mp; uptr->tmxr = (void *)mp;
if ((mp->lines > 1) || if ((mp->lines > 1) ||
@ -3910,15 +3923,10 @@ if (tmxr_open_device_count)
return SCPE_OK; return SCPE_OK;
} }
t_stat tmxr_show_open_devices (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, CONST char* desc)
{
int i, j;
if (0 == tmxr_open_device_count) t_stat tmxr_show_open_device (FILE* st, TMXR *mp)
fprintf(st, "No Attached Multiplexer Devices\n"); {
else { int j;
for (i=0; i<tmxr_open_device_count; ++i) {
TMXR *mp = tmxr_open_devices[i];
TMLN *lp; TMLN *lp;
UNIT *o_uptr = mp->ldsc[0].o_uptr; UNIT *o_uptr = mp->ldsc[0].o_uptr;
UNIT *uptr = mp->ldsc[0].uptr; UNIT *uptr = mp->ldsc[0].uptr;
@ -4008,7 +4016,35 @@ else {
tmxr_fconns (st, lp, -1); tmxr_fconns (st, lp, -1);
tmxr_fstats (st, lp, -1); tmxr_fstats (st, lp, -1);
} }
return SCPE_OK;
} }
t_stat tmxr_show_open_devices (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, CONST char* cptr)
{
int i;
char gbuf[CBUFSIZE];
cptr = get_glyph (cptr, gbuf, 0);
if (*cptr)
return SCPE_2MARG;
if ((0 == tmxr_open_device_count) &&
(gbuf[0] == '\0'))
fprintf(st, "No Attached Multiplexer Devices\n");
else {
for (i=0; i<tmxr_open_device_count; ++i) {
TMXR *mp = tmxr_open_devices[i];
if ((gbuf[0] == '\0') ||
(0 == strcmp (gbuf, mp->dptr->name))) {
tmxr_show_open_device (st, mp);
if (gbuf[0] != '\0')
break;
}
}
if ((gbuf[0] != '\0') &&
(i == tmxr_open_device_count))
return sim_messagef (SCPE_ARG, "Multiplexer device %s not found or attached\n", gbuf);
} }
return SCPE_OK; return SCPE_OK;
} }
@ -4146,13 +4182,17 @@ for (i=0; i<mp->lines; i++) {
if ((lp->conn || lp->txbfd) && /* Connected (or buffered)? */ if ((lp->conn || lp->txbfd) && /* Connected (or buffered)? */
(uptr == lp->o_uptr) && /* output completion unit? */ (uptr == lp->o_uptr) && /* output completion unit? */
(lp->txbps)) { /* while rate limiting */ (lp->txbps)) { /* while rate limiting */
if ((tmxr_tqln(lp)) && /* pending output data? */ if ((tmxr_tqln(lp)) && /* pending output data */
(lp->txnexttime < sim_gtime_now)) (lp->txnexttime < sim_gtime_now))/* that can be transmitted now? */
tmxr_send_buffered_data (lp);/* flush it */ tmxr_send_buffered_data (lp);/* flush it */
if (tmxr_tqln(lp) == 0) /* no pending output data */
due = interval; /* No rush */
else {
if (lp->txnexttime > sim_gtime_now) if (lp->txnexttime > sim_gtime_now)
due = (int32)(lp->txnexttime - sim_gtime_now); due = (int32)(lp->txnexttime - sim_gtime_now);
else else
due = sim_processing_event ? 1 : 0; /* avoid potential infinite loop if called from service routine */ due = sim_processing_event ? 1 : 0; /* avoid potential infinite loop if called from service routine */
}
sooner = MIN(sooner, due); sooner = MIN(sooner, due);
} }
} }