{
CPUState *cpu;
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
if (!cpu_thread_is_idle(cpu)) {
return false;
}
fprintf(stderr, "qemu: hardware error: ");
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
fprintf(stderr, "CPU #%d:\n", cpu->cpu_index);
cpu_dump_state(cpu, stderr, fprintf, CPU_DUMP_FPU);
}
{
CPUState *cpu;
- for (cpu = first_cpu; cpu; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
cpu_synchronize_state(cpu);
}
}
{
CPUState *cpu;
- for (cpu = first_cpu; cpu; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
cpu_synchronize_post_reset(cpu);
}
}
{
CPUState *cpu;
- for (cpu = first_cpu; cpu; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
cpu_synchronize_post_init(cpu);
}
}
qemu_cond_wait(&qemu_io_proceeded_cond, &qemu_global_mutex);
}
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
qemu_wait_io_event_common(cpu);
}
}
qemu_cond_signal(&qemu_cpu_cond);
/* wait for initial kick-off after machine start */
- while (first_cpu->stopped) {
+ while (QTAILQ_FIRST(&cpus)->stopped) {
qemu_cond_wait(tcg_halt_cond, &qemu_global_mutex);
/* process any pending work */
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
qemu_wait_io_event_common(cpu);
}
}
static int all_vcpus_paused(void)
{
- CPUState *cpu = first_cpu;
+ CPUState *cpu;
- while (cpu) {
+ CPU_FOREACH(cpu) {
if (!cpu->stopped) {
return 0;
}
- cpu = cpu->next_cpu;
}
return 1;
void pause_all_vcpus(void)
{
- CPUState *cpu = first_cpu;
+ CPUState *cpu;
qemu_clock_enable(QEMU_CLOCK_VIRTUAL, false);
- while (cpu) {
+ CPU_FOREACH(cpu) {
cpu->stop = true;
qemu_cpu_kick(cpu);
- cpu = cpu->next_cpu;
}
if (qemu_in_vcpu_thread()) {
cpu_stop_current();
if (!kvm_enabled()) {
- cpu = first_cpu;
- while (cpu) {
+ CPU_FOREACH(cpu) {
cpu->stop = false;
cpu->stopped = true;
- cpu = cpu->next_cpu;
}
return;
}
while (!all_vcpus_paused()) {
qemu_cond_wait(&qemu_pause_cond, &qemu_global_mutex);
- cpu = first_cpu;
- while (cpu) {
+ CPU_FOREACH(cpu) {
qemu_cpu_kick(cpu);
- cpu = cpu->next_cpu;
}
}
}
void resume_all_vcpus(void)
{
- CPUState *cpu = first_cpu;
+ CPUState *cpu;
qemu_clock_enable(QEMU_CLOCK_VIRTUAL, true);
- while (cpu) {
+ CPU_FOREACH(cpu) {
cpu_resume(cpu);
- cpu = cpu->next_cpu;
}
}
if (next_cpu == NULL) {
next_cpu = first_cpu;
}
- for (; next_cpu != NULL && !exit_request; next_cpu = next_cpu->next_cpu) {
+ for (; next_cpu != NULL && !exit_request; next_cpu = CPU_NEXT(next_cpu)) {
CPUState *cpu = next_cpu;
CPUArchState *env = cpu->env_ptr;
CPUState *cpu;
int i;
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
for (i = 0; i < nb_numa_nodes; i++) {
if (test_bit(cpu->cpu_index, node_cpumask[i])) {
cpu->numa_node = i;
CpuInfoList *head = NULL, *cur_item = NULL;
CPUState *cpu;
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
CpuInfoList *info;
#if defined(TARGET_I386)
X86CPU *x86_cpu = X86_CPU(cpu);
#if defined(TARGET_I386)
CPUState *cs;
- for (cs = first_cpu; cs != NULL; cs = cs->next_cpu) {
+ CPU_FOREACH(cs) {
X86CPU *cpu = X86_CPU(cs);
CPUX86State *env = &cpu->env;
CPUState *cs;
S390CPU *cpu;
- for (cs = first_cpu; cs != NULL; cs = cs->next_cpu) {
+ CPU_FOREACH(cs) {
cpu = S390_CPU(cs);
if (cpu->env.cpu_num == monitor_get_cpu_index()) {
if (s390_cpu_restart(S390_CPU(cs)) == -1) {
CPUState *cpu;
CPUArchState *env;
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
int mmu_idx;
env = cpu->env_ptr;
int ret;
int id;
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
id = cpu_index(cpu);
ret = cpu_write_elf64_note(fd_write_vmcore, cpu, id, s);
if (ret < 0) {
}
}
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
ret = cpu_write_elf64_qemunote(fd_write_vmcore, cpu, s);
if (ret < 0) {
dump_error(s, "dump: failed to write CPU status.\n");
int ret;
int id;
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
id = cpu_index(cpu);
ret = cpu_write_elf32_note(fd_write_vmcore, cpu, id, s);
if (ret < 0) {
}
}
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
ret = cpu_write_elf32_qemunote(fd_write_vmcore, cpu, s);
if (ret < 0) {
dump_error(s, "dump: failed to write CPU status.\n");
*/
cpu_synchronize_all_states();
nr_cpus = 0;
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
nr_cpus++;
}
#endif
-CPUState *first_cpu;
+struct CPUTailQ cpus = QTAILQ_HEAD_INITIALIZER(cpus);
/* current CPU in the current thread. It is only valid inside
cpu_exec() */
DEFINE_TLS(CPUState *, current_cpu);
CPUState *qemu_get_cpu(int index)
{
- CPUState *cpu = first_cpu;
+ CPUState *cpu;
- while (cpu) {
+ CPU_FOREACH(cpu) {
if (cpu->cpu_index == index) {
- break;
+ return cpu;
}
- cpu = cpu->next_cpu;
}
- return cpu;
+ return NULL;
}
void qemu_for_each_cpu(void (*func)(CPUState *cpu, void *data), void *data)
{
CPUState *cpu;
- cpu = first_cpu;
- while (cpu) {
+ CPU_FOREACH(cpu) {
func(cpu, data);
- cpu = cpu->next_cpu;
}
}
{
CPUState *cpu = ENV_GET_CPU(env);
CPUClass *cc = CPU_GET_CLASS(cpu);
- CPUState **pcpu;
+ CPUState *some_cpu;
int cpu_index;
#if defined(CONFIG_USER_ONLY)
cpu_list_lock();
#endif
- cpu->next_cpu = NULL;
- pcpu = &first_cpu;
cpu_index = 0;
- while (*pcpu != NULL) {
- pcpu = &(*pcpu)->next_cpu;
+ CPU_FOREACH(some_cpu) {
cpu_index++;
}
cpu->cpu_index = cpu_index;
#ifndef CONFIG_USER_ONLY
cpu->thread_id = qemu_get_thread_id();
#endif
- *pcpu = cpu;
+ QTAILQ_INSERT_TAIL(&cpus, cpu, node);
#if defined(CONFIG_USER_ONLY)
cpu_list_unlock();
#endif
/* since each CPU stores ram addresses in its TLB cache, we must
reset the modified entries */
/* XXX: slow ! */
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
CPUArchState *env = cpu->env_ptr;
tlb_flush(env, 1);
switch (type) {
case GDB_BREAKPOINT_SW:
case GDB_BREAKPOINT_HW:
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
env = cpu->env_ptr;
err = cpu_breakpoint_insert(env, addr, BP_GDB, NULL);
if (err)
case GDB_WATCHPOINT_WRITE:
case GDB_WATCHPOINT_READ:
case GDB_WATCHPOINT_ACCESS:
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
env = cpu->env_ptr;
err = cpu_watchpoint_insert(env, addr, len, xlat_gdb_type[type],
NULL);
switch (type) {
case GDB_BREAKPOINT_SW:
case GDB_BREAKPOINT_HW:
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
env = cpu->env_ptr;
err = cpu_breakpoint_remove(env, addr, BP_GDB);
if (err)
case GDB_WATCHPOINT_WRITE:
case GDB_WATCHPOINT_READ:
case GDB_WATCHPOINT_ACCESS:
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
env = cpu->env_ptr;
err = cpu_watchpoint_remove(env, addr, len, xlat_gdb_type[type]);
if (err)
return;
}
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
env = cpu->env_ptr;
cpu_breakpoint_remove_all(env, BP_GDB);
#ifndef CONFIG_USER_ONLY
{
CPUState *cpu;
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
if (cpu_index(cpu) == thread_id) {
return cpu;
}
if (s->query_cpu) {
snprintf(buf, sizeof(buf), "m%x", cpu_index(s->query_cpu));
put_packet(s, buf);
- s->query_cpu = s->query_cpu->next_cpu;
+ s->query_cpu = CPU_NEXT(s->query_cpu);
} else
put_packet(s, "l");
break;
}
info->is_linux = is_linux;
- for (; cs; cs = cs->next_cpu) {
+ for (; cs; cs = CPU_NEXT(cs)) {
cpu = ARM_CPU(cs);
cpu->env.boot_info = info;
qemu_register_reset(do_cpu_reset, cpu);
if (!cap_clock_ctrl) {
return;
}
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
ret = kvm_vcpu_ioctl(cpu, KVM_KVMCLOCK_CTRL, 0);
if (ret) {
if (ret != -EINVAL) {
X86CPU *cpu;
CPUX86State *env;
- for (cs = first_cpu; cs != NULL; cs = cs->next_cpu) {
+ CPU_FOREACH(cs) {
cpu = X86_CPU(cs);
env = &cpu->env;
info.apic = env->apic_state;
DPRINTF("pic_irqs: %s irq %d\n", level? "raise" : "lower", irq);
if (env->apic_state) {
- while (cs) {
+ CPU_FOREACH(cs) {
cpu = X86_CPU(cs);
env = &cpu->env;
if (apic_accept_pic_intr(env->apic_state)) {
apic_deliver_pic_intr(env->apic_state, level);
}
- cs = cs->next_cpu;
}
} else {
if (level) {
return NULL;
}
- for (cs = first_cpu; cs != NULL; cs = cs->next_cpu) {
+ CPU_FOREACH(cs) {
if (kvm_openpic_connect_vcpu(dev, cs)) {
fprintf(stderr, "%s: failed to connect vcpu to irqchip\n",
__func__);
{
CPUState *cs;
- for (cs = first_cpu; cs != NULL; cs = cs->next_cpu) {
+ CPU_FOREACH(cs) {
PowerPCCPU *cpu = POWERPC_CPU(cs);
cpu->env.mpic_proxy = enabled;
assert(spapr->cpu_model);
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
uint32_t associativity[] = {cpu_to_be32(0x5),
cpu_to_be32(0x0),
cpu_to_be32(0x0),
/* This is needed during FDT finalization */
spapr->cpu_model = g_strdup(modelname);
- for (cs = first_cpu; cs != NULL; cs = cs->next_cpu) {
+ CPU_FOREACH(cs) {
PowerPCCPU *cpu = POWERPC_CPU(cs);
CPUPPCState *env = &cpu->env;
PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cs);
switch (mflags) {
case H_SET_MODE_ENDIAN_BIG:
- for (cs = first_cpu; cs != NULL; cs = cs->next_cpu) {
+ CPU_FOREACH(cs) {
PowerPCCPU *cp = POWERPC_CPU(cs);
CPUPPCState *env = &cp->env;
env->spr[SPR_LPCR] &= ~LPCR_ILE;
break;
case H_SET_MODE_ENDIAN_LITTLE:
- for (cs = first_cpu; cs != NULL; cs = cs->next_cpu) {
+ CPU_FOREACH(cs) {
PowerPCCPU *cp = POWERPC_CPU(cs);
CPUPPCState *env = &cp->env;
env->spr[SPR_LPCR] |= LPCR_ILE;
#include <signal.h>
#include "hw/qdev-core.h"
#include "exec/hwaddr.h"
+#include "qemu/queue.h"
#include "qemu/thread.h"
#include "qemu/tls.h"
#include "qemu/typedefs.h"
struct GDBRegisterState *gdb_regs;
int gdb_num_regs;
int gdb_num_g_regs;
- CPUState *next_cpu;
+ QTAILQ_ENTRY(CPUState) node;
int kvm_fd;
bool kvm_vcpu_dirty;
uint32_t halted; /* used by alpha, cris, ppc TCG */
};
-extern CPUState *first_cpu;
+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 CPU_FOREACH_SAFE(cpu, next_cpu) \
+ QTAILQ_FOREACH_SAFE(cpu, &cpus, node, next_cpu)
+#define first_cpu QTAILQ_FIRST(&cpus)
DECLARE_TLS(CPUState *, current_cpu);
#define current_cpu tls_var(current_cpu)
}
}
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
err = kvm_update_guest_debug(cpu, 0);
if (err) {
return err;
}
}
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
err = kvm_update_guest_debug(cpu, 0);
if (err) {
return err;
QTAILQ_FOREACH_SAFE(bp, &s->kvm_sw_breakpoints, entry, next) {
if (kvm_arch_remove_sw_breakpoint(cpu, bp) != 0) {
/* Try harder to find a CPU that currently sees the breakpoint. */
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
if (kvm_arch_remove_sw_breakpoint(cpu, bp) == 0) {
break;
}
}
kvm_arch_remove_all_hw_breakpoints();
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
kvm_update_guest_debug(cpu, 0);
}
}
/* read and fill status of all threads */
cpu_list_lock();
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
if (cpu == thread_cpu) {
continue;
}
{
mmap_fork_end(child);
if (child) {
+ CPUState *cpu, *next_cpu;
/* Child processes created by fork() only have a single thread.
Discard information about the parent threads. */
- first_cpu = thread_cpu;
- first_cpu->next_cpu = NULL;
+ CPU_FOREACH_SAFE(cpu, next_cpu) {
+ if (cpu != thread_cpu) {
+ QTAILQ_REMOVE(&cpus, thread_cpu, node);
+ }
+ }
pending_cpus = 0;
pthread_mutex_init(&exclusive_lock, NULL);
pthread_mutex_init(&cpu_list_mutex, NULL);
pending_cpus = 1;
/* Make all other cpus stop executing. */
- for (other_cpu = first_cpu; other_cpu; other_cpu = other_cpu->next_cpu) {
+ CPU_FOREACH(other_cpu) {
if (other_cpu->running) {
pending_cpus++;
cpu_exit(other_cpu);
Do thread termination if we have more then one thread. */
/* FIXME: This probably breaks if a signal arrives. We should probably
be disabling signals. */
- if (first_cpu->next_cpu) {
+ if (CPU_NEXT(first_cpu)) {
TaskState *ts;
- CPUState **lastp;
- CPUState *p;
cpu_list_lock();
- lastp = &first_cpu;
- p = first_cpu;
- while (p && p != cpu) {
- lastp = &p->next_cpu;
- p = p->next_cpu;
- }
- /* If we didn't find the CPU for this thread then something is
- horribly wrong. */
- if (!p) {
- abort();
- }
/* Remove the CPU from the list. */
- *lastp = p->next_cpu;
+ QTAILQ_REMOVE(&cpus, cpu, node);
cpu_list_unlock();
ts = ((CPUArchState *)cpu_env)->opaque;
if (ts->child_tidptr) {
{
CPUState *cpu;
- for (cpu = start_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
if (cpu_paging_enabled(cpu)) {
return cpu;
}
first_paging_enabled_cpu = find_paging_enabled_cpu(first_cpu);
if (first_paging_enabled_cpu) {
- for (cpu = first_paging_enabled_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ for (cpu = first_paging_enabled_cpu; cpu != NULL;
+ cpu = CPU_NEXT(cpu)) {
Error *err = NULL;
cpu_get_memory_mapping(cpu, list, &err);
if (err) {
monitor_printf(mon, "%d nodes\n", nb_numa_nodes);
for (i = 0; i < nb_numa_nodes; i++) {
monitor_printf(mon, "node %d cpus:", i);
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
if (cpu->numa_node == i) {
monitor_printf(mon, " %d", cpu->cpu_index);
}
params.mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV;
params.addr = 0;
params.misc = 0;
- for (other_cs = first_cpu; other_cs != NULL;
- other_cs = other_cs->next_cpu) {
+ CPU_FOREACH(other_cs) {
if (other_cs == cs) {
continue;
}
cpu = x86_env_get_cpu(env);
cs = CPU(cpu);
/* XXX: not complete but not completely erroneous */
- if (cs->cpu_index != 0 || cs->next_cpu != NULL) {
+ if (cs->cpu_index != 0 || CPU_NEXT(cs) != NULL) {
/* more than one CPU: do not sleep because another CPU may
wake this one */
} else {
CPUState *other_cs = first_cpu;
target_ulong prev = env->mvp->CP0_MVPControl;
- do {
+ CPU_FOREACH(other_cs) {
MIPSCPU *other_cpu = MIPS_CPU(other_cs);
/* Turn off all VPEs except the one executing the dvpe. */
if (&other_cpu->env != env) {
other_cpu->env.mvp->CP0_MVPControl &= ~(1 << CP0MVPCo_EVP);
mips_vpe_sleep(other_cpu);
}
- other_cs = other_cs->next_cpu;
- } while (other_cs);
+ }
return prev;
}
CPUState *other_cs = first_cpu;
target_ulong prev = env->mvp->CP0_MVPControl;
- do {
+ CPU_FOREACH(other_cs) {
MIPSCPU *other_cpu = MIPS_CPU(other_cs);
if (&other_cpu->env != env
other_cpu->env.mvp->CP0_MVPControl |= (1 << CP0MVPCo_EVP);
mips_vpe_wake(other_cpu); /* And wake it up. */
}
- other_cs = other_cs->next_cpu;
- } while (other_cs);
+ }
return prev;
}
#endif /* !CONFIG_USER_ONLY */
return;
}
- for (cs = first_cpu; cs != NULL; cs = cs->next_cpu) {
+ CPU_FOREACH(cs) {
PowerPCCPU *cpu = POWERPC_CPU(cs);
CPUPPCState *cenv = &cpu->env;
#ifndef CONFIG_USER_ONLY
static void cpu_reset_all(void)
{
- CPUState *cpu;
+ CPUState *cs;
S390CPUClass *scc;
- for (cpu = first_cpu; cpu; cpu = cpu->next_cpu) {
- scc = S390_CPU_GET_CLASS(CPU(cpu));
- scc->cpu_reset(CPU(cpu));
+ CPU_FOREACH(cs) {
+ scc = S390_CPU_GET_CLASS(cs);
+ scc->cpu_reset(cs);
}
}
}
tcg_ctx.tb_ctx.nb_tbs = 0;
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
CPUArchState *env = cpu->env_ptr;
memset(env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof(void *));
/* remove the TB from the hash list */
h = tb_jmp_cache_hash_func(tb->pc);
- for (cpu = first_cpu; cpu != NULL; cpu = cpu->next_cpu) {
+ CPU_FOREACH(cpu) {
CPUArchState *env = cpu->env_ptr;
if (env->tb_jmp_cache[h] == tb) {