Skip to content

Commit c8bf6c7

Browse files
committed
LATX, fix: bound final AOT exclusive wait
Final AOT generation runs during process exit and may try to enter an exclusive section after other threads are already blocked in native/host code. In that case start_exclusive() can wait forever for CPUs that will not quiesce. Add start_exclusive_timeout() and use it only for the final AOT exit path. If the timeout expires, cancel the pending waiters, skip final AOT, and return without holding the exclusive section. Normal AOT generation continues to use the existing blocking start_exclusive() path. Signed-off-by: Wenqiang Wei <weiwenqiang@mail.ustc.edu.cn>
1 parent d3231ca commit c8bf6c7

3 files changed

Lines changed: 107 additions & 2 deletions

File tree

cpus-common.c

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,38 @@ static inline void exclusive_idle(void)
177177
}
178178
}
179179

180+
static int64_t wallclock_ms(void)
181+
{
182+
struct timeval tv;
183+
184+
gettimeofday(&tv, NULL);
185+
return (int64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000;
186+
}
187+
188+
static bool exclusive_timedwait(QemuCond *cond, int64_t deadline_ms)
189+
{
190+
int64_t timeout_ms = deadline_ms - wallclock_ms();
191+
192+
if (timeout_ms <= 0) {
193+
return false;
194+
}
195+
if (timeout_ms > INT_MAX) {
196+
timeout_ms = INT_MAX;
197+
}
198+
return qemu_cond_timedwait(cond, &qemu_cpu_list_lock, timeout_ms);
199+
}
200+
201+
static void exclusive_cancel_waiters(void)
202+
{
203+
CPUState *other_cpu;
204+
205+
CPU_FOREACH(other_cpu) {
206+
other_cpu->has_waiter = false;
207+
}
208+
qatomic_set(&pending_cpus, 0);
209+
qemu_cond_broadcast(&exclusive_resume);
210+
}
211+
180212
/* Start an exclusive operation.
181213
Must only be called from outside cpu_exec. */
182214
void start_exclusive(void)
@@ -219,6 +251,59 @@ void start_exclusive(void)
219251
current_cpu->exclusive_context_count = 1;
220252
}
221253

254+
/*
255+
* Try to start an exclusive operation, but do not wait forever for CPUs that
256+
* are stuck in host/native code. Returns true with the same state as
257+
* start_exclusive(), or false with no exclusive operation held.
258+
*/
259+
bool start_exclusive_timeout(int timeout_ms)
260+
{
261+
CPUState *other_cpu;
262+
int64_t deadline_ms = wallclock_ms() + timeout_ms;
263+
int running_cpus;
264+
265+
if (current_cpu->exclusive_context_count) {
266+
current_cpu->exclusive_context_count++;
267+
return true;
268+
}
269+
270+
qemu_mutex_lock(&qemu_cpu_list_lock);
271+
while (pending_cpus) {
272+
if (!exclusive_timedwait(&exclusive_resume, deadline_ms)) {
273+
qemu_mutex_unlock(&qemu_cpu_list_lock);
274+
return false;
275+
}
276+
}
277+
278+
/* Make all other cpus stop executing. */
279+
qatomic_set(&pending_cpus, 1);
280+
281+
/* Write pending_cpus before reading other_cpu->running. */
282+
smp_mb();
283+
running_cpus = 0;
284+
CPU_FOREACH(other_cpu) {
285+
if (qatomic_read(&other_cpu->running)) {
286+
other_cpu->has_waiter = true;
287+
running_cpus++;
288+
qemu_cpu_kick(other_cpu);
289+
}
290+
}
291+
292+
qatomic_set(&pending_cpus, running_cpus + 1);
293+
while (pending_cpus > 1) {
294+
if (!exclusive_timedwait(&exclusive_cond, deadline_ms)) {
295+
exclusive_cancel_waiters();
296+
qemu_mutex_unlock(&qemu_cpu_list_lock);
297+
return false;
298+
}
299+
}
300+
301+
qemu_mutex_unlock(&qemu_cpu_list_lock);
302+
303+
current_cpu->exclusive_context_count = 1;
304+
return true;
305+
}
306+
222307
/* Finish an exclusive operation. */
223308
void end_exclusive(void)
224309
{

include/hw/core/cpu.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -912,6 +912,15 @@ void cpu_exec_end(CPUState *cpu);
912912
*/
913913
void start_exclusive(void);
914914

915+
/**
916+
* start_exclusive_timeout:
917+
* @timeout_ms: maximum time to wait in milliseconds.
918+
*
919+
* Like start_exclusive(), but returns false if other CPUs do not quiesce
920+
* before the timeout expires. On false, no exclusive section is held.
921+
*/
922+
bool start_exclusive_timeout(int timeout_ms);
923+
915924
/**
916925
* end_exclusive:
917926
*

target/i386/latx/sbt/aot.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1660,6 +1660,8 @@ static void creat_daemon(bool is_end)
16601660
umask(0);
16611661
}
16621662

1663+
#define AOT_EXIT_EXCLUSIVE_TIMEOUT_MS 1000
1664+
16631665
void aot_exit_entry(CPUState *cpu, int is_end)
16641666
{
16651667
if (!option_aot) {
@@ -1670,9 +1672,18 @@ void aot_exit_entry(CPUState *cpu, int is_end)
16701672
_exit(0);
16711673
}
16721674

1675+
bool exclusive_started = false;
16731676
bool in_exclusive_context = cpu_in_exclusive_context(cpu);
16741677
if (!in_exclusive_context) {
1675-
start_exclusive();
1678+
if (is_end) {
1679+
if (!start_exclusive_timeout(AOT_EXIT_EXCLUSIVE_TIMEOUT_MS)) {
1680+
qemu_log_mask(LAT_LOG_AOT, "skip final aot: exclusive wait timeout");
1681+
return;
1682+
}
1683+
} else {
1684+
start_exclusive();
1685+
}
1686+
exclusive_started = true;
16761687
}
16771688

16781689
sigset_t sigset;
@@ -1729,7 +1740,7 @@ void aot_exit_entry(CPUState *cpu, int is_end)
17291740
}
17301741

17311742
parent_exit:
1732-
if (!in_exclusive_context) {
1743+
if (exclusive_started) {
17331744
end_exclusive();
17341745
}
17351746
return;

0 commit comments

Comments
 (0)