KVM: selftests: Add KVM syscall wrapper for pthread_create()

Add and use a KVM wrapper for pthread_create() syscall so that selftests
don't need to manually assert that the syscall succeeded.

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

Other than explicitly failing if pthread_create() fails, no functional
change intended.

Link: https://patch.msgid.link/20260731195612.2697986-9-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
This commit is contained in:
Sean Christopherson 2026-07-31 12:56:08 -07:00
parent bb0e7d84c4
commit 5171573ce7
28 changed files with 50 additions and 77 deletions

View File

@ -141,28 +141,22 @@ static void test_run(struct kvm_vm *vm)
{
pthread_t pt_vcpu_migration;
unsigned int i;
int ret;
pthread_mutex_init(&vcpu_done_map_lock, NULL);
vcpu_done_map = bitmap_zalloc(test_args.nr_vcpus);
TEST_ASSERT(vcpu_done_map, "Failed to allocate vcpu done bitmap");
for (i = 0; i < (unsigned long)test_args.nr_vcpus; i++) {
ret = pthread_create(&pt_vcpu_run[i], NULL, test_vcpu_run,
(void *)(unsigned long)i);
TEST_ASSERT(!ret, "Failed to create vCPU-%d pthread", i);
}
for (i = 0; i < (unsigned long)test_args.nr_vcpus; i++)
kvm_pthread_create(&pt_vcpu_run[i], NULL, test_vcpu_run,
(void *)(unsigned long)i);
/* Spawn a thread to control the vCPU migrations */
if (test_args.migration_freq_ms) {
srand(time(NULL));
ret = pthread_create(&pt_vcpu_migration, NULL,
test_vcpu_migration, NULL);
TEST_ASSERT(!ret, "Failed to create the migration pthread");
kvm_pthread_create(&pt_vcpu_migration, NULL, test_vcpu_migration, NULL);
}
for (i = 0; i < test_args.nr_vcpus; i++)
pthread_join(pt_vcpu_run[i], NULL);

View File

@ -988,7 +988,7 @@ static void test_vgic_two_cpus(void *gcode)
struct test_args args = {};
struct kvm_vm *vm;
gva_t args_gva;
int gic_fd, ret;
int gic_fd;
vm = vm_create_with_vcpus(2, gcode, vcpus);
@ -1004,12 +1004,8 @@ static void test_vgic_two_cpus(void *gcode)
gic_fd = vgic_v3_setup(vm, 2, 64);
ret = pthread_create(&thr[0], NULL, test_vcpu_run, vcpus[0]);
if (ret)
TEST_FAIL("Can't create thread for vcpu 0 (%d)\n", ret);
ret = pthread_create(&thr[1], NULL, test_vcpu_run, vcpus[1]);
if (ret)
TEST_FAIL("Can't create thread for vcpu 1 (%d)\n", ret);
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);

View File

@ -311,10 +311,10 @@ static void run_test(void)
pthread_barrier_init(&test_setup_barrier, NULL, nr_vcpus + nr_devices + 1);
for (i = 0; i < nr_vcpus; i++)
pthread_create(&vcpu_threads[i], NULL, vcpu_worker_thread, vcpus[i]);
kvm_pthread_create(&vcpu_threads[i], NULL, vcpu_worker_thread, vcpus[i]);
for (i = 0; i < nr_devices; i++)
pthread_create(&lpi_threads[i], NULL, lpi_worker_thread, (void *)i);
kvm_pthread_create(&lpi_threads[i], NULL, lpi_worker_thread, (void *)i);
pthread_barrier_wait(&test_setup_barrier);

View File

