@@ -2491,11 +2491,11 @@ while (sim_asynch_timer && sim_is_running) {
24912491 pthread_mutex_lock (& sim_timer_lock );
24922492 if (sim_wallclock_entry != NULL ) { /* something to insert in queue? */
24932493
2494+ uptr = unit_ptr_load_atomic (& sim_wallclock_entry );
2495+
24942496 sim_debug (DBG_TIM , & sim_timer_dev , "_timer_thread() - timing %s for %s\n" ,
2495- sim_uname (unit_ptr_load_atomic (sim_wallclock_entry )),
2496- sim_fmt_secs (sim_wallclock_entry -> a_usec_delay /USEC_PER_SEC_d ));
2497+ sim_uname (uptr ), sim_fmt_secs (sim_wallclock_entry -> a_usec_delay /USEC_PER_SEC_d ));
24972498
2498- uptr = unit_ptr_load_atomic (& sim_wallclock_entry );
24992499 sim_wallclock_entry = NULL ;
25002500
25012501 prvptr = NULL ;
@@ -2910,35 +2910,78 @@ t_stat sim_timer_activate_after(UNIT *uptr, double usec_delay)
29102910 for (tmr = 0 ; tmr <= SIM_NTIMERS ; tmr ++ ) {
29112911 RTC * rtc = & rtcs [tmr ];
29122912
2913- rtc -> clock_unit -> cancel = & _sim_wallclock_cancel ;
2914- rtc -> clock_unit -> a_is_active = & _sim_wallclock_is_active ;
2915- }
2916-
2917- sim_debug (DBG_TIM , & sim_timer_dev , "sim_timer_activate_after(%s, %.0f usecs) - queueing wallclock addition at %.6f\n" ,
2918- sim_uname (uptr ), usec_delay , uptr -> a_due_time );
2919-
2920- pthread_mutex_lock (& sim_timer_lock );
2921- for (cptr = unit_ptr_load_atomic (& sim_wallclock_queue ), prvptr = NULL ;
2922- cptr != QUEUE_LIST_END ;
2923- cptr = unit_ptr_load_atomic (& cptr -> a_next )) {
2924- if (uptr -> a_due_time < cptr -> a_due_time )
2913+ if (rtc -> clock_unit == uptr ) {
2914+ uptr = rtc -> timer_unit ;
29252915 break ;
29262916 }
2927- if (prvptr == NULL ) { /* inserting at head */
2928- uptr -> a_next = QUEUE_LIST_END ; /* Temporarily mark as active */
2929- if (sim_timer_thread_running ) {
2930- while (sim_wallclock_entry ) { /* wait for any prior entry has been digested */
2931- sim_debug (DBG_TIM , & sim_timer_dev , "sim_timer_activate_after(%s, %.0f usecs) - queue insert entry %s busy waiting for 1ms\n" ,
2932- sim_uname (uptr ), usec_delay , sim_uname ((UNIT * ) sim_wallclock_entry ));
2933- pthread_mutex_unlock (& sim_timer_lock );
2934- sim_os_ms_sleep (1 );
2935- pthread_mutex_lock (& sim_timer_lock );
2917+ }
2918+ if (sim_is_active (uptr )) /* already active? */
2919+ return SCPE_OK ;
2920+ if (usec_delay < 0.0 ) {
2921+ sim_debug (DBG_QUE , & sim_timer_dev , "sim_timer_activate_after(%s, %.0f usecs) - surprising usec value\n" , sim_uname (uptr ),
2922+ usec_delay );
2923+ }
2924+ if ((sim_is_running ) || (tmr <= SIM_NTIMERS ))
2925+ uptr -> usecs_remaining = 0.0 ;
2926+ else { /* defer non timer wallclock activations until a calibrated timer is in effect */
2927+ uptr -> usecs_remaining = usec_delay ;
2928+ usec_delay = 0.0 ;
2929+ }
2930+ /*
2931+ * Handle long delays by aligning with the calibrated timer's calibration
2932+ * activities. Delays which would expire prior to the next calibration
2933+ * are specifically scheduled directly based on the the current instruction
2934+ * execution rate. Longer delays are coscheduled to fire on the first tick
2935+ * after the next calibration and at that time are either scheduled directly
2936+ * or re-coscheduled for the next calibration time, repeating until the total
2937+ * desired time has elapsed.
2938+ */
2939+ inst_per_usec = sim_timer_inst_per_sec () / USEC_PER_SEC_d ;
2940+ inst_delay_d = floor (inst_per_usec * usec_delay );
2941+ inst_delay = (int32 )inst_delay_d ;
2942+ if ((inst_delay == 0 ) && (usec_delay != 0.0 ))
2943+ inst_delay_d = inst_delay = 1 ; /* Minimum non-zero delay is 1 instruction */
2944+ if (uptr -> usecs_remaining != 0.0 ) /* No calibrated timer yet, wait one cycle */
2945+ inst_delay_d = inst_delay = 1 ; /* Minimum non-zero delay is 1 instruction */
2946+ if (sim_calb_tmr != INVALID_TIMER ) {
2947+ crtc = & rtcs [sim_calb_tmr ];
2948+ if (crtc -> hz ) { /* Calibrated Timer available? */
2949+ int32 inst_til_tick = sim_activate_time (crtc -> timer_unit ) - 1 ;
2950+ int32 ticks_til_calib = crtc -> hz - crtc -> ticks ;
2951+ double usecs_per_tick = floor (USEC_PER_SEC_d / crtc -> hz );
2952+ int32 inst_til_calib = inst_til_tick + ((ticks_til_calib - 1 ) * crtc -> currd );
2953+ uint32 usecs_til_calib = (uint32 )ceil (inst_til_calib / inst_per_usec );
2954+
2955+ if ((uptr != crtc -> timer_unit ) && /* Not scheduling calibrated timer */
2956+ (inst_til_tick > 0 )) { /* and tick not pending? */
2957+ if (inst_delay_d > (double )inst_til_calib ) { /* long wait? */
2958+ stat = sim_clock_coschedule_tmr (uptr , sim_calb_tmr , ticks_til_calib - 1 );
2959+ uptr -> usecs_remaining = (stat == SCPE_OK ) ? usec_delay - usecs_til_calib : 0.0 ;
2960+ sim_debug (DBG_TIM , & sim_timer_dev ,
2961+ "sim_timer_activate_after(%s, %.0f usecs) - coscheduling with with calibrated timer(%" SIZE_T_FMT "u), ticks=%d, "
2962+ "usecs_remaining=%.0f usecs, inst_til_tick=%d, ticks_til_calib=%d, usecs_til_calib=%u\n" ,
2963+ sim_uname (uptr ), usec_delay , sim_calb_tmr , ticks_til_calib , uptr -> usecs_remaining , inst_til_tick ,
2964+ ticks_til_calib , usecs_til_calib );
2965+ sim_debug (DBG_CHK , & sim_timer_dev ,
2966+ "sim_timer_activate_after(%s, %.0f usecs) - result = %.0f usecs, %.0f usecs\n" , sim_uname (uptr ),
2967+ usec_delay , sim_timer_activate_time_usecs (ouptr ), sim_timer_activate_time_usecs (uptr ));
2968+ return stat ;
2969+ }
2970+ if ((usec_delay > (2 * usecs_per_tick )) && (ticks_til_calib > 1 )) { /* long wait? */
2971+ double usecs_til_tick = floor (inst_til_tick / inst_per_usec );
2972+
2973+ stat = sim_clock_coschedule_tmr (uptr , sim_calb_tmr , 0 );
2974+ uptr -> usecs_remaining = (stat == SCPE_OK ) ? usec_delay - usecs_til_tick : 0.0 ;
2975+ sim_debug (DBG_TIM , & sim_timer_dev ,
2976+ "sim_timer_activate_after(%s, %.0f usecs) - coscheduling with with calibrated timer(%" SIZE_T_FMT "u), ticks=%d, "
2977+ "usecs_remaining=%.0f usecs, inst_til_tick=%d, usecs_til_tick=%.0f\n" ,
2978+ sim_uname (uptr ), usec_delay , sim_calb_tmr , 0 , uptr -> usecs_remaining , inst_til_tick , usecs_til_tick );
2979+ sim_debug (DBG_CHK , & sim_timer_dev ,
2980+ "sim_timer_activate_after(%s, %.0f usecs) - result = %.0f usecs, %.0f usecs\n" , sim_uname (uptr ),
2981+ usec_delay , sim_timer_activate_time_usecs (ouptr ), sim_timer_activate_time_usecs (uptr ));
2982+ return stat ;
29362983 }
29372984 }
2938- sim_wallclock_entry = uptr ;
2939- pthread_cond_signal (& sim_timer_wake ); /* wake the timer thread to deal with it */
2940- pthread_mutex_unlock (& sim_timer_lock ); /* allow the time thread to wake up. */
2941- return SCPE_OK ;
29422985 }
29432986 }
29442987 /*
0 commit comments