|  | @@ -95,8 +95,8 @@ static gpr_timespec g_start_time;
 | 
	
		
			
				|  |  |  GPR_TLS_DECL(g_last_seen_min_timer);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  static gpr_atm saturating_add(gpr_atm a, gpr_atm b) {
 | 
	
		
			
				|  |  | -  if (a > GPR_ATM_MAX - b) {
 | 
	
		
			
				|  |  | -    return GPR_ATM_MAX;
 | 
	
		
			
				|  |  | +  if (a > GPR_ATM_MAX - 1 - b) {
 | 
	
		
			
				|  |  | +    return GPR_ATM_MAX - 1;
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |    return a + b;
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -117,7 +117,10 @@ static gpr_atm timespec_to_atm_round_up(gpr_timespec ts) {
 | 
	
		
			
				|  |  |    double x = GPR_MS_PER_SEC * (double)ts.tv_sec +
 | 
	
		
			
				|  |  |               (double)ts.tv_nsec / GPR_NS_PER_MS + 1.0;
 | 
	
		
			
				|  |  |    if (x < 0) return 0;
 | 
	
		
			
				|  |  | -  if (x > GPR_ATM_MAX) return GPR_ATM_MAX;
 | 
	
		
			
				|  |  | +  // when rounding up (for deadlines) we clamp at 1ms before 'infinity', so that
 | 
	
		
			
				|  |  | +  // when executing with now=infinity (at shutdown) all timers are guaranteed to
 | 
	
		
			
				|  |  | +  // fire
 | 
	
		
			
				|  |  | +  if (x > GPR_ATM_MAX - 1) return GPR_ATM_MAX - 1;
 | 
	
		
			
				|  |  |    return (gpr_atm)x;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -321,6 +324,10 @@ void grpc_timer_cancel(grpc_exec_ctx *exec_ctx, grpc_timer *timer) {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    shard_type *shard = &g_shards[GPR_HASH_POINTER(timer, NUM_SHARDS)];
 | 
	
		
			
				|  |  |    gpr_mu_lock(&shard->mu);
 | 
	
		
			
				|  |  | +  if (grpc_timer_trace) {
 | 
	
		
			
				|  |  | +    gpr_log(GPR_DEBUG, "TIMER %p: CANCEL pending=%s", timer,
 | 
	
		
			
				|  |  | +            timer->pending ? "true" : "false");
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  |    if (timer->pending) {
 | 
	
		
			
				|  |  |      grpc_closure_sched(exec_ctx, timer->closure, GRPC_ERROR_CANCELLED);
 | 
	
		
			
				|  |  |      timer->pending = false;
 | 
	
	
		
			
				|  | @@ -394,6 +401,10 @@ static grpc_timer *pop_one(shard_type *shard, gpr_atm now) {
 | 
	
		
			
				|  |  |                timer->deadline, now);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      if (timer->deadline > now) return NULL;
 | 
	
		
			
				|  |  | +    if (grpc_timer_trace) {
 | 
	
		
			
				|  |  | +      gpr_log(GPR_DEBUG, "TIMER %p: FIRE %" PRIdPTR "ms late", timer,
 | 
	
		
			
				|  |  | +              now - timer->deadline);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |      timer->pending = false;
 | 
	
		
			
				|  |  |      grpc_timer_heap_pop(&shard->heap);
 | 
	
		
			
				|  |  |      return timer;
 | 
	
	
		
			
				|  | @@ -444,7 +455,7 @@ static int run_some_expired_timers(grpc_exec_ctx *exec_ctx, gpr_atm now,
 | 
	
		
			
				|  |  |                g_shard_queue[0]->min_deadline);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    while (g_shard_queue[0]->min_deadline < now) {
 | 
	
		
			
				|  |  | +    while (g_shard_queue[0]->min_deadline <= now) {
 | 
	
		
			
				|  |  |        gpr_atm new_min_deadline;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |        /* For efficiency, we pop as many available timers as we can from the
 | 
	
	
		
			
				|  | @@ -454,11 +465,11 @@ static int run_some_expired_timers(grpc_exec_ctx *exec_ctx, gpr_atm now,
 | 
	
		
			
				|  |  |            pop_timers(exec_ctx, g_shard_queue[0], now, &new_min_deadline, error);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |        if (grpc_timer_check_trace) {
 | 
	
		
			
				|  |  | -        gpr_log(GPR_DEBUG,
 | 
	
		
			
				|  |  | -                "  .. popped --> %" PRIdPTR
 | 
	
		
			
				|  |  | -                ", shard[%d]->min_deadline %" PRIdPTR " --> %" PRIdPTR,
 | 
	
		
			
				|  |  | +        gpr_log(GPR_DEBUG, "  .. popped --> %" PRIdPTR
 | 
	
		
			
				|  |  | +                           ", shard[%d]->min_deadline %" PRIdPTR
 | 
	
		
			
				|  |  | +                           " --> %" PRIdPTR ", now=%" PRIdPTR,
 | 
	
		
			
				|  |  |                  n, (int)(g_shard_queue[0] - g_shards),
 | 
	
		
			
				|  |  | -                g_shard_queue[0]->min_deadline, new_min_deadline);
 | 
	
		
			
				|  |  | +                g_shard_queue[0]->min_deadline, new_min_deadline, now);
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |        /* An grpc_timer_init() on the shard could intervene here, adding a new
 |