KVM: selftests: Add KVM syscall wrappers for pthread_{cancel,join}()

Add and use KVM wrappers for pthread_{cancel,join}() so that selftests
don't need to manually assert that the syscalls succeeded.

Note, the vast majority tests don't actually assert success, but they all
obviously rely on the syscall to succeed.

Other than explicitly failing if a syscall fails, no functional change
intended.

Link: https://patch.msgid.link/20260731195612.2697986-10-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
This commit is contained in:
Sean Christopherson 2026-07-31 12:56:09 -07:00
parent 5171573ce7
commit bc9143135b
27 changed files with 38 additions and 61 deletions

View File

@ -158,10 +158,10 @@ static void test_run(struct kvm_vm *vm)
}
for (i = 0; i < test_args.nr_vcpus; i++)
pthread_join(pt_vcpu_run[i], NULL);
kvm_pthread_join(pt_vcpu_run[i], NULL);
if (test_args.migration_freq_ms)
pthread_join(pt_vcpu_migration, NULL);
kvm_pthread_join(pt_vcpu_migration, NULL);
bitmap_free(vcpu_done_map);
}

View File

@ -1007,8 +1007,8 @@ static void test_vgic_two_cpus(void *gcode)
kvm_pthread_create(&thr[0], NULL, test_vcpu_run, vcpus[0]);
kvm_pthread_create(&thr[1], NULL, test_vcpu_run, vcpus[1]);
pthread_join(thr[0], NULL);
pthread_join(thr[1], NULL);
kvm_pthread_join(thr[0], NULL);
kvm_pthread_join(thr[1], NULL);
close(gic_fd);
kvm_vm_free(vm);

View File

@ -321,13 +321,13 @@ static void run_test(void)
clock_gettime(CLOCK_MONOTONIC, &start);
for (i = 0; i < nr_devices; i++)
pthread_join(lpi_threads[i], NULL);
kvm_pthread_join(lpi_threads[i], NULL);
delta = timespec_elapsed(start);
write_guest_global(vm, test_data.request_vcpus_stop, true);
for (i = 0; i < nr_vcpus; i++)
pthread_join(vcpu_threads[i], NULL);
kvm_pthread_join(vcpu_threads[i], NULL);
report_stats(delta);
}

View File

@ -805,7 +805,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
WRITE_ONCE(host_quit, true);
sem_post(&sem_vcpu_cont);
pthread_join(vcpu_thread, NULL);
kvm_pthread_join(vcpu_thread, NULL);
pr_info("Total bits checked: dirty (%lu), clear (%lu)\n",
host_dirty_count, host_clear_count);

View File

@ -101,6 +101,8 @@ __KVM_SYSCALL_DEFINE(sched_setaffinity, 3, pid_t, pid, size_t, cpusetsize, cpu_s
typedef void *(*pthread_fn_t)(void *);
__KVM_SYSCALL_DEFINE(pthread_create, 4, pthread_t *, thread,
const pthread_attr_t *, attr, pthread_fn_t, fn, void *, arg);
__KVM_SYSCALL_DEFINE(pthread_join, 2, pthread_t, thread, void **, thread_return);
__KVM_SYSCALL_DEFINE(pthread_cancel, 1, pthread_t, thread);
#define kvm_free_fd(fd) \
do { \

View File

@ -356,7 +356,7 @@ int main(int argc, char **argv)
WRITE_AND_SYNC_TO_GUEST(vm, done, true);
for (i = 0; i < nr_vcpus; i++)
pthread_join(vcpu_threads[i], NULL);
kvm_pthread_join(vcpu_threads[i], NULL);
return 0;
}

View File

@ -139,5 +139,5 @@ int main(int argc, char *argv[])
}
WRITE_ONCE(done, true);
pthread_join(racing_thread, NULL);
kvm_pthread_join(racing_thread, NULL);
}

View File

@ -413,7 +413,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
}
for (i = 0; i < nr_vcpus; i++)
pthread_join(vcpu_threads[i], NULL);
kvm_pthread_join(vcpu_threads[i], NULL);
ret = sem_destroy(&test_stage_updated);
TEST_ASSERT(ret == 0, "Error in sem_destroy");

View File

@ -312,7 +312,7 @@ void memstress_join_vcpu_threads(int nr_vcpus)
WRITE_ONCE(memstress_args.stop_vcpus, true);
for (i = 0; i < nr_vcpus; i++)
pthread_join(vcpu_threads[i].thread, NULL);
kvm_pthread_join(vcpu_threads[i].thread, NULL);
}
static void toggle_dirty_logging(struct kvm_vm *vm, int slots, bool enable)

