#include "qemu/osdep.h"
#include "qemu/main-loop.h"
#include "exec/cpu-common.h"
-#include "qom/cpu.h"
+#include "hw/core/cpu.h"
#include "sysemu/cpus.h"
+#include "qemu/lockable.h"
static QemuMutex qemu_cpu_list_lock;
static QemuCond exclusive_cond;
static int cpu_get_free_index(void)
{
CPUState *some_cpu;
- int cpu_index = 0;
+ int max_cpu_index = 0;
cpu_index_auto_assigned = true;
CPU_FOREACH(some_cpu) {
- cpu_index++;
+ if (some_cpu->cpu_index >= max_cpu_index) {
+ max_cpu_index = some_cpu->cpu_index + 1;
+ }
}
- return cpu_index;
-}
-
-static void finish_safe_work(CPUState *cpu)
-{
- cpu_exec_start(cpu);
- cpu_exec_end(cpu);
+ return max_cpu_index;
}
void cpu_list_add(CPUState *cpu)
{
- qemu_mutex_lock(&qemu_cpu_list_lock);
+ QEMU_LOCK_GUARD(&qemu_cpu_list_lock);
if (cpu->cpu_index == UNASSIGNED_CPU_INDEX) {
cpu->cpu_index = cpu_get_free_index();
assert(cpu->cpu_index != UNASSIGNED_CPU_INDEX);
} else {
assert(!cpu_index_auto_assigned);
}
- QTAILQ_INSERT_TAIL(&cpus, cpu, node);
- qemu_mutex_unlock(&qemu_cpu_list_lock);
-
- finish_safe_work(cpu);
+ QTAILQ_INSERT_TAIL_RCU(&cpus, cpu, node);
}
void cpu_list_remove(CPUState *cpu)
{
- qemu_mutex_lock(&qemu_cpu_list_lock);
+ QEMU_LOCK_GUARD(&qemu_cpu_list_lock);
if (!QTAILQ_IN_USE(cpu, node)) {
/* there is nothing to undo since cpu_exec_init() hasn't been called */
- qemu_mutex_unlock(&qemu_cpu_list_lock);
return;
}
- 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);
}
struct qemu_work_item {
* section until end_exclusive resets pending_cpus to 0.
*/
qemu_mutex_unlock(&qemu_cpu_list_lock);
+
+ current_cpu->in_exclusive_context = true;
}
/* Finish an exclusive operation. */
void end_exclusive(void)
{
+ current_cpu->in_exclusive_context = false;
+
qemu_mutex_lock(&qemu_cpu_list_lock);
atomic_set(&pending_cpus, 0);
qemu_cond_broadcast(&exclusive_resume);
* see cpu->running == true, and it will kick the CPU.
*/
if (unlikely(atomic_read(&pending_cpus))) {
- qemu_mutex_lock(&qemu_cpu_list_lock);
+ QEMU_LOCK_GUARD(&qemu_cpu_list_lock);
if (!cpu->has_waiter) {
/* Not counted in pending_cpus, let the exclusive item
* run. Since we have the lock, just set cpu->running to true
* waiter at cpu_exec_end.
*/
}
- qemu_mutex_unlock(&qemu_cpu_list_lock);
}
}
* next cpu_exec_start.
*/
if (unlikely(atomic_read(&pending_cpus))) {
- qemu_mutex_lock(&qemu_cpu_list_lock);
+ QEMU_LOCK_GUARD(&qemu_cpu_list_lock);
if (cpu->has_waiter) {
cpu->has_waiter = false;
atomic_set(&pending_cpus, pending_cpus - 1);
qemu_cond_signal(&exclusive_cond);
}
}
- qemu_mutex_unlock(&qemu_cpu_list_lock);
}
}