Fixes for stable operation with SIM_ASYNCH_CLOCKS defined
This commit is contained in:
parent
9faef6ea89
commit
6cf54e8341
6 changed files with 167 additions and 48 deletions
|
@ -1580,8 +1580,10 @@ if ((tmr_inc[tmr] == TMR_INC) && (tmr_time > clk_time)) {
|
||||||
|
|
||||||
tmr_inc[tmr] = (uint32) (((double) clk_time * TMR_INC) / tmr_poll);
|
tmr_inc[tmr] = (uint32) (((double) clk_time * TMR_INC) / tmr_poll);
|
||||||
tmr_time = clk_time;
|
tmr_time = clk_time;
|
||||||
|
sim_clock_coschedule (&sysd_unit[tmr], tmr_time);
|
||||||
}
|
}
|
||||||
sim_activate (&sysd_unit[tmr], tmr_time);
|
else
|
||||||
|
sim_activate (&sysd_unit[tmr], tmr_time);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
28
scp.c
28
scp.c
|
@ -2934,8 +2934,8 @@ else {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (sim_clock_cosched_queue != QUEUE_LIST_END) {
|
if (sim_clock_cosched_queue != QUEUE_LIST_END) {
|
||||||
fprintf (st, "%s clock co-schedule event queue status, time = %.0f\n",
|
fprintf (st, "%s clock (%s) co-schedule event queue status, time = %.0f\n",
|
||||||
sim_name, sim_time);
|
sim_name, sim_uname(sim_clock_unit), sim_time);
|
||||||
for (uptr = sim_clock_cosched_queue; uptr != QUEUE_LIST_END; uptr = uptr->next) {
|
for (uptr = sim_clock_cosched_queue; uptr != QUEUE_LIST_END; uptr = uptr->next) {
|
||||||
if ((dptr = find_dev_from_unit (uptr)) != NULL) {
|
if ((dptr = find_dev_from_unit (uptr)) != NULL) {
|
||||||
fprintf (st, " %s", sim_dname (dptr));
|
fprintf (st, " %s", sim_dname (dptr));
|
||||||
|
@ -3934,6 +3934,8 @@ char *sim_uname (UNIT *uptr)
|
||||||
DEVICE *d = find_dev_from_unit(uptr);
|
DEVICE *d = find_dev_from_unit(uptr);
|
||||||
static AIO_TLS char uname[CBUFSIZE];
|
static AIO_TLS char uname[CBUFSIZE];
|
||||||
|
|
||||||
|
if (!d)
|
||||||
|
return "";
|
||||||
if (d->numunits == 1)
|
if (d->numunits == 1)
|
||||||
return sim_dname (d);
|
return sim_dname (d);
|
||||||
sprintf (uname, "%s%d", sim_dname (d), (int)(uptr-d->units));
|
sprintf (uname, "%s%d", sim_dname (d), (int)(uptr-d->units));
|
||||||
|
@ -6336,28 +6338,39 @@ AIO_CANCEL(uptr);
|
||||||
AIO_UPDATE_QUEUE;
|
AIO_UPDATE_QUEUE;
|
||||||
if (sim_clock_queue == QUEUE_LIST_END)
|
if (sim_clock_queue == QUEUE_LIST_END)
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
|
sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Event for %s\n", sim_uname(uptr));
|
||||||
UPDATE_SIM_TIME; /* update sim time */
|
UPDATE_SIM_TIME; /* update sim time */
|
||||||
if (!sim_is_active (uptr))
|
if (!sim_is_active (uptr))
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
nptr = QUEUE_LIST_END;
|
nptr = QUEUE_LIST_END;
|
||||||
|
|
||||||
if (sim_clock_queue == uptr)
|
if (sim_clock_queue == uptr) {
|
||||||
nptr = sim_clock_queue = uptr->next;
|
nptr = sim_clock_queue = uptr->next;
|
||||||
|
uptr->next = NULL; /* hygiene */
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
|
for (cptr = sim_clock_queue; cptr != QUEUE_LIST_END; cptr = cptr->next) {
|
||||||
if (cptr->next == uptr) {
|
if (cptr->next == uptr) {
|
||||||
nptr = cptr->next = uptr->next;
|
nptr = cptr->next = uptr->next;
|
||||||
|
uptr->next = NULL; /* hygiene */
|
||||||
break; /* end queue scan */
|
break; /* end queue scan */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nptr != QUEUE_LIST_END)
|
if (nptr != QUEUE_LIST_END)
|
||||||
nptr->time = nptr->time + uptr->time;
|
nptr->time += (uptr->next) ? 0 : uptr->time;
|
||||||
uptr->next = NULL; /* hygiene */
|
if (!uptr->next)
|
||||||
uptr->time = 0;
|
uptr->time = 0;
|
||||||
if (sim_clock_queue != QUEUE_LIST_END)
|
if (sim_clock_queue != QUEUE_LIST_END)
|
||||||
sim_interval = sim_clock_queue->time;
|
sim_interval = sim_clock_queue->time;
|
||||||
else sim_interval = noqueue_time = NOQUEUE_WAIT;
|
else sim_interval = noqueue_time = NOQUEUE_WAIT;
|
||||||
|
if (sim_is_active(uptr)) {
|
||||||
|
if (sim_deb) {
|
||||||
|
sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Cancel failed for %s\n", sim_uname(uptr));
|
||||||
|
fclose(sim_deb);
|
||||||
|
}
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6413,7 +6426,8 @@ return 0;
|
||||||
|
|
||||||
double sim_gtime (void)
|
double sim_gtime (void)
|
||||||
{
|
{
|
||||||
UPDATE_SIM_TIME;
|
if (AIO_MAIN_THREAD)
|
||||||
|
UPDATE_SIM_TIME;
|
||||||
return sim_time;
|
return sim_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -541,6 +541,7 @@ for (i=(was_stepping ? sim_rem_step_line : 0);
|
||||||
c = c & ~TMXR_VALID;
|
c = c & ~TMXR_VALID;
|
||||||
if (c != sim_int_char)
|
if (c != sim_int_char)
|
||||||
continue; /* ^E (the interrupt character) must start console interaction */
|
continue; /* ^E (the interrupt character) must start console interaction */
|
||||||
|
sim_stop_timer_services ();
|
||||||
for (j=0; j < sim_rem_con_tmxr.lines; j++) {
|
for (j=0; j < sim_rem_con_tmxr.lines; j++) {
|
||||||
lp = &sim_rem_con_tmxr.ldsc[j];
|
lp = &sim_rem_con_tmxr.ldsc[j];
|
||||||
if ((i == j) || (!lp->conn))
|
if ((i == j) || (!lp->conn))
|
||||||
|
@ -727,6 +728,7 @@ for (i=(was_stepping ? sim_rem_step_line : 0);
|
||||||
tmxr_linemsg (lp, "Simulator Running...");
|
tmxr_linemsg (lp, "Simulator Running...");
|
||||||
tmxr_send_buffered_data (lp);
|
tmxr_send_buffered_data (lp);
|
||||||
}
|
}
|
||||||
|
sim_start_timer_services ();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (cmdp && (cmdp->action == &x_step_cmd)) {
|
if (cmdp && (cmdp->action == &x_step_cmd)) {
|
||||||
|
|
140
sim_defs.h
140
sim_defs.h
|
@ -749,7 +749,24 @@ extern int32 sim_asynch_inst_latency;
|
||||||
/* It is primarily used only used in debugging messages */
|
/* It is primarily used only used in debugging messages */
|
||||||
#define AIO_TLS
|
#define AIO_TLS
|
||||||
#endif
|
#endif
|
||||||
|
#define AIO_QUEUE_CHECK(que, lock) \
|
||||||
|
if (1) { \
|
||||||
|
UNIT *_cptr; \
|
||||||
|
if (lock) \
|
||||||
|
pthread_mutex_lock (lock); \
|
||||||
|
for (_cptr = que; \
|
||||||
|
(_cptr != QUEUE_LIST_END); \
|
||||||
|
_cptr = _cptr->next) \
|
||||||
|
if (!_cptr->next) { \
|
||||||
|
if (sim_deb) { \
|
||||||
|
sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Queue Corruption detected\n");\
|
||||||
|
fclose(sim_deb); \
|
||||||
|
} \
|
||||||
|
abort(); \
|
||||||
|
} \
|
||||||
|
if (lock) \
|
||||||
|
pthread_mutex_unlock (lock); \
|
||||||
|
} else (void)0
|
||||||
#define AIO_MAIN_THREAD (pthread_equal ( pthread_self(), sim_asynch_main_threadid ))
|
#define AIO_MAIN_THREAD (pthread_equal ( pthread_self(), sim_asynch_main_threadid ))
|
||||||
#define AIO_LOCK \
|
#define AIO_LOCK \
|
||||||
pthread_mutex_lock(&sim_asynch_lock)
|
pthread_mutex_lock(&sim_asynch_lock)
|
||||||
|
@ -768,14 +785,16 @@ extern int32 sim_asynch_inst_latency;
|
||||||
if ((uptr)->a_cancel) \
|
if ((uptr)->a_cancel) \
|
||||||
(uptr)->a_cancel (uptr); \
|
(uptr)->a_cancel (uptr); \
|
||||||
else { \
|
else { \
|
||||||
if (AIO_IS_ACTIVE (uptr)) { \
|
if ((uptr)->next) { \
|
||||||
UNIT *cptr, *nptr; \
|
UNIT *cptr; \
|
||||||
AIO_UPDATE_QUEUE; \
|
AIO_UPDATE_QUEUE; \
|
||||||
pthread_mutex_lock (&sim_timer_lock); \
|
pthread_mutex_lock (&sim_timer_lock); \
|
||||||
nptr = QUEUE_LIST_END; \
|
|
||||||
if ((uptr) == sim_wallclock_queue) { \
|
if ((uptr) == sim_wallclock_queue) { \
|
||||||
sim_wallclock_queue = (uptr)->next; \
|
sim_wallclock_queue = (uptr)->next; \
|
||||||
(uptr)->next = NULL; \
|
(uptr)->next = NULL; \
|
||||||
|
sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Timer Event for %s\n", sim_uname(uptr));\
|
||||||
|
sim_timer_event_canceled = TRUE; \
|
||||||
|
pthread_cond_signal (&sim_timer_wake); \
|
||||||
} \
|
} \
|
||||||
else \
|
else \
|
||||||
for (cptr = sim_wallclock_queue; \
|
for (cptr = sim_wallclock_queue; \
|
||||||
|
@ -783,18 +802,13 @@ extern int32 sim_asynch_inst_latency;
|
||||||
cptr = cptr->next) \
|
cptr = cptr->next) \
|
||||||
if (cptr->next == (uptr)) { \
|
if (cptr->next == (uptr)) { \
|
||||||
cptr->next = (uptr)->next; \
|
cptr->next = (uptr)->next; \
|
||||||
nptr = cptr; \
|
|
||||||
(uptr)->next = NULL; \
|
(uptr)->next = NULL; \
|
||||||
|
sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Timer Event for %s\n", sim_uname(uptr));\
|
||||||
break; \
|
break; \
|
||||||
} \
|
} \
|
||||||
if (nptr == QUEUE_LIST_END) { \
|
|
||||||
sim_timer_event_canceled = TRUE; \
|
|
||||||
pthread_cond_signal (&sim_timer_wake); \
|
|
||||||
} \
|
|
||||||
if ((uptr)->next == NULL) \
|
if ((uptr)->next == NULL) \
|
||||||
(uptr)->a_due_time = (uptr)->a_usec_delay = 0; \
|
(uptr)->a_due_time = (uptr)->a_usec_delay = 0; \
|
||||||
else { \
|
else { \
|
||||||
nptr = QUEUE_LIST_END; \
|
|
||||||
if ((uptr) == sim_clock_cosched_queue) { \
|
if ((uptr) == sim_clock_cosched_queue) { \
|
||||||
sim_clock_cosched_queue = (uptr)->next; \
|
sim_clock_cosched_queue = (uptr)->next; \
|
||||||
(uptr)->next = NULL; \
|
(uptr)->next = NULL; \
|
||||||
|
@ -805,10 +819,18 @@ extern int32 sim_asynch_inst_latency;
|
||||||
cptr = cptr->next) \
|
cptr = cptr->next) \
|
||||||
if (cptr->next == (uptr)) { \
|
if (cptr->next == (uptr)) { \
|
||||||
cptr->next = (uptr)->next; \
|
cptr->next = (uptr)->next; \
|
||||||
nptr = cptr; \
|
|
||||||
(uptr)->next = NULL; \
|
(uptr)->next = NULL; \
|
||||||
break; \
|
break; \
|
||||||
} \
|
} \
|
||||||
|
if ((uptr)->next == NULL) { \
|
||||||
|
sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Clock Coscheduling Event for %s\n", sim_uname(uptr));\
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
while (sim_timer_event_canceled) { \
|
||||||
|
pthread_mutex_unlock (&sim_timer_lock); \
|
||||||
|
sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Waiting for Timer Event cancelation for %s\n", sim_uname(uptr));\
|
||||||
|
sim_os_ms_sleep (0); \
|
||||||
|
pthread_mutex_lock (&sim_timer_lock); \
|
||||||
} \
|
} \
|
||||||
pthread_mutex_unlock (&sim_timer_lock); \
|
pthread_mutex_unlock (&sim_timer_lock); \
|
||||||
} \
|
} \
|
||||||
|
@ -838,14 +860,16 @@ extern int32 sim_asynch_inst_latency;
|
||||||
sim_tmxr_poll_count -= (uptr)->a_poll_waiter_count; \
|
sim_tmxr_poll_count -= (uptr)->a_poll_waiter_count; \
|
||||||
(uptr)->a_poll_waiter_count = 0; \
|
(uptr)->a_poll_waiter_count = 0; \
|
||||||
} \
|
} \
|
||||||
if (AIO_IS_ACTIVE (uptr)) { \
|
if ((uptr)->next) { \
|
||||||
UNIT *cptr, *nptr; \
|
UNIT *cptr; \
|
||||||
AIO_UPDATE_QUEUE; \
|
AIO_UPDATE_QUEUE; \
|
||||||
pthread_mutex_lock (&sim_timer_lock); \
|
pthread_mutex_lock (&sim_timer_lock); \
|
||||||
nptr = QUEUE_LIST_END; \
|
|
||||||
if ((uptr) == sim_wallclock_queue) { \
|
if ((uptr) == sim_wallclock_queue) { \
|
||||||
sim_wallclock_queue = (uptr)->next; \
|
sim_wallclock_queue = (uptr)->next; \
|
||||||
(uptr)->next = NULL; \
|
(uptr)->next = NULL; \
|
||||||
|
sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Timer Event for %s\n", sim_uname(uptr));\
|
||||||
|
sim_timer_event_canceled = TRUE; \
|
||||||
|
pthread_cond_signal (&sim_timer_wake); \
|
||||||
} \
|
} \
|
||||||
else \
|
else \
|
||||||
for (cptr = sim_wallclock_queue; \
|
for (cptr = sim_wallclock_queue; \
|
||||||
|
@ -853,18 +877,13 @@ extern int32 sim_asynch_inst_latency;
|
||||||
cptr = cptr->next) \
|
cptr = cptr->next) \
|
||||||
if (cptr->next == (uptr)) { \
|
if (cptr->next == (uptr)) { \
|
||||||
cptr->next = (uptr)->next; \
|
cptr->next = (uptr)->next; \
|
||||||
nptr = cptr; \
|
|
||||||
(uptr)->next = NULL; \
|
(uptr)->next = NULL; \
|
||||||
|
sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Timer Event for %s\n", sim_uname(uptr));\
|
||||||
break; \
|
break; \
|
||||||
} \
|
} \
|
||||||
if (nptr == QUEUE_LIST_END) { \
|
|
||||||
sim_timer_event_canceled = TRUE; \
|
|
||||||
pthread_cond_signal (&sim_timer_wake); \
|
|
||||||
} \
|
|
||||||
if ((uptr)->next == NULL) \
|
if ((uptr)->next == NULL) \
|
||||||
(uptr)->a_due_time = (uptr)->a_usec_delay = 0; \
|
(uptr)->a_due_time = (uptr)->a_usec_delay = 0; \
|
||||||
else { \
|
else { \
|
||||||
nptr = QUEUE_LIST_END; \
|
|
||||||
if ((uptr) == sim_clock_cosched_queue) { \
|
if ((uptr) == sim_clock_cosched_queue) { \
|
||||||
sim_clock_cosched_queue = (uptr)->next; \
|
sim_clock_cosched_queue = (uptr)->next; \
|
||||||
(uptr)->next = NULL; \
|
(uptr)->next = NULL; \
|
||||||
|
@ -875,10 +894,18 @@ extern int32 sim_asynch_inst_latency;
|
||||||
cptr = cptr->next) \
|
cptr = cptr->next) \
|
||||||
if (cptr->next == (uptr)) { \
|
if (cptr->next == (uptr)) { \
|
||||||
cptr->next = (uptr)->next; \
|
cptr->next = (uptr)->next; \
|
||||||
nptr = cptr; \
|
|
||||||
(uptr)->next = NULL; \
|
(uptr)->next = NULL; \
|
||||||
break; \
|
break; \
|
||||||
} \
|
} \
|
||||||
|
if ((uptr)->next == NULL) { \
|
||||||
|
sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Canceling Clock Coscheduling Event for %s\n", sim_uname(uptr));\
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
while (sim_timer_event_canceled) { \
|
||||||
|
pthread_mutex_unlock (&sim_timer_lock); \
|
||||||
|
sim_debug (SIM_DBG_EVENT, sim_dflt_dev, "Waiting for Timer Event cancelation for %s\n", sim_uname(uptr));\
|
||||||
|
sim_os_ms_sleep (0); \
|
||||||
|
pthread_mutex_lock (&sim_timer_lock); \
|
||||||
} \
|
} \
|
||||||
pthread_mutex_unlock (&sim_timer_lock); \
|
pthread_mutex_unlock (&sim_timer_lock); \
|
||||||
} \
|
} \
|
||||||
|
@ -988,8 +1015,8 @@ extern int32 sim_asynch_inst_latency;
|
||||||
do \
|
do \
|
||||||
q = AIO_QUEUE_VAL; \
|
q = AIO_QUEUE_VAL; \
|
||||||
while (q != AIO_QUEUE_SET(QUEUE_LIST_END, q)); \
|
while (q != AIO_QUEUE_SET(QUEUE_LIST_END, q)); \
|
||||||
sim_debug (SIM_DBG_AIO_QUEUE, sim_dflt_dev, "Found Asynch event for %s after %d instructions\n", sim_uname(q), q->a_event_time);\
|
|
||||||
while (q != QUEUE_LIST_END) { /* List !Empty */ \
|
while (q != QUEUE_LIST_END) { /* List !Empty */ \
|
||||||
|
sim_debug (SIM_DBG_AIO_QUEUE, sim_dflt_dev, "Migrating Asynch event for %s after %d instructions\n", sim_uname(q), q->a_event_time);\
|
||||||
uptr = q; \
|
uptr = q; \
|
||||||
q = q->a_next; \
|
q = q->a_next; \
|
||||||
uptr->a_next = NULL; /* hygiene */ \
|
uptr->a_next = NULL; /* hygiene */ \
|
||||||
|
@ -1014,8 +1041,8 @@ extern int32 sim_asynch_inst_latency;
|
||||||
} else { \
|
} else { \
|
||||||
UNIT *q, *qe; \
|
UNIT *q, *qe; \
|
||||||
ouptr->a_event_time = event_time; \
|
ouptr->a_event_time = event_time; \
|
||||||
uptr->a_activate_call = caller; \
|
ouptr->a_activate_call = caller; \
|
||||||
uptr->a_next = QUEUE_LIST_END; /* Mark as on list */ \
|
ouptr->a_next = QUEUE_LIST_END; /* Mark as on list */ \
|
||||||
do { \
|
do { \
|
||||||
do \
|
do \
|
||||||
q = AIO_QUEUE_VAL; \
|
q = AIO_QUEUE_VAL; \
|
||||||
|
@ -1035,6 +1062,39 @@ extern int32 sim_asynch_inst_latency;
|
||||||
} \
|
} \
|
||||||
return SCPE_OK; \
|
return SCPE_OK; \
|
||||||
} else (void)0
|
} else (void)0
|
||||||
|
#define AIO_ACTIVATE_LIST(caller, list, event_time) \
|
||||||
|
if (1) { \
|
||||||
|
UNIT *ouptr, *q, *qe; \
|
||||||
|
sim_debug (SIM_DBG_AIO_QUEUE, sim_dflt_dev, "Queueing Asynch events for %s after %d instructions\n", sim_uname(list), event_time);\
|
||||||
|
for (qe=(list); qe->next != QUEUE_LIST_END;) { \
|
||||||
|
qe->a_event_time = event_time; \
|
||||||
|
qe->a_activate_call = caller; \
|
||||||
|
qe->a_next = qe->next; \
|
||||||
|
qe->next = NULL; \
|
||||||
|
qe = qe->a_next; \
|
||||||
|
} \
|
||||||
|
qe->a_event_time = event_time; \
|
||||||
|
qe->a_activate_call = caller; \
|
||||||
|
qe->a_next = QUEUE_LIST_END; \
|
||||||
|
qe->next = NULL; \
|
||||||
|
ouptr = (list); \
|
||||||
|
do { \
|
||||||
|
do \
|
||||||
|
q = AIO_QUEUE_VAL; \
|
||||||
|
while (q != AIO_QUEUE_SET(QUEUE_LIST_END, q));/* Grab current list */ \
|
||||||
|
for (qe = ouptr; qe->a_next != QUEUE_LIST_END; qe = qe->a_next); \
|
||||||
|
qe->a_next = q; /* append current list */ \
|
||||||
|
do \
|
||||||
|
q = AIO_QUEUE_VAL; \
|
||||||
|
while (q != AIO_QUEUE_SET(ouptr, q)); \
|
||||||
|
ouptr = q; \
|
||||||
|
} while (ouptr != QUEUE_LIST_END); \
|
||||||
|
sim_asynch_check = 0; /* try to force check */ \
|
||||||
|
if (sim_idle_wait) { \
|
||||||
|
sim_debug (TIMER_DBG_IDLE, &sim_timer_dev, "waking due to event on %s after %d instructions\n", sim_uname(ouptr), event_time);\
|
||||||
|
pthread_cond_signal (&sim_asynch_wake); \
|
||||||
|
} \
|
||||||
|
} else (void)0
|
||||||
#else /* !USE_AIO_INTRINSICS */
|
#else /* !USE_AIO_INTRINSICS */
|
||||||
/* This approach uses a pthread mutex to manage access to the link list */
|
/* This approach uses a pthread mutex to manage access to the link list */
|
||||||
/* head sim_asynch_queue. It will always work, but may be slower than the */
|
/* head sim_asynch_queue. It will always work, but may be slower than the */
|
||||||
|
@ -1098,8 +1158,8 @@ extern int32 sim_asynch_inst_latency;
|
||||||
} else (void)0
|
} else (void)0
|
||||||
#define AIO_ACTIVATE(caller, uptr, event_time) \
|
#define AIO_ACTIVATE(caller, uptr, event_time) \
|
||||||
if (!pthread_equal ( pthread_self(), sim_asynch_main_threadid )) { \
|
if (!pthread_equal ( pthread_self(), sim_asynch_main_threadid )) { \
|
||||||
sim_debug (SIM_DBG_AIO_QUEUE, sim_dflt_dev, "queueing asynch event for %s after %d instructions\n", sim_uname(uptr), event_time);\
|
sim_debug (SIM_DBG_AIO_QUEUE, sim_dflt_dev, "Queueing Asynch event for %s after %d instructions\n", sim_uname(uptr), event_time);\
|
||||||
AIO_UNLOCK; \
|
AIO_LOCK; \
|
||||||
if (uptr->a_next) { /* already queued? */ \
|
if (uptr->a_next) { /* already queued? */ \
|
||||||
uptr->a_activate_call = sim_activate_abs; \
|
uptr->a_activate_call = sim_activate_abs; \
|
||||||
} else { \
|
} else { \
|
||||||
|
@ -1108,12 +1168,38 @@ extern int32 sim_asynch_inst_latency;
|
||||||
uptr->a_activate_call = caller; \
|
uptr->a_activate_call = caller; \
|
||||||
sim_asynch_queue = uptr; \
|
sim_asynch_queue = uptr; \
|
||||||
} \
|
} \
|
||||||
if (sim_idle_wait) \
|
if (sim_idle_wait) { \
|
||||||
|
sim_debug (TIMER_DBG_IDLE, &sim_timer_dev, "waking due to event on %s after %d instructions\n", sim_uname(uptr), event_time);\
|
||||||
pthread_cond_signal (&sim_asynch_wake); \
|
pthread_cond_signal (&sim_asynch_wake); \
|
||||||
|
} \
|
||||||
AIO_UNLOCK; \
|
AIO_UNLOCK; \
|
||||||
sim_asynch_check = 0; \
|
sim_asynch_check = 0; \
|
||||||
return SCPE_OK; \
|
return SCPE_OK; \
|
||||||
} else (void)0
|
} else (void)0
|
||||||
|
#define AIO_ACTIVATE_LIST(caller, list, event_time) \
|
||||||
|
if (1) { \
|
||||||
|
UNIT *qe; \
|
||||||
|
sim_debug (SIM_DBG_AIO_QUEUE, sim_dflt_dev, "Queueing Asynch events for %s after %d instructions\n", sim_uname(list), event_time);\
|
||||||
|
for (qe=list; qe->next != QUEUE_LIST_END;) { \
|
||||||
|
qe->a_event_time = event_time; \
|
||||||
|
qe->a_activate_call = caller; \
|
||||||
|
qe->a_next = qe->next; \
|
||||||
|
qe->next = NULL; \
|
||||||
|
qe = qe->a_next; \
|
||||||
|
} \
|
||||||
|
qe->a_event_time = event_time; \
|
||||||
|
qe->a_activate_call = caller; \
|
||||||
|
qe->next = NULL; \
|
||||||
|
AIO_LOCK; \
|
||||||
|
qe->a_next = sim_asynch_queue; \
|
||||||
|
sim_asynch_queue = list; \
|
||||||
|
sim_asynch_check = 0; /* try to force check */ \
|
||||||
|
if (sim_idle_wait) { \
|
||||||
|
sim_debug (TIMER_DBG_IDLE, &sim_timer_dev, "waking due to event on %s after %d instructions\n", sim_uname(list), event_time);\
|
||||||
|
pthread_cond_signal (&sim_asynch_wake); \
|
||||||
|
} \
|
||||||
|
AIO_UNLOCK; \
|
||||||
|
} else (void)0
|
||||||
#endif /* USE_AIO_INTRINSICS */
|
#endif /* USE_AIO_INTRINSICS */
|
||||||
#define AIO_VALIDATE if (!pthread_equal ( pthread_self(), sim_asynch_main_threadid )) abort()
|
#define AIO_VALIDATE if (!pthread_equal ( pthread_self(), sim_asynch_main_threadid )) abort()
|
||||||
#define AIO_CHECK_EVENT \
|
#define AIO_CHECK_EVENT \
|
||||||
|
|
38
sim_timer.c
38
sim_timer.c
|
@ -101,7 +101,7 @@ static uint32 sim_throt_val = 0;
|
||||||
static uint32 sim_throt_state = 0;
|
static uint32 sim_throt_state = 0;
|
||||||
static uint32 sim_throt_sleep_time = 0;
|
static uint32 sim_throt_sleep_time = 0;
|
||||||
static int32 sim_throt_wait = 0;
|
static int32 sim_throt_wait = 0;
|
||||||
static UNIT *sim_clock_unit = NULL;
|
UNIT *sim_clock_unit = NULL;
|
||||||
t_bool sim_asynch_timer =
|
t_bool sim_asynch_timer =
|
||||||
#if defined (SIM_ASYNCH_CLOCKS)
|
#if defined (SIM_ASYNCH_CLOCKS)
|
||||||
TRUE;
|
TRUE;
|
||||||
|
@ -1216,7 +1216,7 @@ while (sim_asynch_enabled && sim_asynch_timer && sim_is_running) {
|
||||||
if (sim_wallclock_queue == QUEUE_LIST_END)
|
if (sim_wallclock_queue == QUEUE_LIST_END)
|
||||||
sim_debug (DBG_TIM, &sim_timer_dev, "_timer_thread() - waiting forever\n");
|
sim_debug (DBG_TIM, &sim_timer_dev, "_timer_thread() - waiting forever\n");
|
||||||
else
|
else
|
||||||
sim_debug (DBG_TIM, &sim_timer_dev, "_timer_thread() - waiting for %.0f usecs until %.6f\n", wait_usec, sim_wallclock_queue->a_due_time);
|
sim_debug (DBG_TIM, &sim_timer_dev, "_timer_thread() - waiting for %.0f usecs until %.6f for %s\n", wait_usec, sim_wallclock_queue->a_due_time, sim_uname(sim_wallclock_queue));
|
||||||
if ((wait_usec <= 0.0) ||
|
if ((wait_usec <= 0.0) ||
|
||||||
(0 != pthread_cond_timedwait (&sim_timer_wake, &sim_timer_lock, &due_time))) {
|
(0 != pthread_cond_timedwait (&sim_timer_wake, &sim_timer_lock, &due_time))) {
|
||||||
if (sim_wallclock_queue == QUEUE_LIST_END) /* queue empty? */
|
if (sim_wallclock_queue == QUEUE_LIST_END) /* queue empty? */
|
||||||
|
@ -1238,22 +1238,29 @@ while (sim_asynch_enabled && sim_asynch_timer && sim_is_running) {
|
||||||
}
|
}
|
||||||
sim_debug (DBG_TIM, &sim_timer_dev, "_timer_thread() - slept %.0fms - activating(%s,%d)\n",
|
sim_debug (DBG_TIM, &sim_timer_dev, "_timer_thread() - slept %.0fms - activating(%s,%d)\n",
|
||||||
1000.0*(_timespec_to_double (&stop_time)-_timespec_to_double (&start_time)), sim_uname(uptr), inst_delay);
|
1000.0*(_timespec_to_double (&stop_time)-_timespec_to_double (&start_time)), sim_uname(uptr), inst_delay);
|
||||||
sim_activate (uptr, inst_delay);
|
if (sim_clock_unit == uptr) {
|
||||||
if (sim_clock_unit == uptr)
|
/*
|
||||||
while (sim_clock_cosched_queue != QUEUE_LIST_END) {
|
* Some devices may depend on executing during the same instruction as the
|
||||||
uptr = sim_clock_cosched_queue;
|
* clock tick event. We link the clock coschedule queue to the clock tick
|
||||||
sim_clock_cosched_queue = uptr->next;
|
* and then insert that list in the asynch event queue in a single operation
|
||||||
uptr->next = NULL;
|
*/
|
||||||
sim_activate (uptr, inst_delay);
|
uptr->next = sim_clock_cosched_queue;
|
||||||
|
sim_clock_cosched_queue = QUEUE_LIST_END;
|
||||||
|
AIO_ACTIVATE_LIST(sim_activate, uptr, inst_delay);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
sim_activate (uptr, inst_delay);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
else /* Something wants to adjust the queue */
|
else /* Something wants to adjust the queue since the wait condition was signaled */
|
||||||
if (sim_timer_event_canceled)
|
if (sim_timer_event_canceled)
|
||||||
sim_timer_event_canceled = FALSE; /* reset flag and continue */
|
sim_timer_event_canceled = FALSE; /* reset flag and continue */
|
||||||
else
|
else
|
||||||
if (sim_wallclock_entry == NULL) /* nothing to insert? */
|
if (sim_wallclock_entry == NULL) { /* nothing to insert? */
|
||||||
|
sim_debug (DBG_TIM, &sim_timer_dev, "_timer_thread() - condition wakeup without new entry\n");
|
||||||
break; /* stop processing entries */
|
break; /* stop processing entries */
|
||||||
}
|
}
|
||||||
|
}
|
||||||
pthread_mutex_unlock (&sim_timer_lock);
|
pthread_mutex_unlock (&sim_timer_lock);
|
||||||
|
|
||||||
sim_debug (DBG_TIM, &sim_timer_dev, "_timer_thread() - exiting\n");
|
sim_debug (DBG_TIM, &sim_timer_dev, "_timer_thread() - exiting\n");
|
||||||
|
@ -1426,9 +1433,16 @@ if (1) {
|
||||||
sim_uname(uptr), uptr->a_due_time);
|
sim_uname(uptr), uptr->a_due_time);
|
||||||
}
|
}
|
||||||
pthread_mutex_lock (&sim_timer_lock);
|
pthread_mutex_lock (&sim_timer_lock);
|
||||||
|
while (sim_wallclock_entry) {
|
||||||
|
sim_debug (DBG_TIM, &sim_timer_dev, "sim_timer_activate_after() - queue insert entry %s busy waiting for 1ms\n",
|
||||||
|
sim_uname(sim_wallclock_entry));
|
||||||
|
pthread_mutex_unlock (&sim_timer_lock);
|
||||||
|
sim_os_ms_sleep (1);
|
||||||
|
pthread_mutex_lock (&sim_timer_lock);
|
||||||
|
}
|
||||||
sim_wallclock_entry = uptr;
|
sim_wallclock_entry = uptr;
|
||||||
pthread_cond_signal (&sim_timer_wake); /* wake the timer thread to deal with it */
|
|
||||||
pthread_mutex_unlock (&sim_timer_lock);
|
pthread_mutex_unlock (&sim_timer_lock);
|
||||||
|
pthread_cond_signal (&sim_timer_wake); /* wake the timer thread to deal with it */
|
||||||
return SCPE_OK;
|
return SCPE_OK;
|
||||||
#else
|
#else
|
||||||
return _sim_activate (uptr, inst_delay); /* queue it now */
|
return _sim_activate (uptr, inst_delay); /* queue it now */
|
||||||
|
|
|
@ -119,6 +119,7 @@ uint32 sim_timer_idle_capable (uint32 *hoat_tick_ms);
|
||||||
|
|
||||||
extern t_bool sim_idle_enab; /* idle enabled flag */
|
extern t_bool sim_idle_enab; /* idle enabled flag */
|
||||||
extern volatile t_bool sim_idle_wait; /* idle waiting flag */
|
extern volatile t_bool sim_idle_wait; /* idle waiting flag */
|
||||||
|
extern UNIT *sim_clock_unit;
|
||||||
extern t_bool sim_asynch_timer;
|
extern t_bool sim_asynch_timer;
|
||||||
extern DEVICE sim_timer_dev;
|
extern DEVICE sim_timer_dev;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue