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:
parent
c73f56cc5a
commit
d3da865e9b
2 changed files with 140 additions and 100 deletions
2
scp.c
2
scp.c
|
@ -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
|
||||||
|
|
114
sim_tmxr.c
114
sim_tmxr.c
|
@ -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 */
|
||||||
|
|
||||||
mp->uptr = uptr; /* save unit for polling */
|
if (mp->uptr == NULL) /* has polling unit been set? */
|
||||||
|
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,55 +3923,50 @@ 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)
|
|
||||||
|
t_stat tmxr_show_open_device (FILE* st, TMXR *mp)
|
||||||
{
|
{
|
||||||
int i, j;
|
int j;
|
||||||
|
TMLN *lp;
|
||||||
|
UNIT *o_uptr = mp->ldsc[0].o_uptr;
|
||||||
|
UNIT *uptr = mp->ldsc[0].uptr;
|
||||||
|
char *attach;
|
||||||
|
|
||||||
if (0 == tmxr_open_device_count)
|
fprintf(st, "Multiplexer device: %s", (mp->dptr ? sim_dname (mp->dptr) : ""));
|
||||||
fprintf(st, "No Attached Multiplexer Devices\n");
|
if (mp->lines > 1) {
|
||||||
else {
|
|
||||||
for (i=0; i<tmxr_open_device_count; ++i) {
|
|
||||||
TMXR *mp = tmxr_open_devices[i];
|
|
||||||
TMLN *lp;
|
|
||||||
UNIT *o_uptr = mp->ldsc[0].o_uptr;
|
|
||||||
UNIT *uptr = mp->ldsc[0].uptr;
|
|
||||||
char *attach;
|
|
||||||
|
|
||||||
fprintf(st, "Multiplexer device: %s", (mp->dptr ? sim_dname (mp->dptr) : ""));
|
|
||||||
if (mp->lines > 1) {
|
|
||||||
fprintf(st, ", ");
|
fprintf(st, ", ");
|
||||||
tmxr_show_lines(st, NULL, 0, mp);
|
tmxr_show_lines(st, NULL, 0, mp);
|
||||||
}
|
}
|
||||||
if (mp->packet)
|
if (mp->packet)
|
||||||
fprintf(st, ", Packet");
|
fprintf(st, ", Packet");
|
||||||
if (mp->datagram)
|
if (mp->datagram)
|
||||||
fprintf(st, ", UDP");
|
fprintf(st, ", UDP");
|
||||||
if (mp->notelnet)
|
if (mp->notelnet)
|
||||||
fprintf(st, ", Telnet=disabled");
|
fprintf(st, ", Telnet=disabled");
|
||||||
if (mp->modem_control)
|
if (mp->modem_control)
|
||||||
fprintf(st, ", ModemControl=enabled");
|
fprintf(st, ", ModemControl=enabled");
|
||||||
if (mp->buffered)
|
if (mp->buffered)
|
||||||
fprintf(st, ", Buffered=%d", mp->buffered);
|
fprintf(st, ", Buffered=%d", mp->buffered);
|
||||||
for (j = 1; j < mp->lines; j++)
|
for (j = 1; j < mp->lines; j++)
|
||||||
if (o_uptr != mp->ldsc[j].o_uptr)
|
if (o_uptr != mp->ldsc[j].o_uptr)
|
||||||
break;
|
break;
|
||||||
if (j == mp->lines)
|
if (j == mp->lines)
|
||||||
fprintf(st, ", Output Unit: %s", sim_uname (o_uptr));
|
fprintf(st, ", Output Unit: %s", sim_uname (o_uptr));
|
||||||
for (j = 1; j < mp->lines; j++)
|
for (j = 1; j < mp->lines; j++)
|
||||||
if (uptr != mp->ldsc[j].uptr)
|
if (uptr != mp->ldsc[j].uptr)
|
||||||
break;
|
break;
|
||||||
if (j == mp->lines) {
|
if (j == mp->lines) {
|
||||||
fprintf(st, ",\n Input Polling Unit: %s", sim_uname (uptr));
|
fprintf(st, ",\n Input Polling Unit: %s", sim_uname (uptr));
|
||||||
if (uptr != mp->uptr)
|
if (uptr != mp->uptr)
|
||||||
fprintf(st, ", Connection Polling Unit: %s", sim_uname (mp->uptr));
|
fprintf(st, ", Connection Polling Unit: %s", sim_uname (mp->uptr));
|
||||||
}
|
}
|
||||||
attach = tmxr_mux_attach_string (NULL, mp);
|
attach = tmxr_mux_attach_string (NULL, mp);
|
||||||
if (attach)
|
if (attach)
|
||||||
fprintf(st, ",\n attached to %s, ", attach);
|
fprintf(st, ",\n attached to %s, ", attach);
|
||||||
free (attach);
|
free (attach);
|
||||||
tmxr_show_summ(st, NULL, 0, mp);
|
tmxr_show_summ(st, NULL, 0, mp);
|
||||||
fprintf(st, ", sessions=%d", mp->sessions);
|
fprintf(st, ", sessions=%d", mp->sessions);
|
||||||
if (mp->lines == 1) {
|
if (mp->lines == 1) {
|
||||||
if (mp->ldsc->rxbps) {
|
if (mp->ldsc->rxbps) {
|
||||||
fprintf(st, ", Speed=%d", mp->ldsc->rxbps);
|
fprintf(st, ", Speed=%d", mp->ldsc->rxbps);
|
||||||
if (mp->ldsc->bpsfactor != 1.0)
|
if (mp->ldsc->bpsfactor != 1.0)
|
||||||
|
@ -3966,11 +3974,11 @@ else {
|
||||||
fprintf(st, " bps");
|
fprintf(st, " bps");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fprintf(st, "\n");
|
fprintf(st, "\n");
|
||||||
if (mp->ring_start_time) {
|
if (mp->ring_start_time) {
|
||||||
fprintf (st, " incoming Connection from: %s ringing for %d milliseconds\n", mp->ring_ipad, sim_os_msec () - mp->ring_start_time);
|
fprintf (st, " incoming Connection from: %s ringing for %d milliseconds\n", mp->ring_ipad, sim_os_msec () - mp->ring_start_time);
|
||||||
}
|
}
|
||||||
for (j = 0; j < mp->lines; j++) {
|
for (j = 0; j < mp->lines; j++) {
|
||||||
lp = mp->ldsc + j;
|
lp = mp->ldsc + j;
|
||||||
if (mp->lines > 1) {
|
if (mp->lines > 1) {
|
||||||
if (lp->dptr && (mp->dptr != lp->dptr))
|
if (lp->dptr && (mp->dptr != lp->dptr))
|
||||||
|
@ -4008,8 +4016,36 @@ 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue