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:
parent
27f9fc3c3e
commit
8cc11faf00
3 changed files with 108 additions and 25 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Reference in a new issue