View File

@ -187,8 +187,7 @@ void uffd_stop_demand_paging(struct uffd_desc *uffd)
"Unable to write to pipefd %i for uffd_desc %p", i, uffd);
for (i = 0; i < uffd->num_readers; ++i)
TEST_ASSERT(!pthread_join(uffd->readers[i], NULL),
"Pthread_join failed on reader %i for uffd_desc %p", i, uffd);
kvm_pthread_join(uffd->readers[i], NULL);
close(uffd->uffd);

View File

@ -381,7 +381,7 @@ static void free_vm(struct vm_data *data)
static void wait_guest_exit(struct vm_data *data)
{
pthread_join(data->vcpu_thread, NULL);
kvm_pthread_join(data->vcpu_thread, NULL);
}
static void let_guest_run(struct sync_area *sync)

View File

@ -409,7 +409,7 @@ int main(int argc, char *argv[])
/* Sanity check that the vCPUs actually ran. */
for (i = 0; i < nr_vcpus; i++)
pthread_join(threads[i], NULL);
kvm_pthread_join(threads[i], NULL);
/*
* Deliberately exit without deleting the remaining memslots or closing

View File

@ -116,7 +116,7 @@ static void pre_fault_memory(struct kvm_vcpu *vcpu, u64 base_gpa, u64 offset,
*/
if (!slot_recreated) {
WRITE_ONCE(data.recreate_slot, true);
pthread_join(slot_worker, NULL);
kvm_pthread_join(slot_worker, NULL);
slot_recreated = true;
/*

View File

@ -312,7 +312,7 @@ int main(int argc, char *argv[])
" e.g. via cpuidle.off=1 or via -l <latency>, or run with -u to\n"
" disable this sanity check.", i);
pthread_join(migration_thread, NULL);
kvm_pthread_join(migration_thread, NULL);
kvm_vm_free(vm);

View File

@ -701,7 +701,7 @@ static void test_cmpxchg_key_concurrent(void)
}
}
pthread_join(thread, NULL);
kvm_pthread_join(thread, NULL);
MOP(t.vcpu, LOGICAL, READ, mem2, max_block, GADDR_V(mem2));
TEST_ASSERT(popcount_eq(*(__uint128_t *)mem1, *(__uint128_t *)mem2),

View File

@ -216,7 +216,7 @@ static void test_move_memory_region(bool disable_slot_zap_quirk)
/* Defered sync from when the memslot was misaligned (above). */
wait_for_vcpu();
pthread_join(vcpu_thread, NULL);
kvm_pthread_join(vcpu_thread, NULL);
kvm_vm_free(vm);
}
@ -302,7 +302,7 @@ static void test_delete_memory_region(bool disable_slot_zap_quirk)
*/
vm_mem_region_delete(vm, 0);
pthread_join(vcpu_thread, NULL);
kvm_pthread_join(vcpu_thread, NULL);
run = vcpu->run;

View File

