memory: switch memory listeners to a QTAILQ
This allows reverse iteration, which in turns allows consistent ordering among multiple listeners: l1->add l2->add l2->del l1->del Signed-off-by: Avi Kivity <avi@redhat.com> Reviewed-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
		
							parent
							
								
									946996e9c1
								
							
						
					
					
						commit
						72e22d2fe1
					
				| 
						 | 
				
			
			@ -751,6 +751,7 @@ int vhost_dev_init(struct vhost_dev *hdev, int devfd, bool force)
 | 
			
		|||
        .log_sync = vhost_log_sync,
 | 
			
		||||
        .log_global_start = vhost_log_global_start,
 | 
			
		||||
        .log_global_stop = vhost_log_global_stop,
 | 
			
		||||
        .priority = 10
 | 
			
		||||
    };
 | 
			
		||||
    hdev->mem = g_malloc0(offsetof(struct vhost_memory, regions));
 | 
			
		||||
    hdev->n_mem_sections = 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -726,6 +726,7 @@ static MemoryListener kvm_memory_listener = {
 | 
			
		|||
    .log_sync = kvm_log_sync,
 | 
			
		||||
    .log_global_start = kvm_log_global_start,
 | 
			
		||||
    .log_global_stop = kvm_log_global_stop,
 | 
			
		||||
    .priority = 10,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void kvm_handle_interrupt(CPUState *env, int mask)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										70
									
								
								memory.c
								
								
								
								
							
							
						
						
									
										70
									
								
								memory.c
								
								
								
								
							| 
						 | 
				
			
			@ -27,8 +27,8 @@ unsigned memory_region_transaction_depth = 0;
 | 
			
		|||
static bool memory_region_update_pending = false;
 | 
			
		||||
static bool global_dirty_log = false;
 | 
			
		||||
 | 
			
		||||
static QLIST_HEAD(, MemoryListener) memory_listeners
 | 
			
		||||
    = QLIST_HEAD_INITIALIZER(memory_listeners);
 | 
			
		||||
static QTAILQ_HEAD(memory_listeners, MemoryListener) memory_listeners
 | 
			
		||||
    = QTAILQ_HEAD_INITIALIZER(memory_listeners);
 | 
			
		||||
 | 
			
		||||
typedef struct AddrRange AddrRange;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -678,17 +678,31 @@ static void address_space_update_ioeventfds(AddressSpace *as)
 | 
			
		|||
    as->ioeventfd_nb = ioeventfd_nb;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define MEMORY_LISTENER_CALL(_callback, _args...)               \
 | 
			
		||||
    do {                                                        \
 | 
			
		||||
        MemoryListener *_listener;                              \
 | 
			
		||||
                                                                \
 | 
			
		||||
        QLIST_FOREACH(_listener, &memory_listeners, link) {     \
 | 
			
		||||
            _listener->_callback(_listener, ##_args);           \
 | 
			
		||||
        }                                                       \
 | 
			
		||||
enum ListenerDirection { Forward, Reverse };
 | 
			
		||||
 | 
			
		||||
#define MEMORY_LISTENER_CALL(_callback, _direction, _args...)           \
 | 
			
		||||
    do {                                                                \
 | 
			
		||||
        MemoryListener *_listener;                                      \
 | 
			
		||||
                                                                        \
 | 
			
		||||
        switch (_direction) {                                           \
 | 
			
		||||
        case Forward:                                                   \
 | 
			
		||||
            QTAILQ_FOREACH(_listener, &memory_listeners, link) {        \
 | 
			
		||||
                _listener->_callback(_listener, ##_args);               \
 | 
			
		||||
            }                                                           \
 | 
			
		||||
            break;                                                      \
 | 
			
		||||
        case Reverse:                                                   \
 | 
			
		||||
            QTAILQ_FOREACH_REVERSE(_listener, &memory_listeners,        \
 | 
			
		||||
                                   memory_listeners, link) {            \
 | 
			
		||||
                _listener->_callback(_listener, ##_args);               \
 | 
			
		||||
            }                                                           \
 | 
			
		||||
            break;                                                      \
 | 
			
		||||
        default:                                                        \
 | 
			
		||||
            abort();                                                    \
 | 
			
		||||
        }                                                               \
 | 
			
		||||
    } while (0)
 | 
			
		||||
 | 
			
		||||
#define MEMORY_LISTENER_UPDATE_REGION(fr, as, callback)                 \
 | 
			
		||||
    MEMORY_LISTENER_CALL(callback, &(MemoryRegionSection) {             \
 | 
			
		||||
#define MEMORY_LISTENER_UPDATE_REGION(fr, as, dir, callback)            \
 | 
			
		||||
    MEMORY_LISTENER_CALL(callback, dir, &(MemoryRegionSection) {        \
 | 
			
		||||
        .mr = (fr)->mr,                                                 \
 | 
			
		||||
        .address_space = (as)->root,                                    \
 | 
			
		||||
        .offset_within_region = (fr)->offset_in_region,                 \
 | 
			
		||||
| 
						 | 
				
			
			@ -728,7 +742,7 @@ static void address_space_update_topology_pass(AddressSpace *as,
 | 
			
		|||
            /* In old, but (not in new, or in new but attributes changed). */
 | 
			
		||||
 | 
			
		||||
            if (!adding) {
 | 
			
		||||
                MEMORY_LISTENER_UPDATE_REGION(frold, as, region_del);
 | 
			
		||||
                MEMORY_LISTENER_UPDATE_REGION(frold, as, Reverse, region_del);
 | 
			
		||||
                as->ops->range_del(as, frold);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -738,11 +752,11 @@ static void address_space_update_topology_pass(AddressSpace *as,
 | 
			
		|||
 | 
			
		||||
            if (adding) {
 | 
			
		||||
                if (frold->dirty_log_mask && !frnew->dirty_log_mask) {
 | 
			
		||||
                    MEMORY_LISTENER_UPDATE_REGION(frnew, as, log_stop);
 | 
			
		||||
                    MEMORY_LISTENER_UPDATE_REGION(frnew, as, Reverse, log_stop);
 | 
			
		||||
                    as->ops->log_stop(as, frnew);
 | 
			
		||||
                } else if (frnew->dirty_log_mask && !frold->dirty_log_mask) {
 | 
			
		||||
                    as->ops->log_start(as, frnew);
 | 
			
		||||
                    MEMORY_LISTENER_UPDATE_REGION(frnew, as, log_start);
 | 
			
		||||
                    MEMORY_LISTENER_UPDATE_REGION(frnew, as, Forward, log_start);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -753,7 +767,7 @@ static void address_space_update_topology_pass(AddressSpace *as,
 | 
			
		|||
 | 
			
		||||
            if (adding) {
 | 
			
		||||
                as->ops->range_add(as, frnew);
 | 
			
		||||
                MEMORY_LISTENER_UPDATE_REGION(frnew, as, region_add);
 | 
			
		||||
                MEMORY_LISTENER_UPDATE_REGION(frnew, as, Forward, region_add);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            ++inew;
 | 
			
		||||
| 
						 | 
				
			
			@ -1142,7 +1156,8 @@ void memory_region_sync_dirty_bitmap(MemoryRegion *mr)
 | 
			
		|||
 | 
			
		||||
    FOR_EACH_FLAT_RANGE(fr, &address_space_memory.current_map) {
 | 
			
		||||
        if (fr->mr == mr) {
 | 
			
		||||
            MEMORY_LISTENER_UPDATE_REGION(fr, &address_space_memory, log_sync);
 | 
			
		||||
            MEMORY_LISTENER_UPDATE_REGION(fr, &address_space_memory,
 | 
			
		||||
                                          Forward, log_sync);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1469,7 +1484,7 @@ void memory_global_sync_dirty_bitmap(MemoryRegion *address_space)
 | 
			
		|||
    FlatRange *fr;
 | 
			
		||||
 | 
			
		||||
    FOR_EACH_FLAT_RANGE(fr, &as->current_map) {
 | 
			
		||||
        MEMORY_LISTENER_UPDATE_REGION(fr, as, log_sync);
 | 
			
		||||
        MEMORY_LISTENER_UPDATE_REGION(fr, as, Forward, log_sync);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1477,13 +1492,13 @@ void memory_global_dirty_log_start(void)
 | 
			
		|||
{
 | 
			
		||||
    cpu_physical_memory_set_dirty_tracking(1);
 | 
			
		||||
    global_dirty_log = true;
 | 
			
		||||
    MEMORY_LISTENER_CALL(log_global_start);
 | 
			
		||||
    MEMORY_LISTENER_CALL(log_global_start, Forward);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void memory_global_dirty_log_stop(void)
 | 
			
		||||
{
 | 
			
		||||
    global_dirty_log = false;
 | 
			
		||||
    MEMORY_LISTENER_CALL(log_global_stop);
 | 
			
		||||
    MEMORY_LISTENER_CALL(log_global_stop, Reverse);
 | 
			
		||||
    cpu_physical_memory_set_dirty_tracking(0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1509,14 +1524,27 @@ static void listener_add_address_space(MemoryListener *listener,
 | 
			
		|||
 | 
			
		||||
void memory_listener_register(MemoryListener *listener)
 | 
			
		||||
{
 | 
			
		||||
    QLIST_INSERT_HEAD(&memory_listeners, listener, link);
 | 
			
		||||
    MemoryListener *other = NULL;
 | 
			
		||||
 | 
			
		||||
    if (QTAILQ_EMPTY(&memory_listeners)
 | 
			
		||||
        || listener->priority >= QTAILQ_LAST(&memory_listeners,
 | 
			
		||||
                                             memory_listeners)->priority) {
 | 
			
		||||
        QTAILQ_INSERT_TAIL(&memory_listeners, listener, link);
 | 
			
		||||
    } else {
 | 
			
		||||
        QTAILQ_FOREACH(other, &memory_listeners, link) {
 | 
			
		||||
            if (listener->priority < other->priority) {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        QTAILQ_INSERT_BEFORE(other, listener, link);
 | 
			
		||||
    }
 | 
			
		||||
    listener_add_address_space(listener, &address_space_memory);
 | 
			
		||||
    listener_add_address_space(listener, &address_space_io);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void memory_listener_unregister(MemoryListener *listener)
 | 
			
		||||
{
 | 
			
		||||
    QLIST_REMOVE(listener, link);
 | 
			
		||||
    QTAILQ_REMOVE(&memory_listeners, listener, link);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void set_system_memory_map(MemoryRegion *mr)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										4
									
								
								memory.h
								
								
								
								
							
							
						
						
									
										4
									
								
								memory.h
								
								
								
								
							| 
						 | 
				
			
			@ -185,7 +185,9 @@ struct MemoryListener {
 | 
			
		|||
    void (*log_sync)(MemoryListener *listener, MemoryRegionSection *section);
 | 
			
		||||
    void (*log_global_start)(MemoryListener *listener);
 | 
			
		||||
    void (*log_global_stop)(MemoryListener *listener);
 | 
			
		||||
    QLIST_ENTRY(MemoryListener) link;
 | 
			
		||||
    /* Lower = earlier (during add), later (during del) */
 | 
			
		||||
    unsigned priority;
 | 
			
		||||
    QTAILQ_ENTRY(MemoryListener) link;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue