qom: convert the CPU list to RCU
Iterating over the list without using atomics is undefined behaviour, since the list can be modified concurrently by other threads (e.g. every time a new thread is created in user-mode). Fix it by implementing the CPU list as an RCU QTAILQ. This requires a little bit of extra work to traverse list in reverse order (see previous patch), but other than that the conversion is trivial. Signed-off-by: Emilio G. Cota <cota@braap.org> Message-Id: <20180819091335.22863-12-cota@braap.org> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
		
							parent
							
								
									04d595b300
								
							
						
					
					
						commit
						068a5ea02f
					
				| @ -84,7 +84,7 @@ void cpu_list_add(CPUState *cpu) | ||||
|     } else { | ||||
|         assert(!cpu_index_auto_assigned); | ||||
|     } | ||||
|     QTAILQ_INSERT_TAIL(&cpus, cpu, node); | ||||
|     QTAILQ_INSERT_TAIL_RCU(&cpus, cpu, node); | ||||
|     qemu_mutex_unlock(&qemu_cpu_list_lock); | ||||
| 
 | ||||
|     finish_safe_work(cpu); | ||||
| @ -101,7 +101,7 @@ void cpu_list_remove(CPUState *cpu) | ||||
| 
 | ||||
|     assert(!(cpu_index_auto_assigned && cpu != QTAILQ_LAST(&cpus, CPUTailQ))); | ||||
| 
 | ||||
|     QTAILQ_REMOVE(&cpus, cpu, node); | ||||
|     QTAILQ_REMOVE_RCU(&cpus, cpu, node); | ||||
|     cpu->cpu_index = UNASSIGNED_CPU_INDEX; | ||||
|     qemu_mutex_unlock(&qemu_cpu_list_lock); | ||||
| } | ||||
|  | ||||
							
								
								
									
										2
									
								
								cpus.c
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								cpus.c
									
									
									
									
									
								
							| @ -1491,7 +1491,7 @@ static void *qemu_tcg_rr_cpu_thread_fn(void *arg) | ||||
|             atomic_mb_set(&cpu->exit_request, 0); | ||||
|         } | ||||
| 
 | ||||
|         qemu_tcg_rr_wait_io_event(cpu ? cpu : QTAILQ_FIRST(&cpus)); | ||||
|         qemu_tcg_rr_wait_io_event(cpu ? cpu : first_cpu); | ||||
|         deal_with_unplugged_cpus(); | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -26,6 +26,7 @@ | ||||
| #include "exec/memattrs.h" | ||||
| #include "qapi/qapi-types-run-state.h" | ||||
| #include "qemu/bitmap.h" | ||||
| #include "qemu/rcu_queue.h" | ||||
| #include "qemu/queue.h" | ||||
| #include "qemu/thread.h" | ||||
| 
 | ||||
| @ -442,13 +443,11 @@ struct CPUState { | ||||
| 
 | ||||
| QTAILQ_HEAD(CPUTailQ, CPUState); | ||||
| extern struct CPUTailQ cpus; | ||||
| #define CPU_NEXT(cpu) QTAILQ_NEXT(cpu, node) | ||||
| #define CPU_FOREACH(cpu) QTAILQ_FOREACH(cpu, &cpus, node) | ||||
| #define first_cpu        QTAILQ_FIRST_RCU(&cpus) | ||||
| #define CPU_NEXT(cpu)    QTAILQ_NEXT_RCU(cpu, node) | ||||
| #define CPU_FOREACH(cpu) QTAILQ_FOREACH_RCU(cpu, &cpus, node) | ||||
| #define CPU_FOREACH_SAFE(cpu, next_cpu) \ | ||||
|     QTAILQ_FOREACH_SAFE(cpu, &cpus, node, next_cpu) | ||||
| #define CPU_FOREACH_REVERSE(cpu) \ | ||||
|     QTAILQ_FOREACH_REVERSE(cpu, &cpus, CPUTailQ, node) | ||||
| #define first_cpu QTAILQ_FIRST(&cpus) | ||||
|     QTAILQ_FOREACH_SAFE_RCU(cpu, &cpus, node, next_cpu) | ||||
| 
 | ||||
| extern __thread CPUState *current_cpu; | ||||
| 
 | ||||
|  | ||||
| @ -126,7 +126,7 @@ void fork_end(int child) | ||||
|            Discard information about the parent threads.  */ | ||||
|         CPU_FOREACH_SAFE(cpu, next_cpu) { | ||||
|             if (cpu != thread_cpu) { | ||||
|                 QTAILQ_REMOVE(&cpus, cpu, node); | ||||
|                 QTAILQ_REMOVE_RCU(&cpus, cpu, node); | ||||
|             } | ||||
|         } | ||||
|         qemu_init_cpu_list(); | ||||
|  | ||||
| @ -8157,7 +8157,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, | ||||
|             TaskState *ts; | ||||
| 
 | ||||
|             /* Remove the CPU from the list.  */ | ||||
|             QTAILQ_REMOVE(&cpus, cpu, node); | ||||
|             QTAILQ_REMOVE_RCU(&cpus, cpu, node); | ||||
| 
 | ||||
|             cpu_list_unlock(); | ||||
| 
 | ||||
|  | ||||
| @ -1096,7 +1096,7 @@ void s390_set_qemu_cpu_model(uint16_t type, uint8_t gen, uint8_t ec_ga, | ||||
|     const S390CPUDef *def = s390_find_cpu_def(type, gen, ec_ga, NULL); | ||||
| 
 | ||||
|     g_assert(def); | ||||
|     g_assert(QTAILQ_EMPTY(&cpus)); | ||||
|     g_assert(QTAILQ_EMPTY_RCU(&cpus)); | ||||
| 
 | ||||
|     /* TCG emulates some features that can usually not be enabled with
 | ||||
|      * the emulated machine generation. Make sure they can be enabled | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Emilio G. Cota
						Emilio G. Cota