timers: fix stop/cont with -icount
Stop/cont commands are broken with -icount due to a deadlock. The real problem is that the computation of timers_state.cpu_ticks_offset makes no sense with -icount enabled: we set it to an icount clock value in cpu_disable_ticks, and subtract a TSC (or similar, whatever cpu_get_real_ticks happens to return) value in cpu_enable_ticks. The fix is simple. timers_state.cpu_ticks_offset is only used together with cpu_get_real_ticks, so we can use cpu_get_real_ticks in cpu_disable_ticks. There is no need to update cpu_ticks_prev at the time cpu_disable_ticks is called; instead, we can do it the next time cpu_get_ticks is called. The change to cpu_disable_ticks is the important part of the patch. The rest modifies the code to always check timers_state.cpu_ticks_prev, even when the ticks are not advancing (i.e. the VM is stopped). It also makes a similar change to cpu_get_clock_locked, so that the code remains similar for cpu_get_ticks and cpu_get_clock_locked. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Message-id: 1382977938-13844-1-git-send-email-pbonzini@redhat.com Signed-off-by: Anthony Liguori <aliguori@amazon.com>
This commit is contained in:
		
							parent
							
								
									cd5be5829c
								
							
						
					
					
						commit
						5f3e31012e
					
				
							
								
								
									
										32
									
								
								cpus.c
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								cpus.c
									
									
									
									
									
								
							@ -165,36 +165,38 @@ int64_t cpu_get_icount(void)
 | 
				
			|||||||
/* Caller must hold the BQL */
 | 
					/* Caller must hold the BQL */
 | 
				
			||||||
int64_t cpu_get_ticks(void)
 | 
					int64_t cpu_get_ticks(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    int64_t ticks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (use_icount) {
 | 
					    if (use_icount) {
 | 
				
			||||||
        return cpu_get_icount();
 | 
					        return cpu_get_icount();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (!timers_state.cpu_ticks_enabled) {
 | 
					
 | 
				
			||||||
        return timers_state.cpu_ticks_offset;
 | 
					    ticks = timers_state.cpu_ticks_offset;
 | 
				
			||||||
    } else {
 | 
					    if (timers_state.cpu_ticks_enabled) {
 | 
				
			||||||
        int64_t ticks;
 | 
					        ticks += cpu_get_real_ticks();
 | 
				
			||||||
        ticks = cpu_get_real_ticks();
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (timers_state.cpu_ticks_prev > ticks) {
 | 
					    if (timers_state.cpu_ticks_prev > ticks) {
 | 
				
			||||||
        /* Note: non increasing ticks may happen if the host uses
 | 
					        /* Note: non increasing ticks may happen if the host uses
 | 
				
			||||||
           software suspend */
 | 
					           software suspend */
 | 
				
			||||||
        timers_state.cpu_ticks_offset += timers_state.cpu_ticks_prev - ticks;
 | 
					        timers_state.cpu_ticks_offset += timers_state.cpu_ticks_prev - ticks;
 | 
				
			||||||
 | 
					        ticks = timers_state.cpu_ticks_prev;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    timers_state.cpu_ticks_prev = ticks;
 | 
					    timers_state.cpu_ticks_prev = ticks;
 | 
				
			||||||
        return ticks + timers_state.cpu_ticks_offset;
 | 
					    return ticks;
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int64_t cpu_get_clock_locked(void)
 | 
					static int64_t cpu_get_clock_locked(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int64_t ti;
 | 
					    int64_t ticks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!timers_state.cpu_ticks_enabled) {
 | 
					    ticks = timers_state.cpu_clock_offset;
 | 
				
			||||||
        ti = timers_state.cpu_clock_offset;
 | 
					    if (timers_state.cpu_ticks_enabled) {
 | 
				
			||||||
    } else {
 | 
					        ticks += get_clock();
 | 
				
			||||||
        ti = get_clock();
 | 
					 | 
				
			||||||
        ti += timers_state.cpu_clock_offset;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return ti;
 | 
					    return ticks;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* return the host CPU monotonic timer and handle stop/restart */
 | 
					/* return the host CPU monotonic timer and handle stop/restart */
 | 
				
			||||||
@ -235,7 +237,7 @@ void cpu_disable_ticks(void)
 | 
				
			|||||||
    /* Here, the really thing protected by seqlock is cpu_clock_offset. */
 | 
					    /* Here, the really thing protected by seqlock is cpu_clock_offset. */
 | 
				
			||||||
    seqlock_write_lock(&timers_state.vm_clock_seqlock);
 | 
					    seqlock_write_lock(&timers_state.vm_clock_seqlock);
 | 
				
			||||||
    if (timers_state.cpu_ticks_enabled) {
 | 
					    if (timers_state.cpu_ticks_enabled) {
 | 
				
			||||||
        timers_state.cpu_ticks_offset = cpu_get_ticks();
 | 
					        timers_state.cpu_ticks_offset += cpu_get_real_ticks();
 | 
				
			||||||
        timers_state.cpu_clock_offset = cpu_get_clock_locked();
 | 
					        timers_state.cpu_clock_offset = cpu_get_clock_locked();
 | 
				
			||||||
        timers_state.cpu_ticks_enabled = 0;
 | 
					        timers_state.cpu_ticks_enabled = 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user