@ -557,7 +557,7 @@ int main(int ac, char **av)
do
sched_yield();
while (get_run_delay() - run_delay < MIN_RUN_DELAY_NS);
pthread_join(thread, NULL);
kvm_pthread_join(thread, NULL);
run_delay = get_run_delay() - run_delay;
TEST_ASSERT(run_delay >= MIN_RUN_DELAY_NS,
"Expected run_delay >= %ld, got %ld",

View File

@ -225,15 +225,9 @@ static void *vcpu_thread(void *arg)
static void cancel_join_vcpu_thread(pthread_t thread, struct kvm_vcpu *vcpu)
{
void *retval;
int r;
r = pthread_cancel(thread);
TEST_ASSERT(!r, "pthread_cancel on vcpu_id=%d failed with errno=%d",
vcpu->id, r);
r = pthread_join(thread, &retval);
TEST_ASSERT(!r, "pthread_join on vcpu_id=%d failed with errno=%d",
vcpu->id, r);
kvm_pthread_cancel(thread);
kvm_pthread_join(thread, &retval);
TEST_ASSERT(retval == PTHREAD_CANCELED,
"expected retval=%p, got %p", PTHREAD_CANCELED,
retval);

View File

@ -551,15 +551,9 @@ static void *vcpu_thread(void *arg)
static void cancel_join_vcpu_thread(pthread_t thread, struct kvm_vcpu *vcpu)
{
void *retval;
int r;
r = pthread_cancel(thread);
TEST_ASSERT(!r, "pthread_cancel on vcpu_id=%d failed with errno=%d",
vcpu->id, r);
r = pthread_join(thread, &retval);
TEST_ASSERT(!r, "pthread_join on vcpu_id=%d failed with errno=%d",
vcpu->id, r);
kvm_pthread_cancel(thread);
kvm_pthread_join(thread, &retval);
TEST_ASSERT(retval == PTHREAD_CANCELED,
"expected retval=%p, got %p", PTHREAD_CANCELED,
retval);

View File

@ -418,7 +418,7 @@ static void test_mem_conversions(enum vm_mem_backing_src_type src_type, u32 nr_v
WRITE_ONCE(run_vcpus, true);
for (i = 0; i < nr_vcpus; i++)
pthread_join(threads[i], NULL);
kvm_pthread_join(threads[i], NULL);
kvm_vm_free(vm);

View File

@ -70,7 +70,7 @@ static void test_private_access_memslot_deleted(void)
vm_mem_region_delete(vm, EXITS_TEST_SLOT);
pthread_join(vm_thread, &thread_return);
kvm_pthread_join(vm_thread, &thread_return);
exit_reason = (u32)(u64)thread_return;
TEST_ASSERT_EQ(exit_reason, KVM_EXIT_MEMORY_FAULT);

View File

@ -65,8 +65,8 @@ int main(void)
vcpu_set_msr(vcpuN, MSR_IA32_APICBASE, LAPIC_DISABLED);
}
TEST_ASSERT_EQ(pthread_cancel(thread), 0);
TEST_ASSERT_EQ(pthread_join(thread, NULL), 0);
kvm_pthread_cancel(thread);
kvm_pthread_join(thread, NULL);
kvm_vm_free(vm);

View File

@ -131,7 +131,7 @@ static void test_sev_migrate_locking(void)
kvm_pthread_create(&pt[i], NULL, locking_test_thread, &input[i]);
for (i = 0; i < NR_LOCK_TESTING_THREADS; ++i)
pthread_join(pt[i], NULL);
kvm_pthread_join(pt[i], NULL);
for (i = 0; i < NR_LOCK_TESTING_THREADS; ++i)
kvm_vm_free(input[i].vm);
}

View File

@ -199,8 +199,8 @@ static void race_sync_regs(struct kvm_vcpu *vcpu, void *racer)
}
}
TEST_ASSERT_EQ(pthread_cancel(thread), 0);
TEST_ASSERT_EQ(pthread_join(thread, NULL), 0);
kvm_pthread_cancel(thread);
kvm_pthread_join(thread, NULL);
kvm_x86_state_cleanup(state);
}

View File

@ -99,7 +99,7 @@ int main(int argc, char *argv[])
unsigned long failures = 0;
for (cpu = 0; cpu < NR_TEST_VCPUS; cpu++) {
void *this_cpu_failures;
pthread_join(cpu_threads[cpu], &this_cpu_failures);
kvm_pthread_join(cpu_threads[cpu], &this_cpu_failures);
failures += (unsigned long)this_cpu_failures;
}

View File

@ -231,17 +231,9 @@ static void *vcpu_thread(void *arg)
static void cancel_join_vcpu_thread(pthread_t thread, struct kvm_vcpu *vcpu)
{
void *retval;
int r;
r = pthread_cancel(thread);
TEST_ASSERT(r == 0,
"pthread_cancel on vcpu_id=%d failed with errno=%d",
vcpu->id, r);
r = pthread_join(thread, &retval);
TEST_ASSERT(r == 0,
"pthread_join on vcpu_id=%d failed with errno=%d",
vcpu->id, r);
kvm_pthread_cancel(thread);
kvm_pthread_join(thread, &retval);
TEST_ASSERT(retval == PTHREAD_CANCELED,
"expected retval=%p, got %p", PTHREAD_CANCELED,
retval);

View File

@ -437,7 +437,6 @@ int main(int argc, char *argv[])
struct kvm_vm *vm;
pthread_t thread;
bool verbose;
int ret;
verbose = argc > 1 && (!strncmp(argv[1], "-v", 3) ||
!strncmp(argv[1], "--verbose", 10));
@ -948,11 +947,8 @@ int main(int argc, char *argv[])
TEST_ASSERT(!evtchn_irq_expected,
"Expected event channel IRQ but it didn't happen");
ret = pthread_cancel(thread);
TEST_ASSERT(ret == 0, "pthread_cancel() failed: %s", strerror(ret));
ret = pthread_join(thread, 0);
TEST_ASSERT(ret == 0, "pthread_join() failed: %s", strerror(ret));
kvm_pthread_cancel(thread);
kvm_pthread_join(thread, 0);
goto done;
case TEST_GUEST_SAW_IRQ: