FRONTPANEL: FRONTPANEL: sim_frontpanel API release 9

- Add sim_panel_mem_deposit_instruction API
- Properly shutdown debug activities when more than one panel is active
- Properly unwind socket facilities when more than one panel is active
- More rigorously unwind things when a panel is destroyed while its
   simulator is running.
- Give explicit session request traffic priority over potentially pending
   repeat command processing.
This commit is contained in:
Mark Pizzolato 2017-12-13 05:44:43 -08:00
parent 27f9fc3c3e
commit 8cc11faf00
3 changed files with 108 additions and 25 deletions

View file

@ -1232,7 +1232,7 @@ t_stat sim_rem_con_repeat_svc (UNIT *uptr)
int line = uptr - rem_con_repeat_units; int line = uptr - rem_con_repeat_units;
REMOTE *rem = &sim_rem_consoles[line]; REMOTE *rem = &sim_rem_consoles[line];
sim_debug (DBG_REP, &sim_remote_console, "sim_rem_con_repeat_svc(line=%d) - interval=%d\n", line, rem->repeat_interval); sim_debug (DBG_REP, &sim_remote_console, "sim_rem_con_repeat_svc(line=%d) - interval=%d usecs\n", line, rem->repeat_interval);
if (rem->repeat_interval) { if (rem->repeat_interval) {
rem->repeat_pending = TRUE; rem->repeat_pending = TRUE;
sim_activate_after (uptr, rem->repeat_interval); /* reschedule */ sim_activate_after (uptr, rem->repeat_interval); /* reschedule */
@ -1382,7 +1382,9 @@ for (i=(was_active_command ? sim_rem_cmd_active_line : 0);
} }
} }
else { else {
if ((!rem->repeat_pending) || (rem->buf_ptr != 0)) { if (((!rem->repeat_pending) && (rem->act == NULL)) || /* Repeat isn't pending AND no prior commands still active */
(rem->buf_ptr != 0) || /* OR Not at beginning of line */
(tmxr_input_pending_ln (lp))) { /* OR input available to read */
c = tmxr_getc_ln (lp); c = tmxr_getc_ln (lp);
if (!(TMXR_VALID & c)) if (!(TMXR_VALID & c))
continue; continue;
@ -1461,10 +1463,12 @@ for (i=(was_active_command ? sim_rem_cmd_active_line : 0);
break; break;
} }
else { else {
if (rem->repeat_pending) { if ((rem->repeat_pending) && /* New repeat pending */
(rem->act = NULL) && /* AND no prior still active */
(!tmxr_input_pending_ln (lp))) { /* AND no session input pending */
rem->repeat_pending = FALSE; rem->repeat_pending = FALSE;
sim_rem_setact (i, rem->repeat_action); sim_rem_setact (rem-sim_rem_consoles, rem->repeat_action);
sim_rem_getact (i, rem->buf, rem->buf_size); sim_rem_getact (rem-sim_rem_consoles, rem->buf, rem->buf_size);
if (!master_session) if (!master_session)
tmxr_linemsgf (lp, "%s%s\n", sim_prompt, rem->buf); tmxr_linemsgf (lp, "%s%s\n", sim_prompt, rem->buf);
else else
@ -1566,7 +1570,10 @@ for (i=(was_active_command ? sim_rem_cmd_active_line : 0);
break; break;
} }
c = 0; c = 0;
if ((!got_command) && (rem->single_mode) && (tmxr_input_pending_ln (lp))) { if ((!got_command) && /* No Command yet */
(rem->single_mode) && /* AND single command mode */
(tmxr_input_pending_ln (lp)) && /* AND something ready to read */
(rem->act == NULL)) { /* AND no prior still active */
c = tmxr_getc_ln (lp); c = tmxr_getc_ln (lp);
c = c & ~TMXR_VALID; c = c & ~TMXR_VALID;
} }

View file

@ -889,7 +889,7 @@ if (p->sock == INVALID_SOCKET) {
} }
goto Error_Return; goto Error_Return;
} }
_panel_debug (p, DBG_XMT|DBG_RCV, "Connected to simulator on %s after %dms\n", NULL, 0, p->hostport, (int)i*100); _panel_debug (p, DBG_XMT|DBG_RCV, "Connected to simulator on %s after %dms", NULL, 0, p->hostport, (int)i*100);
pthread_mutex_init (&p->io_lock, NULL); pthread_mutex_init (&p->io_lock, NULL);
pthread_mutex_init (&p->io_send_lock, NULL); pthread_mutex_init (&p->io_send_lock, NULL);
pthread_mutex_init (&p->io_command_lock, NULL); pthread_mutex_init (&p->io_command_lock, NULL);
@ -909,7 +909,7 @@ if (1) {
pthread_create (&p->io_thread, &attr, _panel_reader, (void *)p); pthread_create (&p->io_thread, &attr, _panel_reader, (void *)p);
while (!p->io_thread_running) while (!p->io_thread_running)
pthread_cond_wait (&p->startup_done, &p->io_lock); /* Wait for thread to stabilize */ pthread_cond_wait (&p->startup_done, &p->io_lock); /* Wait for thread to stabilize */
if (p->Debug) { if ((p->Debug) && (p->parent == NULL)) {
p->debugflush_thread_running = 0; p->debugflush_thread_running = 0;
pthread_create (&p->debugflush_thread, &attr, _panel_debugflusher, (void *)p); pthread_create (&p->debugflush_thread, &attr, _panel_debugflusher, (void *)p);
while (!p->debugflush_thread_running) while (!p->debugflush_thread_running)
@ -981,6 +981,8 @@ if (1) {
sim_panel_set_error (NULL, "%s", errbuf); sim_panel_set_error (NULL, "%s", errbuf);
free (errbuf); free (errbuf);
} }
if (!simulator_panel)
sim_cleanup_sock();
return NULL; return NULL;
} }
@ -1022,13 +1024,15 @@ sim_panel_destroy (PANEL *panel)
REG *reg; REG *reg;
if (panel) { if (panel) {
_panel_debug (panel, DBG_XMT|DBG_RCV, "Closing Panel %s\n", NULL, 0, panel->device_name? panel->device_name : panel->path); _panel_debug (panel, DBG_XMT|DBG_RCV, "Closing Panel %s", NULL, 0, panel->device_name? panel->device_name : panel->path);
if (panel->devices) { if (panel->devices) {
size_t i; size_t i;
for (i=0; i<panel->device_count; i++) { for (i=0; i<panel->device_count; i++) {
if (panel->devices[i]) if (panel->devices[i]) {
sim_panel_destroy (panel->devices[i]); sim_panel_destroy (panel->devices[i]);
panel->devices[i] = NULL;
}
} }
free (panel->devices); free (panel->devices);
panel->devices = NULL; panel->devices = NULL;
@ -1042,19 +1046,26 @@ if (panel) {
sim_panel_set_display_callback_interval (panel, NULL, NULL, 0); sim_panel_set_display_callback_interval (panel, NULL, NULL, 0);
/* Next, attempt a simulator shutdown only with the master panel */ /* Next, attempt a simulator shutdown only with the master panel */
if (panel->parent == NULL) { if (panel->parent == NULL) {
if (panel->State == Run) if (panel->State == Run) {
int i;
_panel_send (panel, "\005\r", 2); _panel_send (panel, "\005\r", 2);
for (i=0; (panel->State == Run) && (i < 10); i++)
msleep(100);
if (panel->State == Run)
_panel_debug (panel, DBG_THR, "Unable to HALT running simulator for shutdown", NULL, 0);
}
_panel_send (panel, "EXIT\r", 5); _panel_send (panel, "EXIT\r", 5);
} }
/* Wait for up to 2 seconds for a graceful shutdown */ /* Wait for up to 2 seconds for a graceful shutdown */
panel->sock = INVALID_SOCKET;
for (wait_count=0; panel->io_thread_running && (wait_count<20); ++wait_count) for (wait_count=0; panel->io_thread_running && (wait_count<20); ++wait_count)
msleep (100); msleep (100);
/* Now close the socket which should stop a pending read that hasn't completed */ /* Now close the socket which should stop a pending read that hasn't completed */
panel->sock = INVALID_SOCKET;
sim_close_sock (sock); sim_close_sock (sock);
pthread_join (panel->io_thread, NULL); pthread_join (panel->io_thread, NULL);
} }
if (panel->Debug) if ((panel->Debug) && (panel->parent == NULL))
pthread_join (panel->debugflush_thread, NULL); pthread_join (panel->debugflush_thread, NULL);
pthread_mutex_destroy (&panel->io_lock); pthread_mutex_destroy (&panel->io_lock);
pthread_mutex_destroy (&panel->io_send_lock); pthread_mutex_destroy (&panel->io_send_lock);
@ -1097,6 +1108,7 @@ if (panel) {
free (panel->simulator_version); free (panel->simulator_version);
if ((panel->Debug) && (!panel->parent)) if ((panel->Debug) && (!panel->parent))
fclose (panel->Debug); fclose (panel->Debug);
if (!panel->parent)
sim_cleanup_sock (); sim_cleanup_sock ();
_panel_deregister_panel (panel); _panel_deregister_panel (panel);
free (panel); free (panel);
@ -1378,6 +1390,7 @@ panel->callback_context = context;
if (usecs_between_callbacks && (0 == panel->usecs_between_callbacks)) { /* Need to start/enable callbacks */ if (usecs_between_callbacks && (0 == panel->usecs_between_callbacks)) { /* Need to start/enable callbacks */
pthread_attr_t attr; pthread_attr_t attr;
_panel_debug (panel, DBG_THR, "Starting callback thread, Interval: %d usecs", NULL, 0, usecs_between_callbacks);
panel->usecs_between_callbacks = usecs_between_callbacks; panel->usecs_between_callbacks = usecs_between_callbacks;
pthread_cond_init (&panel->startup_done, NULL); pthread_cond_init (&panel->startup_done, NULL);
pthread_attr_init(&attr); pthread_attr_init(&attr);
@ -1389,6 +1402,7 @@ if (usecs_between_callbacks && (0 == panel->usecs_between_callbacks)) { /* Need
pthread_cond_destroy (&panel->startup_done); pthread_cond_destroy (&panel->startup_done);
} }
if ((usecs_between_callbacks == 0) && panel->usecs_between_callbacks) { /* Need to stop callbacks */ if ((usecs_between_callbacks == 0) && panel->usecs_between_callbacks) { /* Need to stop callbacks */
_panel_debug (panel, DBG_THR, "Shutting down callback thread", NULL, 0);
panel->usecs_between_callbacks = 0; /* flag disabled */ panel->usecs_between_callbacks = 0; /* flag disabled */
pthread_mutex_unlock (&panel->io_lock); /* allow access */ pthread_mutex_unlock (&panel->io_lock); /* allow access */
pthread_join (panel->callback_thread, NULL); /* synchronize with thread rundown */ pthread_join (panel->callback_thread, NULL); /* synchronize with thread rundown */
@ -1855,6 +1869,45 @@ if (_panel_sendf (panel, &cmd_stat, NULL, (panel->radix == 16) ? "DEPOSIT -H %ll
return 0; return 0;
} }
/**
sim_panel_mem_deposit_instruction
addr_size the size (in local storage) of the buffer which
contains the memory address of the data to be deposited
into the simulator
addr a pointer to the buffer containing the memory address
of the data to be deposited into the simulator
instruction a pointer to the buffer that contains the mnemonic
instruction to be deposited at the indicated address
*/
int
sim_panel_mem_deposit_instruction (PANEL *panel,
size_t addr_size,
const void *addr,
const char *instruction)
{
unsigned long long address = 0;
int cmd_stat;
if (!panel || (panel->State == Error)) {
sim_panel_set_error (NULL, "Invalid Panel");
return -1;
}
if (panel->State == Run) {
sim_panel_set_error (NULL, "Not Halted");
return -1;
}
if (little_endian)
memcpy (&address, addr, addr_size);
else
memcpy (((char *)&address) + sizeof(address)-addr_size, addr, addr_size);
if (_panel_sendf (panel, &cmd_stat, NULL, (panel->radix == 16) ? "DEPOSIT -H %llx %s" : "DEPOSIT -H %llo %s", address, instruction))
return -1;
return 0;
}
/** /**
sim_panel_set_register_value sim_panel_set_register_value
@ -2269,7 +2322,7 @@ Start_Next_Line:
} }
} }
if (p->io_waiting) { if (p->io_waiting) {
_panel_debug (p, DBG_RCV, "Receive: restarting waiting thread while exiting", NULL, 0); _panel_debug (p, DBG_THR, "Receive: restarting waiting thread while exiting", NULL, 0);
p->io_waiting = 0; p->io_waiting = 0;
pthread_cond_signal (&p->io_done); pthread_cond_signal (&p->io_done);
} }
@ -2377,10 +2430,12 @@ while ((p->sock != INVALID_SOCKET) &&
} }
pthread_mutex_unlock (&p->io_lock); pthread_mutex_unlock (&p->io_lock);
/* stop any established repeating activity in the simulator */ /* stop any established repeating activity in the simulator */
if (p->parent == NULL) /* Top level panel? */ if (p->parent == NULL) { /* Top level panel? */
_panel_debug (p, DBG_THR, "Stopping All Repeats before exiting", NULL, 0);
_panel_sendf (p, &cmd_stat, NULL, "%s", register_repeat_stop_all); _panel_sendf (p, &cmd_stat, NULL, "%s", register_repeat_stop_all);
}
else { else {
if (p->State == Run) _panel_debug (p, DBG_THR, "Stopping Repeats before exiting", NULL, 0);
_panel_sendf (p, &cmd_stat, NULL, "%s", register_repeat_stop); _panel_sendf (p, &cmd_stat, NULL, "%s", register_repeat_stop);
} }
pthread_mutex_lock (&p->io_lock); pthread_mutex_lock (&p->io_lock);

View file

@ -56,7 +56,7 @@ extern "C" {
#if !defined(__VAX) /* Unsupported platform */ #if !defined(__VAX) /* Unsupported platform */
#define SIM_FRONTPANEL_VERSION 8 #define SIM_FRONTPANEL_VERSION 9
/** /**
@ -326,6 +326,8 @@ sim_panel_break_output_clear (PANEL *panel, const char *condition);
sim_panel_gen_deposit - Deposit to register or memory sim_panel_gen_deposit - Deposit to register or memory
sim_panel_mem_examine - Examine memory location sim_panel_mem_examine - Examine memory location
sim_panel_mem_deposit - Deposit to memory location sim_panel_mem_deposit - Deposit to memory location
sim_panel_mem_deposit_instruction - Deposit instruction to memory
location
sim_panel_set_register_value - Deposit to a register or memory sim_panel_set_register_value - Deposit to a register or memory
location location
*/ */
@ -408,6 +410,25 @@ sim_panel_mem_deposit (PANEL *panel,
size_t value_size, size_t value_size,
const void *value); const void *value);
/**
sim_panel_mem_deposit_instruction
addr_size the size (in local storage) of the buffer which
contains the memory address of the data to be deposited
into the simulator
addr a pointer to the buffer containing the memory address
of the data to be deposited into the simulator
instruction a pointer to the buffer that contains the mnemonic
instruction to be deposited at the indicated address
*/
int
sim_panel_mem_deposit_instruction (PANEL *panel,
size_t addr_size,
const void *addr,
const char *instruction);
/** /**
sim_panel_set_register_value sim_panel_set_register_value