@ -691,7 +691,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)
TEST_ASSERT_EQ(vcpu_stop, false);
pthread_create(&vcpu_thread, NULL, vcpu_worker, vcpu);
kvm_pthread_create(&vcpu_thread, NULL, vcpu_worker, vcpu);
for (iteration = 1; iteration <= p->iterations; iteration++) {
unsigned long i, reap_i;

View File

@ -5,7 +5,6 @@
* return notifiers.
*/
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <stdint.h>
#include <stdlib.h>
@ -14,6 +13,7 @@
#include <test_util.h>
#include "kvm_syscalls.h"
#include "kvm_util.h"
#include "ucall_common.h"
@ -62,15 +62,6 @@ static void *sleeping_thread(void *arg)
TEST_FAIL("%s: exited", __func__);
}
static inline void check_create_thread(pthread_t *thread, pthread_attr_t *attr,
void *(*f)(void *), void *arg)
{
int r;
r = pthread_create(thread, attr, f, arg);
TEST_ASSERT(r == 0, "%s: failed to create thread", __func__);
}
static void run_test(u32 run)
{
struct kvm_vcpu *vcpu;
@ -90,11 +81,10 @@ static void run_test(u32 run)
for (i = 0; i < VCPU_NUM; ++i) {
vcpu = vm_vcpu_add(vm, i, guest_code);
check_create_thread(&thread, &attr, run_vcpu, vcpu);
kvm_pthread_create(&thread, &attr, run_vcpu, vcpu);
for (j = 0; j < SLEEPING_THREAD_NUM; ++j)
check_create_thread(&thread, &attr, sleeping_thread,
(void *)NULL);
kvm_pthread_create(&thread, &attr, sleeping_thread, (void *)NULL);
}
pr_debug("%s: [%d] all threads launched\n", __func__, run);
sem_post(sem);

View File

@ -12,6 +12,7 @@
#include <sys/mman.h>
#include <sys/syscall.h>
#include <pthread.h>
#include <sched.h>
#include <test_util.h>
@ -97,6 +98,10 @@ __KVM_SYSCALL_DEFINE(madvise, 3, void *, addr, size_t, length, int, advice);
__KVM_SYSCALL_DEFINE(sched_getaffinity, 3, pid_t, pid, size_t, cpusetsize, cpu_set_t *, mask);
__KVM_SYSCALL_DEFINE(sched_setaffinity, 3, pid_t, pid, size_t, cpusetsize, cpu_set_t *, mask);
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);
#define kvm_free_fd(fd) \
do { \
kvm_close(fd); \

View File

@ -296,7 +296,7 @@ int main(int argc, char **argv)
kvm_sched_getaffinity(0, sizeof(available_cpus), &available_cpus);
for (i = 0; i < nr_vcpus; i++)
pthread_create(&vcpu_threads[i], NULL, vcpu_thread_main, vcpus[i]);
kvm_pthread_create(&vcpu_threads[i], NULL, vcpu_thread_main, vcpus[i]);
for (i = 0; i < nr_vcpus; i++) {
struct kvm_vcpu *vcpu = vcpus[i];

View File

@ -128,7 +128,7 @@ int main(int argc, char *argv[])
close(__eventfd);
pthread_create(&racing_thread, NULL, secondary_irqfd_juggler, vm2);
kvm_pthread_create(&racing_thread, NULL, secondary_irqfd_juggler, vm2);
for (i = 0; i < 10000; i++) {
WRITE_ONCE(__eventfd, kvm_new_eventfd());

View File

@ -364,8 +364,8 @@ static void run_test(enum vm_guest_mode mode, void *arg)
*current_stage = KVM_BEFORE_MAPPINGS;
for (i = 0; i < nr_vcpus; i++)
pthread_create(&vcpu_threads[i], NULL, vcpu_worker,
test_args.vcpus[i]);
kvm_pthread_create(&vcpu_threads[i], NULL, vcpu_worker,
test_args.vcpus[i]);
vcpus_complete_new_stage(*current_stage);
pr_info("Started all vCPUs successfully\n");

View File

@ -294,7 +294,7 @@ void memstress_start_vcpu_threads(int nr_vcpus,
vcpu->vcpu_idx = i;
WRITE_ONCE(vcpu->running, false);
pthread_create(&vcpu->thread, NULL, vcpu_thread_main, vcpu);
kvm_pthread_create(&vcpu->thread, NULL, vcpu_thread_main, vcpu);
}
for (i = 0; i < nr_vcpus; i++) {

View File

@ -167,8 +167,8 @@ struct uffd_desc *uffd_setup_demand_paging(int uffd_mode, useconds_t delay,
uffd_desc->reader_args[i].handler = handler;
uffd_desc->reader_args[i].pipe = pipes[0];
pthread_create(&uffd_desc->readers[i], NULL, uffd_handler_thread_fn,
&uffd_desc->reader_args[i]);
kvm_pthread_create(&uffd_desc->readers[i], NULL, uffd_handler_thread_fn,
&uffd_desc->reader_args[i]);
PER_VCPU_DEBUG("Created uffd thread %i for HVA range [%p, %p)\n",
i, hva, hva + len);

View File

@ -366,7 +366,7 @@ static void launch_vm(struct vm_data *data)
{
pr_info_v("Launching the test VM\n");
pthread_create(&data->vcpu_thread, NULL, vcpu_worker, data);
kvm_pthread_create(&data->vcpu_thread, NULL, vcpu_worker, data);
/* Ensure the guest thread is spun up. */
wait_for_vcpu();

View File

@ -222,7 +222,7 @@ static pthread_t *spawn_workers(struct kvm_vm *vm, struct kvm_vcpu **vcpus,
info[i].vcpu = vcpus[i];
info[i].start_gpa = gpa;
info[i].end_gpa = gpa + nr_bytes;
pthread_create(&threads[i], NULL, vcpu_worker, &info[i]);
kvm_pthread_create(&threads[i], NULL, vcpu_worker, &info[i]);
}
return threads;
}

View File

@ -84,7 +84,7 @@ static void pre_fault_memory(struct kvm_vcpu *vcpu, u64 base_gpa, u64 offset,
* Concurrently delete (and recreate) the slot to test KVM's handling
* of a racing memslot deletion with prefaulting.
*/
pthread_create(&slot_worker, NULL, delete_slot_worker, &data);
kvm_pthread_create(&slot_worker, NULL, delete_slot_worker, &data);
while (!READ_ONCE(data.worker_ready))
cpu_relax();

View File

@ -239,8 +239,8 @@ int main(int argc, char *argv[])
*/
vm = vm_create_with_one_vcpu(&vcpu, guest_code);
pthread_create(&migration_thread, NULL, migration_worker,
(void *)(unsigned long)kvm_gettid());
kvm_pthread_create(&migration_thread, NULL, migration_worker,
(void *)(unsigned long)kvm_gettid());
if (latency >= 0) {
/*

View File

@ -678,7 +678,7 @@ static void test_cmpxchg_key_concurrent(void)
HOST_SYNC(t.vcpu, STAGE_SKEYS_SET);
prepare_mem12();
MOP(t.vcpu, LOGICAL, WRITE, mem1, max_block, GADDR_V(mem2));
pthread_create(&thread, NULL, run_guest, &t.vcpu);
kvm_pthread_create(&thread, NULL, run_guest, &t.vcpu);
for (int i = 0; i < cmpxchg_iter_outer; i++) {
do {

View File

@ -133,7 +133,7 @@ static struct kvm_vm *spawn_vm(struct kvm_vcpu **vcpu, pthread_t *vcpu_thread,
hva = addr_gpa2hva(vm, MEM_REGION_GPA);
memset(hva, 0, 2 * 4096);
pthread_create(vcpu_thread, NULL, vcpu_worker, *vcpu);
kvm_pthread_create(vcpu_thread, NULL, vcpu_worker, *vcpu);
/* Ensure the guest thread is spun up. */
wait_for_vcpu();

View File

@ -553,7 +553,7 @@ int main(int ac, char **av)
/* Steal time from the VCPU. The steal time thread has the same CPU affinity as the VCPUs. */
run_delay = get_run_delay();
pthread_create(&thread, &attr, do_steal_time, NULL);
kvm_pthread_create(&thread, &attr, do_steal_time, NULL);
do
sched_yield();
while (get_run_delay() - run_delay < MIN_RUN_DELAY_NS);

View File

@ -245,7 +245,7 @@ int main(int argc, char *argv[])
struct kvm_vcpu *vcpu[3];
gva_t hcall_page;
pthread_t threads[2];
int stage = 1, r;
int stage = 1;
struct ucall uc;
TEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_SEND_IPI));
@ -272,11 +272,8 @@ int main(int argc, char *argv[])
vcpu_args_set(vcpu[0], 2, hcall_page, addr_gva2gpa(vm, hcall_page));
vcpu_set_hv_cpuid(vcpu[0]);
r = pthread_create(&threads[0], NULL, vcpu_thread, vcpu[1]);
TEST_ASSERT(!r, "pthread_create failed errno=%d", r);
r = pthread_create(&threads[1], NULL, vcpu_thread, vcpu[2]);
TEST_ASSERT(!r, "pthread_create failed errno=%d", errno);
kvm_pthread_create(&threads[0], NULL, vcpu_thread, vcpu[1]);
kvm_pthread_create(&threads[1], NULL, vcpu_thread, vcpu[2]);
while (true) {
vcpu_run(vcpu[0]);
@ -306,5 +303,5 @@ int main(int argc, char *argv[])
cancel_join_vcpu_thread(threads[1], vcpu[2]);
kvm_vm_free(vm);
return r;
return 0;
}

View File

@ -575,7 +575,7 @@ int main(int argc, char *argv[])
u64 *pte;
struct test_data *data;
struct ucall uc;
int stage = 1, r, i;
int stage = 1, i;
TEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_TLBFLUSH));
@ -632,11 +632,8 @@ int main(int argc, char *argv[])
vcpu_set_msr(vcpu[2], HV_X64_MSR_VP_INDEX, WORKER_VCPU_ID_2);
vcpu_set_hv_cpuid(vcpu[2]);
r = pthread_create(&threads[0], NULL, vcpu_thread, vcpu[1]);
TEST_ASSERT(!r, "pthread_create() failed");
r = pthread_create(&threads[1], NULL, vcpu_thread, vcpu[2]);
TEST_ASSERT(!r, "pthread_create() failed");
kvm_pthread_create(&threads[0], NULL, vcpu_thread, vcpu[1]);
kvm_pthread_create(&threads[1], NULL, vcpu_thread, vcpu[2]);
while (true) {
vcpu_run(vcpu[0]);

View File

@ -412,7 +412,7 @@ static void test_mem_conversions(enum vm_mem_backing_src_type src_type, u32 nr_v
*/
virt_map(vm, gpa, gpa, PER_CPU_DATA_SIZE / vm->page_size);
pthread_create(&threads[i], NULL, __test_mem_conversions, vcpus[i]);
kvm_pthread_create(&threads[i], NULL, __test_mem_conversions, vcpus[i]);
}
WRITE_ONCE(run_vcpus, true);

View File

@ -65,9 +65,8 @@ static void test_private_access_memslot_deleted(void)
/* Request to access page privately */
vm_mem_set_private(vm, EXITS_TEST_GPA, EXITS_TEST_SIZE);
pthread_create(&vm_thread, NULL,
(void *(*)(void *))run_vcpu_get_exit_reason,
(void *)vcpu);
kvm_pthread_create(&vm_thread, NULL,
(pthread_fn_t)run_vcpu_get_exit_reason, (void *)vcpu);
vm_mem_region_delete(vm, EXITS_TEST_SLOT);

View File

@ -57,7 +57,7 @@ int main(void)
for (i = 0; i < KVM_MAX_VCPUS; i++)
vcpu_set_msr(vcpus[i], MSR_IA32_APICBASE, LAPIC_X2APIC);
TEST_ASSERT_EQ(pthread_create(&thread, NULL, race, vcpus[0]), 0);
kvm_pthread_create(&thread, NULL, race, vcpus[0]);
vcpuN = vcpus[KVM_MAX_VCPUS - 1];
for (t = time(NULL) + TIMEOUT; time(NULL) < t;) {

View File

@ -128,7 +128,7 @@ static void test_sev_migrate_locking(void)
sizeof(input[i].source_vms));
for (i = 0; i < NR_LOCK_TESTING_THREADS; ++i)
pthread_create(&pt[i], NULL, locking_test_thread, &input[i]);
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);

View File

@ -181,7 +181,7 @@ static void race_sync_regs(struct kvm_vcpu *vcpu, void *racer)
!!(run->s.regs.sregs.cr4 & X86_CR4_PAE),
!!(run->s.regs.sregs.efer & EFER_LME));
TEST_ASSERT_EQ(pthread_create(&thread, NULL, racer, (void *)run), 0);
kvm_pthread_create(&thread, NULL, racer, (void *)run);
for (t = time(NULL) + TIMEOUT; time(NULL) < t;) {
/*

View File

@ -94,7 +94,7 @@ int main(int argc, char *argv[])
pthread_t cpu_threads[NR_TEST_VCPUS];
unsigned long cpu;
for (cpu = 0; cpu < NR_TEST_VCPUS; cpu++)
pthread_create(&cpu_threads[cpu], NULL, run_vcpu, (void *)cpu);
kvm_pthread_create(&cpu_threads[cpu], NULL, run_vcpu, (void *)cpu);
unsigned long failures = 0;
for (cpu = 0; cpu < NR_TEST_VCPUS; cpu++) {

View File

@ -387,7 +387,6 @@ void get_cmdline_args(int argc, char *argv[], int *run_secs,
int main(int argc, char *argv[])
{
int r;
int wait_secs;
const int max_halter_wait = 10;
int run_secs = 0;
@ -428,9 +427,7 @@ int main(int argc, char *argv[])
params[1].pipis_rcvd = pipis_rcvd;
/* Start halter vCPU thread and wait for it to execute first HLT. */
r = pthread_create(&threads[0], NULL, vcpu_thread, &params[0]);
TEST_ASSERT(r == 0,
"pthread_create halter failed errno=%d", errno);
kvm_pthread_create(&threads[0], NULL, vcpu_thread, &params[0]);
fprintf(stderr, "Halter vCPU thread started\n");
wait_secs = 0;
@ -447,8 +444,7 @@ int main(int argc, char *argv[])
"Halter vCPU thread reported its APIC ID: %u after %d seconds.\n",
data->halter_apic_id, wait_secs);
r = pthread_create(&threads[1], NULL, vcpu_thread, &params[1]);
TEST_ASSERT(r == 0, "pthread_create sender failed errno=%d", errno);
kvm_pthread_create(&threads[1], NULL, vcpu_thread, &params[1]);
fprintf(stderr,
"IPI sender vCPU thread started. Letting vCPUs run for %d seconds.\n",

View File

@ -894,8 +894,7 @@ int main(int argc, char *argv[])
if (verbose)
printf("Testing shinfo lock corruption (KVM_XEN_HVM_EVTCHN_SEND)\n");
ret = pthread_create(&thread, NULL, &juggle_shinfo_state, (void *)vm);
TEST_ASSERT(ret == 0, "pthread_create() failed: %s", strerror(ret));
kvm_pthread_create(&thread, NULL, &juggle_shinfo_state, (void *)vm);
struct kvm_irq_routing_xen_evtchn uxe = {
.port = 1,