Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions cpus-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,38 @@ static inline void exclusive_idle(void)
}
}

static int64_t wallclock_ms(void)
{
struct timeval tv;

gettimeofday(&tv, NULL);
return (int64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000;
}

static bool exclusive_timedwait(QemuCond *cond, int64_t deadline_ms)
{
int64_t timeout_ms = deadline_ms - wallclock_ms();

if (timeout_ms <= 0) {
return false;
}
if (timeout_ms > INT_MAX) {
timeout_ms = INT_MAX;
}
return qemu_cond_timedwait(cond, &qemu_cpu_list_lock, timeout_ms);
}

static void exclusive_cancel_waiters(void)
{
CPUState *other_cpu;

CPU_FOREACH(other_cpu) {
other_cpu->has_waiter = false;
}
qatomic_set(&pending_cpus, 0);
qemu_cond_broadcast(&exclusive_resume);
}

/* Start an exclusive operation.
Must only be called from outside cpu_exec. */
void start_exclusive(void)
Expand Down Expand Up @@ -219,6 +251,59 @@ void start_exclusive(void)
current_cpu->exclusive_context_count = 1;
}

/*
* Try to start an exclusive operation, but do not wait forever for CPUs that
* are stuck in host/native code. Returns true with the same state as
* start_exclusive(), or false with no exclusive operation held.
*/
bool start_exclusive_timeout(int timeout_ms)
{
CPUState *other_cpu;
int64_t deadline_ms = wallclock_ms() + timeout_ms;
int running_cpus;

if (current_cpu->exclusive_context_count) {
current_cpu->exclusive_context_count++;
return true;
}

qemu_mutex_lock(&qemu_cpu_list_lock);
while (pending_cpus) {
if (!exclusive_timedwait(&exclusive_resume, deadline_ms)) {
qemu_mutex_unlock(&qemu_cpu_list_lock);
return false;
}
}

/* Make all other cpus stop executing. */
qatomic_set(&pending_cpus, 1);

/* Write pending_cpus before reading other_cpu->running. */
smp_mb();
running_cpus = 0;
CPU_FOREACH(other_cpu) {
if (qatomic_read(&other_cpu->running)) {
other_cpu->has_waiter = true;
running_cpus++;
qemu_cpu_kick(other_cpu);
}
}

qatomic_set(&pending_cpus, running_cpus + 1);
while (pending_cpus > 1) {
if (!exclusive_timedwait(&exclusive_cond, deadline_ms)) {
exclusive_cancel_waiters();
qemu_mutex_unlock(&qemu_cpu_list_lock);
return false;
}
}

qemu_mutex_unlock(&qemu_cpu_list_lock);

current_cpu->exclusive_context_count = 1;
return true;
}

/* Finish an exclusive operation. */
void end_exclusive(void)
{
Expand Down
9 changes: 9 additions & 0 deletions include/hw/core/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -912,6 +912,15 @@ void cpu_exec_end(CPUState *cpu);
*/
void start_exclusive(void);

/**
* start_exclusive_timeout:
* @timeout_ms: maximum time to wait in milliseconds.
*
* Like start_exclusive(), but returns false if other CPUs do not quiesce
* before the timeout expires. On false, no exclusive section is held.
*/
bool start_exclusive_timeout(int timeout_ms);

/**
* end_exclusive:
*
Expand Down
15 changes: 13 additions & 2 deletions target/i386/latx/sbt/aot.c
Original file line number Diff line number Diff line change
Expand Up @@ -1660,6 +1660,8 @@ static void creat_daemon(bool is_end)
umask(0);
}

#define AOT_EXIT_EXCLUSIVE_TIMEOUT_MS 1000

void aot_exit_entry(CPUState *cpu, int is_end)
{
if (!option_aot) {
Expand All @@ -1670,9 +1672,18 @@ void aot_exit_entry(CPUState *cpu, int is_end)
_exit(0);
}

bool exclusive_started = false;
bool in_exclusive_context = cpu_in_exclusive_context(cpu);
if (!in_exclusive_context) {
start_exclusive();
if (is_end) {
if (!start_exclusive_timeout(AOT_EXIT_EXCLUSIVE_TIMEOUT_MS)) {
qemu_log_mask(LAT_LOG_AOT, "skip final aot: exclusive wait timeout");
return;
}
} else {
start_exclusive();
}
exclusive_started = true;
}

sigset_t sigset;
Expand Down Expand Up @@ -1729,7 +1740,7 @@ void aot_exit_entry(CPUState *cpu, int is_end)
}

parent_exit:
if (!in_exclusive_context) {
if (exclusive_started) {
end_exclusive();
}
return;
Expand Down
Loading