AI Trajectory


Trajectory: (Expand/Collapse All)
Seq Timestamp Type Name Duration
0/0 2026/08/01 07:22 flow patch-triage
0m Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch only modifies userspace KVM selftests (tools/testing/selftests/kvm/*) to use custom pthread wrappers. It does not make any functional changes to the kernel itself.",
  "WorthFuzzing": false
}

1/1 2026/08/01 07:22 action read-patch-diff
0m Args:
null

Results:
{
  "PatchDiff": "commit 5ecc5ac3dfacfb5a33ff75f1df4a9f9562dbd262\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate:   Sat Aug 1 07:22:47 2026 +0000\n\n    syz-cluster: applied patch under review\n\ndiff --git a/tools/testing/selftests/kvm/arch_timer.c b/tools/testing/selftests/kvm/arch_timer.c\nindex f8b02597897bd..03160ad666f58 100644\n--- a/tools/testing/selftests/kvm/arch_timer.c\n+++ b/tools/testing/selftests/kvm/arch_timer.c\n@@ -141,33 +141,27 @@ static void test_run(struct kvm_vm *vm)\n {\n \tpthread_t pt_vcpu_migration;\n \tunsigned int i;\n-\tint ret;\n \n \tpthread_mutex_init(\u0026vcpu_done_map_lock, NULL);\n \tvcpu_done_map = bitmap_zalloc(test_args.nr_vcpus);\n \tTEST_ASSERT(vcpu_done_map, \"Failed to allocate vcpu done bitmap\");\n \n-\tfor (i = 0; i \u003c (unsigned long)test_args.nr_vcpus; i++) {\n-\t\tret = pthread_create(\u0026pt_vcpu_run[i], NULL, test_vcpu_run,\n-\t\t\t\t     (void *)(unsigned long)i);\n-\t\tTEST_ASSERT(!ret, \"Failed to create vCPU-%d pthread\", i);\n-\t}\n+\tfor (i = 0; i \u003c (unsigned long)test_args.nr_vcpus; i++)\n+\t\tkvm_pthread_create(\u0026pt_vcpu_run[i], NULL, test_vcpu_run,\n+\t\t\t\t   (void *)(unsigned long)i);\n \n \t/* Spawn a thread to control the vCPU migrations */\n \tif (test_args.migration_freq_ms) {\n \t\tsrand(time(NULL));\n \n-\t\tret = pthread_create(\u0026pt_vcpu_migration, NULL,\n-\t\t\t\t\ttest_vcpu_migration, NULL);\n-\t\tTEST_ASSERT(!ret, \"Failed to create the migration pthread\");\n+\t\tkvm_pthread_create(\u0026pt_vcpu_migration, NULL, test_vcpu_migration, NULL);\n \t}\n \n-\n \tfor (i = 0; i \u003c test_args.nr_vcpus; i++)\n-\t\tpthread_join(pt_vcpu_run[i], NULL);\n+\t\tkvm_pthread_join(pt_vcpu_run[i], NULL);\n \n \tif (test_args.migration_freq_ms)\n-\t\tpthread_join(pt_vcpu_migration, NULL);\n+\t\tkvm_pthread_join(pt_vcpu_migration, NULL);\n \n \tbitmap_free(vcpu_done_map);\n }\ndiff --git a/tools/testing/selftests/kvm/arm64/vgic_irq.c b/tools/testing/selftests/kvm/arm64/vgic_irq.c\nindex 5e231998617e7..3cb85932ee85c 100644\n--- a/tools/testing/selftests/kvm/arm64/vgic_irq.c\n+++ b/tools/testing/selftests/kvm/arm64/vgic_irq.c\n@@ -988,7 +988,7 @@ static void test_vgic_two_cpus(void *gcode)\n \tstruct test_args args = {};\n \tstruct kvm_vm *vm;\n \tgva_t args_gva;\n-\tint gic_fd, ret;\n+\tint gic_fd;\n \n \tvm = vm_create_with_vcpus(2, gcode, vcpus);\n \n@@ -1004,15 +1004,11 @@ static void test_vgic_two_cpus(void *gcode)\n \n \tgic_fd = vgic_v3_setup(vm, 2, 64);\n \n-\tret = pthread_create(\u0026thr[0], NULL, test_vcpu_run, vcpus[0]);\n-\tif (ret)\n-\t\tTEST_FAIL(\"Can't create thread for vcpu 0 (%d)\\n\", ret);\n-\tret = pthread_create(\u0026thr[1], NULL, test_vcpu_run, vcpus[1]);\n-\tif (ret)\n-\t\tTEST_FAIL(\"Can't create thread for vcpu 1 (%d)\\n\", ret);\n+\tkvm_pthread_create(\u0026thr[0], NULL, test_vcpu_run, vcpus[0]);\n+\tkvm_pthread_create(\u0026thr[1], NULL, test_vcpu_run, vcpus[1]);\n \n-\tpthread_join(thr[0], NULL);\n-\tpthread_join(thr[1], NULL);\n+\tkvm_pthread_join(thr[0], NULL);\n+\tkvm_pthread_join(thr[1], NULL);\n \n \tclose(gic_fd);\n \tkvm_vm_free(vm);\ndiff --git a/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c b/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c\nindex d64d434d3f06e..9a69c439a0f8f 100644\n--- a/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c\n+++ b/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c\n@@ -311,23 +311,23 @@ static void run_test(void)\n \tpthread_barrier_init(\u0026test_setup_barrier, NULL, nr_vcpus + nr_devices + 1);\n \n \tfor (i = 0; i \u003c nr_vcpus; i++)\n-\t\tpthread_create(\u0026vcpu_threads[i], NULL, vcpu_worker_thread, vcpus[i]);\n+\t\tkvm_pthread_create(\u0026vcpu_threads[i], NULL, vcpu_worker_thread, vcpus[i]);\n \n \tfor (i = 0; i \u003c nr_devices; i++)\n-\t\tpthread_create(\u0026lpi_threads[i], NULL, lpi_worker_thread, (void *)i);\n+\t\tkvm_pthread_create(\u0026lpi_threads[i], NULL, lpi_worker_thread, (void *)i);\n \n \tpthread_barrier_wait(\u0026test_setup_barrier);\n \n \tclock_gettime(CLOCK_MONOTONIC, \u0026start);\n \n \tfor (i = 0; i \u003c nr_devices; i++)\n-\t\tpthread_join(lpi_threads[i], NULL);\n+\t\tkvm_pthread_join(lpi_threads[i], NULL);\n \n \tdelta = timespec_elapsed(start);\n \twrite_guest_global(vm, test_data.request_vcpus_stop, true);\n \n \tfor (i = 0; i \u003c nr_vcpus; i++)\n-\t\tpthread_join(vcpu_threads[i], NULL);\n+\t\tkvm_pthread_join(vcpu_threads[i], NULL);\n \n \treport_stats(delta);\n }\ndiff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c\nindex e8419d7da1eab..af5eb0334a74f 100644\n--- a/tools/testing/selftests/kvm/dirty_log_test.c\n+++ b/tools/testing/selftests/kvm/dirty_log_test.c\n@@ -691,7 +691,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)\n \n \tTEST_ASSERT_EQ(vcpu_stop, false);\n \n-\tpthread_create(\u0026vcpu_thread, NULL, vcpu_worker, vcpu);\n+\tkvm_pthread_create(\u0026vcpu_thread, NULL, vcpu_worker, vcpu);\n \n \tfor (iteration = 1; iteration \u003c= p-\u003eiterations; iteration++) {\n \t\tunsigned long i, reap_i;\n@@ -805,7 +805,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)\n \tWRITE_ONCE(host_quit, true);\n \tsem_post(\u0026sem_vcpu_cont);\n \n-\tpthread_join(vcpu_thread, NULL);\n+\tkvm_pthread_join(vcpu_thread, NULL);\n \n \tpr_info(\"Total bits checked: dirty (%lu), clear (%lu)\\n\",\n \t\thost_dirty_count, host_clear_count);\ndiff --git a/tools/testing/selftests/kvm/hardware_disable_test.c b/tools/testing/selftests/kvm/hardware_disable_test.c\nindex 3147f5c97e943..4abad71589899 100644\n--- a/tools/testing/selftests/kvm/hardware_disable_test.c\n+++ b/tools/testing/selftests/kvm/hardware_disable_test.c\n@@ -5,7 +5,6 @@\n  * return notifiers.\n  */\n #include \u003cfcntl.h\u003e\n-#include \u003cpthread.h\u003e\n #include \u003csemaphore.h\u003e\n #include \u003cstdint.h\u003e\n #include \u003cstdlib.h\u003e\n@@ -14,20 +13,23 @@\n \n #include \u003ctest_util.h\u003e\n \n+#include \"kvm_syscalls.h\"\n #include \"kvm_util.h\"\n+#include \"ucall_common.h\"\n \n-#define VCPU_NUM 4\n-#define SLEEPING_THREAD_NUM (1 \u003c\u003c 4)\n-#define FORK_NUM (1ULL \u003c\u003c 9)\n-#define DELAY_US_MAX 2000\n+#define NR_VCPUS\t\t4\n+#define NR_SLEEPERS_PER_VCPU\t16\n+#define NR_ITERATIONS\t\t512\n+#define DELAY_US_MAX\t\t2000\n \n sem_t *sem;\n+static cpu_set_t child_cpu_set;\n \n static void guest_code(void)\n {\n \tfor (;;)\n \t\t;  /* Some busy work */\n-\tprintf(\"Should not be reached.\\n\");\n+\tGUEST_ASSERT(0);\n }\n \n static void *run_vcpu(void *arg)\n@@ -37,84 +39,47 @@ static void *run_vcpu(void *arg)\n \n \tvcpu_run(vcpu);\n \n-\tTEST_ASSERT(false, \"%s: exited with reason %d: %s\",\n-\t\t    __func__, run-\u003eexit_reason,\n-\t\t    exit_reason_str(run-\u003eexit_reason));\n-\tpthread_exit(NULL);\n+\tTEST_FAIL(\"vCPU%d exited with reason %d: %s\",\n+\t\t  vcpu-\u003eid, run-\u003eexit_reason, exit_reason_str(run-\u003eexit_reason));\n }\n \n static void *sleeping_thread(void *arg)\n {\n \tint fd;\n \n-\twhile (true) {\n+\twhile (1) {\n \t\tfd = open(\"/dev/null\", O_RDWR);\n \t\tclose(fd);\n \t}\n-\tTEST_ASSERT(false, \"%s: exited\", __func__);\n-\tpthread_exit(NULL);\n-}\n-\n-static inline void check_create_thread(pthread_t *thread, pthread_attr_t *attr,\n-\t\t\t\t       void *(*f)(void *), void *arg)\n-{\n-\tint r;\n-\n-\tr = pthread_create(thread, attr, f, arg);\n-\tTEST_ASSERT(r == 0, \"%s: failed to create thread\", __func__);\n-}\n-\n-static inline void check_set_affinity(pthread_t thread, cpu_set_t *cpu_set)\n-{\n-\tint r;\n-\n-\tr = pthread_setaffinity_np(thread, sizeof(cpu_set_t), cpu_set);\n-\tTEST_ASSERT(r == 0, \"%s: failed set affinity\", __func__);\n-}\n-\n-static inline void check_join(pthread_t thread, void **retval)\n-{\n-\tint r;\n-\n-\tr = pthread_join(thread, retval);\n-\tTEST_ASSERT(r == 0, \"%s: failed to join thread\", __func__);\n+\tTEST_FAIL(\"%s: exited\", __func__);\n }\n \n static void run_test(u32 run)\n {\n \tstruct kvm_vcpu *vcpu;\n \tstruct kvm_vm *vm;\n-\tcpu_set_t cpu_set;\n-\tpthread_t threads[VCPU_NUM];\n-\tpthread_t throw_away;\n-\tvoid *b;\n+\tpthread_t thread;\n \tu32 i, j;\n \n-\tCPU_ZERO(\u0026cpu_set);\n-\tfor (i = 0; i \u003c VCPU_NUM; i++)\n-\t\tCPU_SET(i, \u0026cpu_set);\n-\n-\tvm = vm_create(VCPU_NUM);\n+\tvm = vm_create(NR_VCPUS);\n \n \tpr_debug(\"%s: [%d] start vcpus\\n\", __func__, run);\n-\tfor (i = 0; i \u003c VCPU_NUM; ++i) {\n+\tfor (i = 0; i \u003c NR_VCPUS; ++i) {\n \t\tvcpu = vm_vcpu_add(vm, i, guest_code);\n \n-\t\tcheck_create_thread(\u0026threads[i], NULL, run_vcpu, vcpu);\n-\t\tcheck_set_affinity(threads[i], \u0026cpu_set);\n+\t\tkvm_pthread_create(\u0026thread, NULL, run_vcpu, vcpu);\n+\t\tkvm_pthread_setaffinity(thread, \u0026child_cpu_set);\n \n-\t\tfor (j = 0; j \u003c SLEEPING_THREAD_NUM; ++j) {\n-\t\t\tcheck_create_thread(\u0026throw_away, NULL, sleeping_thread,\n-\t\t\t\t\t    (void *)NULL);\n-\t\t\tcheck_set_affinity(throw_away, \u0026cpu_set);\n+\t\tfor (j = 0; j \u003c NR_SLEEPERS_PER_VCPU; ++j) {\n+\t\t\tkvm_pthread_create(\u0026thread, NULL, sleeping_thread, (void *)NULL);\n+\t\t\tkvm_pthread_setaffinity(thread, \u0026child_cpu_set);\n \t\t}\n \t}\n \tpr_debug(\"%s: [%d] all threads launched\\n\", __func__, run);\n \tsem_post(sem);\n-\tfor (i = 0; i \u003c VCPU_NUM; ++i)\n-\t\tcheck_join(threads[i], \u0026b);\n-\t/* Should not be reached */\n-\tTEST_ASSERT(false, \"%s: [%d] child escaped the ninja\", __func__, run);\n+\n+\t/* Wait for the parent to SIGKILL this child. */\n+\twhile (1);\n }\n \n void wait_for_child_setup(pid_t pid)\n@@ -147,16 +112,34 @@ void wait_for_child_setup(pid_t pid)\n \t}\n }\n \n+static void setup_child_cpu_set(void)\n+{\n+\tint cpu;\n+\n+\tkvm_sched_getaffinity(0, sizeof(child_cpu_set), \u0026child_cpu_set);\n+\n+\tif (CPU_COUNT(\u0026child_cpu_set) \u003c 2)\n+\t\treturn;\n+\n+\tcpu = pin_task_to_random_cpu(pthread_self(), \u0026child_cpu_set);\n+\tCPU_CLR(cpu, \u0026child_cpu_set);\n+\n+\twhile (CPU_COUNT(\u0026child_cpu_set) \u003e NR_VCPUS)\n+\t\tCPU_CLR(kvm_pick_random_cpu(\u0026child_cpu_set), \u0026child_cpu_set);\n+}\n+\n int main(int argc, char **argv)\n {\n \tu32 i;\n \tint s, r;\n \tpid_t pid;\n \n+\tsetup_child_cpu_set();\n+\n \tsem = sem_open(\"vm_sem\", O_CREAT | O_EXCL, 0644, 0);\n \tsem_unlink(\"vm_sem\");\n \n-\tfor (i = 0; i \u003c FORK_NUM; ++i) {\n+\tfor (i = 0; i \u003c NR_ITERATIONS; ++i) {\n \t\tpid = fork();\n \t\tTEST_ASSERT(pid \u003e= 0, \"%s: unable to fork\", __func__);\n \t\tif (pid == 0)\ndiff --git a/tools/testing/selftests/kvm/include/kvm_syscalls.h b/tools/testing/selftests/kvm/include/kvm_syscalls.h\nindex 5dae6143ddb04..3d82351bef92e 100644\n--- a/tools/testing/selftests/kvm/include/kvm_syscalls.h\n+++ b/tools/testing/selftests/kvm/include/kvm_syscalls.h\n@@ -12,6 +12,7 @@\n #include \u003csys/mman.h\u003e\n #include \u003csys/syscall.h\u003e\n \n+#include \u003cpthread.h\u003e\n #include \u003csched.h\u003e\n #include \u003ctest_util.h\u003e\n \n@@ -96,6 +97,52 @@ __KVM_SYSCALL_DEFINE(ftruncate, 2, unsigned int, fd, off_t, length);\n __KVM_SYSCALL_DEFINE(madvise, 3, void *, addr, size_t, length, int, advice);\n __KVM_SYSCALL_DEFINE(sched_getaffinity, 3, pid_t, pid, size_t, cpusetsize, cpu_set_t *, mask);\n \n+__KVM_SYSCALL_DEFINE(pthread_getaffinity_np, 3, pthread_t, thread,\n+\t\t     size_t, cpusetsize, cpu_set_t *, cpuset);\n+__KVM_SYSCALL_DEFINE(pthread_setaffinity_np, 3, pthread_t, thread,\n+\t\t     size_t, cpusetsize, const cpu_set_t *, cpuset);\n+\n+static inline void kvm_pthread_getaffinity(pthread_t thread, cpu_set_t *cpuset)\n+{\n+\tkvm_pthread_getaffinity_np(thread, sizeof(cpu_set_t), cpuset);\n+}\n+\n+static inline void kvm_pthread_setaffinity(pthread_t thread,\n+\t\t\t\t\t   const cpu_set_t *cpuset)\n+{\n+\tkvm_pthread_setaffinity_np(thread, sizeof(cpu_set_t), cpuset);\n+}\n+\n+typedef void *(*pthread_fn_t)(void *);\n+__KVM_SYSCALL_DEFINE(pthread_create, 4, pthread_t *, thread,\n+\t\t     const pthread_attr_t *, attr, pthread_fn_t, fn, void *, arg);\n+__KVM_SYSCALL_DEFINE(pthread_join, 2, pthread_t, thread, void **, thread_return);\n+__KVM_SYSCALL_DEFINE(pthread_cancel, 1, pthread_t, thread);\n+\n+static inline void __kvm_cancel_join_pthread(pthread_t thread, void **r)\n+{\n+\tkvm_pthread_cancel(thread);\n+\tkvm_pthread_join(thread, r);\n+}\n+\n+static inline void kvm_cancel_join_pthread(pthread_t thread)\n+{\n+\t__kvm_cancel_join_pthread(thread, NULL);\n+}\n+\n+/*\n+ * Cancel+Join a pthread that was configured with PTHREAD_CANCEL_ASYNCHRONOUS\n+ * and is expected to exit only in response to cancellation.\n+ */\n+static inline void kvm_cancel_join_pthread_async(pthread_t thread)\n+{\n+\tvoid *r;\n+\n+\t__kvm_cancel_join_pthread(thread, \u0026r);\n+\tTEST_ASSERT(r == PTHREAD_CANCELED,\n+\t\t    \"expected retval=%p, got %p\", PTHREAD_CANCELED, r);\n+}\n+\n #define kvm_free_fd(fd)\t\t\\\n do {\t\t\t\t\\\n \tkvm_close(fd);\t\t\\\ndiff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h\nindex b39e713c30a46..5a7a455b53875 100644\n--- a/tools/testing/selftests/kvm/include/kvm_util.h\n+++ b/tools/testing/selftests/kvm/include/kvm_util.h\n@@ -1084,6 +1084,8 @@ struct kvm_vcpu *vm_recreate_with_one_vcpu(struct kvm_vm *vm);\n \n void kvm_set_files_rlimit(u32 nr_vcpus);\n \n+int kvm_pick_random_cpu(cpu_set_t *possible_cpus);\n+\n int __pin_task_to_cpu(pthread_t task, int cpu);\n \n static inline void pin_task_to_cpu(pthread_t task, int cpu)\n@@ -1094,7 +1096,14 @@ static inline void pin_task_to_cpu(pthread_t task, int cpu)\n \tTEST_ASSERT(!r, \"Failed to set thread affinity to pCPU '%u'\", cpu);\n }\n \n-void pin_task_to_random_cpu(pthread_t task, cpu_set_t *possible_cpus);\n+static inline int pin_task_to_random_cpu(pthread_t task, cpu_set_t *possible_cpus)\n+{\n+\tint cpu;\n+\n+\tcpu = kvm_pick_random_cpu(possible_cpus);\n+\tpin_task_to_cpu(task, cpu);\n+\treturn cpu;\n+}\n \n static inline int pin_task_to_any_cpu(pthread_t task)\n {\ndiff --git a/tools/testing/selftests/kvm/irq_test.c b/tools/testing/selftests/kvm/irq_test.c\nindex 240f6f0fdbe43..168c52734fef5 100644\n--- a/tools/testing/selftests/kvm/irq_test.c\n+++ b/tools/testing/selftests/kvm/irq_test.c\n@@ -296,7 +296,7 @@ int main(int argc, char **argv)\n \t\tkvm_sched_getaffinity(0, sizeof(available_cpus), \u0026available_cpus);\n \n \tfor (i = 0; i \u003c nr_vcpus; i++)\n-\t\tpthread_create(\u0026vcpu_threads[i], NULL, vcpu_thread_main, vcpus[i]);\n+\t\tkvm_pthread_create(\u0026vcpu_threads[i], NULL, vcpu_thread_main, vcpus[i]);\n \n \tfor (i = 0; i \u003c nr_vcpus; i++) {\n \t\tstruct kvm_vcpu *vcpu = vcpus[i];\n@@ -356,7 +356,7 @@ int main(int argc, char **argv)\n \tWRITE_AND_SYNC_TO_GUEST(vm, done, true);\n \n \tfor (i = 0; i \u003c nr_vcpus; i++)\n-\t\tpthread_join(vcpu_threads[i], NULL);\n+\t\tkvm_pthread_join(vcpu_threads[i], NULL);\n \n \treturn 0;\n }\ndiff --git a/tools/testing/selftests/kvm/irqfd_test.c b/tools/testing/selftests/kvm/irqfd_test.c\nindex 5d7590d018681..ebb2478878de8 100644\n--- a/tools/testing/selftests/kvm/irqfd_test.c\n+++ b/tools/testing/selftests/kvm/irqfd_test.c\n@@ -128,7 +128,7 @@ int main(int argc, char *argv[])\n \n \tclose(__eventfd);\n \n-\tpthread_create(\u0026racing_thread, NULL, secondary_irqfd_juggler, vm2);\n+\tkvm_pthread_create(\u0026racing_thread, NULL, secondary_irqfd_juggler, vm2);\n \n \tfor (i = 0; i \u003c 10000; i++) {\n \t\tWRITE_ONCE(__eventfd, kvm_new_eventfd());\n@@ -139,5 +139,5 @@ int main(int argc, char *argv[])\n \t}\n \n \tWRITE_ONCE(done, true);\n-\tpthread_join(racing_thread, NULL);\n+\tkvm_pthread_join(racing_thread, NULL);\n }\ndiff --git a/tools/testing/selftests/kvm/kvm_page_table_test.c b/tools/testing/selftests/kvm/kvm_page_table_test.c\nindex a910e3abb8c71..974813ea89533 100644\n--- a/tools/testing/selftests/kvm/kvm_page_table_test.c\n+++ b/tools/testing/selftests/kvm/kvm_page_table_test.c\n@@ -364,8 +364,8 @@ static void run_test(enum vm_guest_mode mode, void *arg)\n \t*current_stage = KVM_BEFORE_MAPPINGS;\n \n \tfor (i = 0; i \u003c nr_vcpus; i++)\n-\t\tpthread_create(\u0026vcpu_threads[i], NULL, vcpu_worker,\n-\t\t\t       test_args.vcpus[i]);\n+\t\tkvm_pthread_create(\u0026vcpu_threads[i], NULL, vcpu_worker,\n+\t\t\t\t   test_args.vcpus[i]);\n \n \tvcpus_complete_new_stage(*current_stage);\n \tpr_info(\"Started all vCPUs successfully\\n\");\n@@ -413,7 +413,7 @@ static void run_test(enum vm_guest_mode mode, void *arg)\n \t}\n \n \tfor (i = 0; i \u003c nr_vcpus; i++)\n-\t\tpthread_join(vcpu_threads[i], NULL);\n+\t\tkvm_pthread_join(vcpu_threads[i], NULL);\n \n \tret = sem_destroy(\u0026test_stage_updated);\n \tTEST_ASSERT(ret == 0, \"Error in sem_destroy\");\ndiff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c\nindex 3794575d2ca0c..9ddc047d5c275 100644\n--- a/tools/testing/selftests/kvm/lib/kvm_util.c\n+++ b/tools/testing/selftests/kvm/lib/kvm_util.c\n@@ -668,7 +668,7 @@ void kvm_print_vcpu_pinning_help(void)\n \t       \"     (default: no pinning)\\n\", name, name);\n }\n \n-void pin_task_to_random_cpu(pthread_t task, cpu_set_t *possible_cpus)\n+int kvm_pick_random_cpu(cpu_set_t *possible_cpus)\n {\n \tint target_idx;\n \tint nr_cpus;\n@@ -680,13 +680,11 @@ void pin_task_to_random_cpu(pthread_t task, cpu_set_t *possible_cpus)\n \ttarget_idx = kvm_random_u64(\u0026kvm_rng) % nr_cpus;\n \n \tfor (cpu = 0; cpu \u003c CPU_SETSIZE; cpu++) {\n-\t\tif (CPU_ISSET(cpu, possible_cpus) \u0026\u0026 target_idx-- == 0) {\n-\t\t\tpin_task_to_cpu(task, cpu);\n-\t\t\treturn;\n-\t\t}\n+\t\tif (CPU_ISSET(cpu, possible_cpus) \u0026\u0026 target_idx-- == 0)\n+\t\t\treturn cpu;\n \t}\n-\n \tTEST_FAIL(\"Failed to find random CPU in possible_cpus\");\n+\treturn -1;\n }\n \n void kvm_parse_vcpu_pinning(const char *pcpus_string, u32 vcpu_to_pcpu[],\ndiff --git a/tools/testing/selftests/kvm/lib/memstress.c b/tools/testing/selftests/kvm/lib/memstress.c\nindex 3599b75d97c91..2864562f57b40 100644\n--- a/tools/testing/selftests/kvm/lib/memstress.c\n+++ b/tools/testing/selftests/kvm/lib/memstress.c\n@@ -294,7 +294,7 @@ void memstress_start_vcpu_threads(int nr_vcpus,\n \t\tvcpu-\u003evcpu_idx = i;\n \t\tWRITE_ONCE(vcpu-\u003erunning, false);\n \n-\t\tpthread_create(\u0026vcpu-\u003ethread, NULL, vcpu_thread_main, vcpu);\n+\t\tkvm_pthread_create(\u0026vcpu-\u003ethread, NULL, vcpu_thread_main, vcpu);\n \t}\n \n \tfor (i = 0; i \u003c nr_vcpus; i++) {\n@@ -312,7 +312,7 @@ void memstress_join_vcpu_threads(int nr_vcpus)\n \tWRITE_ONCE(memstress_args.stop_vcpus, true);\n \n \tfor (i = 0; i \u003c nr_vcpus; i++)\n-\t\tpthread_join(vcpu_threads[i].thread, NULL);\n+\t\tkvm_pthread_join(vcpu_threads[i].thread, NULL);\n }\n \n static void toggle_dirty_logging(struct kvm_vm *vm, int slots, bool enable)\ndiff --git a/tools/testing/selftests/kvm/lib/userfaultfd_util.c b/tools/testing/selftests/kvm/lib/userfaultfd_util.c\nindex ef8d76f71f837..f7ce5a6ddcc22 100644\n--- a/tools/testing/selftests/kvm/lib/userfaultfd_util.c\n+++ b/tools/testing/selftests/kvm/lib/userfaultfd_util.c\n@@ -167,8 +167,8 @@ struct uffd_desc *uffd_setup_demand_paging(int uffd_mode, useconds_t delay,\n \t\tuffd_desc-\u003ereader_args[i].handler = handler;\n \t\tuffd_desc-\u003ereader_args[i].pipe = pipes[0];\n \n-\t\tpthread_create(\u0026uffd_desc-\u003ereaders[i], NULL, uffd_handler_thread_fn,\n-\t\t\t       \u0026uffd_desc-\u003ereader_args[i]);\n+\t\tkvm_pthread_create(\u0026uffd_desc-\u003ereaders[i], NULL, uffd_handler_thread_fn,\n+\t\t\t\t   \u0026uffd_desc-\u003ereader_args[i]);\n \n \t\tPER_VCPU_DEBUG(\"Created uffd thread %i for HVA range [%p, %p)\\n\",\n \t\t\t       i, hva, hva + len);\n@@ -187,8 +187,7 @@ void uffd_stop_demand_paging(struct uffd_desc *uffd)\n \t\t\t    \"Unable to write to pipefd %i for uffd_desc %p\", i, uffd);\n \n \tfor (i = 0; i \u003c uffd-\u003enum_readers; ++i)\n-\t\tTEST_ASSERT(!pthread_join(uffd-\u003ereaders[i], NULL),\n-\t\t\t    \"Pthread_join failed on reader %i for uffd_desc %p\", i, uffd);\n+\t\tkvm_pthread_join(uffd-\u003ereaders[i], NULL);\n \n \tclose(uffd-\u003euffd);\n \ndiff --git a/tools/testing/selftests/kvm/memslot_perf_test.c b/tools/testing/selftests/kvm/memslot_perf_test.c\nindex 4d9ad6104a6ed..e1299611be322 100644\n--- a/tools/testing/selftests/kvm/memslot_perf_test.c\n+++ b/tools/testing/selftests/kvm/memslot_perf_test.c\n@@ -366,7 +366,7 @@ static void launch_vm(struct vm_data *data)\n {\n \tpr_info_v(\"Launching the test VM\\n\");\n \n-\tpthread_create(\u0026data-\u003evcpu_thread, NULL, vcpu_worker, data);\n+\tkvm_pthread_create(\u0026data-\u003evcpu_thread, NULL, vcpu_worker, data);\n \n \t/* Ensure the guest thread is spun up. */\n \twait_for_vcpu();\n@@ -381,7 +381,7 @@ static void free_vm(struct vm_data *data)\n \n static void wait_guest_exit(struct vm_data *data)\n {\n-\tpthread_join(data-\u003evcpu_thread, NULL);\n+\tkvm_pthread_join(data-\u003evcpu_thread, NULL);\n }\n \n static void let_guest_run(struct sync_area *sync)\ndiff --git a/tools/testing/selftests/kvm/mmu_stress_test.c b/tools/testing/selftests/kvm/mmu_stress_test.c\nindex 3d5f33a63b2b4..741e343962edf 100644\n--- a/tools/testing/selftests/kvm/mmu_stress_test.c\n+++ b/tools/testing/selftests/kvm/mmu_stress_test.c\n@@ -222,7 +222,7 @@ static pthread_t *spawn_workers(struct kvm_vm *vm, struct kvm_vcpu **vcpus,\n \t\tinfo[i].vcpu = vcpus[i];\n \t\tinfo[i].start_gpa = gpa;\n \t\tinfo[i].end_gpa = gpa + nr_bytes;\n-\t\tpthread_create(\u0026threads[i], NULL, vcpu_worker, \u0026info[i]);\n+\t\tkvm_pthread_create(\u0026threads[i], NULL, vcpu_worker, \u0026info[i]);\n \t}\n \treturn threads;\n }\n@@ -409,7 +409,7 @@ int main(int argc, char *argv[])\n \n \t/* Sanity check that the vCPUs actually ran. */\n \tfor (i = 0; i \u003c nr_vcpus; i++)\n-\t\tpthread_join(threads[i], NULL);\n+\t\tkvm_pthread_join(threads[i], NULL);\n \n \t/*\n \t * Deliberately exit without deleting the remaining memslots or closing\ndiff --git a/tools/testing/selftests/kvm/pre_fault_memory_test.c b/tools/testing/selftests/kvm/pre_fault_memory_test.c\nindex a0fcae3cb7a8b..c57631aab3d38 100644\n--- a/tools/testing/selftests/kvm/pre_fault_memory_test.c\n+++ b/tools/testing/selftests/kvm/pre_fault_memory_test.c\n@@ -84,7 +84,7 @@ static void pre_fault_memory(struct kvm_vcpu *vcpu, u64 base_gpa, u64 offset,\n \t * Concurrently delete (and recreate) the slot to test KVM's handling\n \t * of a racing memslot deletion with prefaulting.\n \t */\n-\tpthread_create(\u0026slot_worker, NULL, delete_slot_worker, \u0026data);\n+\tkvm_pthread_create(\u0026slot_worker, NULL, delete_slot_worker, \u0026data);\n \n \twhile (!READ_ONCE(data.worker_ready))\n \t\tcpu_relax();\n@@ -116,7 +116,7 @@ static void pre_fault_memory(struct kvm_vcpu *vcpu, u64 base_gpa, u64 offset,\n \t\t */\n \t\tif (!slot_recreated) {\n \t\t\tWRITE_ONCE(data.recreate_slot, true);\n-\t\t\tpthread_join(slot_worker, NULL);\n+\t\t\tkvm_pthread_join(slot_worker, NULL);\n \t\t\tslot_recreated = true;\n \n \t\t\t/*\ndiff --git a/tools/testing/selftests/kvm/rseq_test.c b/tools/testing/selftests/kvm/rseq_test.c\nindex 557e393c223b9..df3e5ad1c3939 100644\n--- a/tools/testing/selftests/kvm/rseq_test.c\n+++ b/tools/testing/selftests/kvm/rseq_test.c\n@@ -241,8 +241,8 @@ int main(int argc, char *argv[])\n \t */\n \tvm = vm_create_with_one_vcpu(\u0026vcpu, guest_code);\n \n-\tpthread_create(\u0026migration_thread, NULL, migration_worker,\n-\t\t       (void *)(unsigned long)kvm_gettid());\n+\tkvm_pthread_create(\u0026migration_thread, NULL, migration_worker,\n+\t\t\t   (void *)(unsigned long)kvm_gettid());\n \n \tif (latency \u003e= 0) {\n \t\t/*\n@@ -314,7 +314,7 @@ int main(int argc, char *argv[])\n \t\t    \"  e.g. via cpuidle.off=1 or via -l \u003clatency\u003e, or run with -u to\\n\"\n \t\t    \"  disable this sanity check.\", i);\n \n-\tpthread_join(migration_thread, NULL);\n+\tkvm_pthread_join(migration_thread, NULL);\n \n \tkvm_vm_free(vm);\n \ndiff --git a/tools/testing/selftests/kvm/s390/memop.c b/tools/testing/selftests/kvm/s390/memop.c\nindex 0244848621b34..ce8db96ccf7e2 100644\n--- a/tools/testing/selftests/kvm/s390/memop.c\n+++ b/tools/testing/selftests/kvm/s390/memop.c\n@@ -678,7 +678,7 @@ static void test_cmpxchg_key_concurrent(void)\n \tHOST_SYNC(t.vcpu, STAGE_SKEYS_SET);\n \tprepare_mem12();\n \tMOP(t.vcpu, LOGICAL, WRITE, mem1, max_block, GADDR_V(mem2));\n-\tpthread_create(\u0026thread, NULL, run_guest, \u0026t.vcpu);\n+\tkvm_pthread_create(\u0026thread, NULL, run_guest, \u0026t.vcpu);\n \n \tfor (int i = 0; i \u003c cmpxchg_iter_outer; i++) {\n \t\tdo {\n@@ -701,7 +701,7 @@ static void test_cmpxchg_key_concurrent(void)\n \t\t}\n \t}\n \n-\tpthread_join(thread, NULL);\n+\tkvm_pthread_join(thread, NULL);\n \n \tMOP(t.vcpu, LOGICAL, READ, mem2, max_block, GADDR_V(mem2));\n \tTEST_ASSERT(popcount_eq(*(__uint128_t *)mem1, *(__uint128_t *)mem2),\ndiff --git a/tools/testing/selftests/kvm/set_memory_region_test.c b/tools/testing/selftests/kvm/set_memory_region_test.c\nindex a152ab65c6577..dffe9654f45bd 100644\n--- a/tools/testing/selftests/kvm/set_memory_region_test.c\n+++ b/tools/testing/selftests/kvm/set_memory_region_test.c\n@@ -133,7 +133,7 @@ static struct kvm_vm *spawn_vm(struct kvm_vcpu **vcpu, pthread_t *vcpu_thread,\n \thva = addr_gpa2hva(vm, MEM_REGION_GPA);\n \tmemset(hva, 0, 2 * 4096);\n \n-\tpthread_create(vcpu_thread, NULL, vcpu_worker, *vcpu);\n+\tkvm_pthread_create(vcpu_thread, NULL, vcpu_worker, *vcpu);\n \n \t/* Ensure the guest thread is spun up. */\n \twait_for_vcpu();\n@@ -216,7 +216,7 @@ static void test_move_memory_region(bool disable_slot_zap_quirk)\n \t/* Defered sync from when the memslot was misaligned (above). */\n \twait_for_vcpu();\n \n-\tpthread_join(vcpu_thread, NULL);\n+\tkvm_pthread_join(vcpu_thread, NULL);\n \n \tkvm_vm_free(vm);\n }\n@@ -302,7 +302,7 @@ static void test_delete_memory_region(bool disable_slot_zap_quirk)\n \t */\n \tvm_mem_region_delete(vm, 0);\n \n-\tpthread_join(vcpu_thread, NULL);\n+\tkvm_pthread_join(vcpu_thread, NULL);\n \n \trun = vcpu-\u003erun;\n \ndiff --git a/tools/testing/selftests/kvm/steal_time.c b/tools/testing/selftests/kvm/steal_time.c\nindex 0b88c743ee7d5..bc3c62b72c58c 100644\n--- a/tools/testing/selftests/kvm/steal_time.c\n+++ b/tools/testing/selftests/kvm/steal_time.c\n@@ -548,15 +548,15 @@ int main(int ac, char **av)\n \n \t\t/* Steal time from the VCPU. The steal time thread has the same CPU affinity as the VCPUs. */\n \t\trun_delay = get_run_delay();\n-\t\tpthread_create(\u0026thread, NULL, do_steal_time, NULL);\n-\t\tpthread_getaffinity_np(thread, sizeof(cpuset), \u0026cpuset);\n+\t\tkvm_pthread_create(\u0026thread, NULL, do_steal_time, NULL);\n+\t\tkvm_pthread_getaffinity(thread, \u0026cpuset);\n \t\tTEST_ASSERT(CPU_COUNT(\u0026cpuset) == 1 \u0026\u0026 CPU_ISSET(cpu, \u0026cpuset),\n \t\t\t    \"Worker failed to inherit parent's CPU affinity\");\n \n \t\tdo\n \t\t\tsched_yield();\n \t\twhile (get_run_delay() - run_delay \u003c MIN_RUN_DELAY_NS);\n-\t\tpthread_join(thread, NULL);\n+\t\tkvm_pthread_join(thread, NULL);\n \t\trun_delay = get_run_delay() - run_delay;\n \t\tTEST_ASSERT(run_delay \u003e= MIN_RUN_DELAY_NS,\n \t\t\t    \"Expected run_delay \u003e= %ld, got %ld\",\ndiff --git a/tools/testing/selftests/kvm/x86/hyperv_ipi.c b/tools/testing/selftests/kvm/x86/hyperv_ipi.c\nindex 771535f9aad3c..fe38cc4cba051 100644\n--- a/tools/testing/selftests/kvm/x86/hyperv_ipi.c\n+++ b/tools/testing/selftests/kvm/x86/hyperv_ipi.c\n@@ -222,30 +222,13 @@ static void *vcpu_thread(void *arg)\n \treturn NULL;\n }\n \n-static void cancel_join_vcpu_thread(pthread_t thread, struct kvm_vcpu *vcpu)\n-{\n-\tvoid *retval;\n-\tint r;\n-\n-\tr = pthread_cancel(thread);\n-\tTEST_ASSERT(!r, \"pthread_cancel on vcpu_id=%d failed with errno=%d\",\n-\t\t    vcpu-\u003eid, r);\n-\n-\tr = pthread_join(thread, \u0026retval);\n-\tTEST_ASSERT(!r, \"pthread_join on vcpu_id=%d failed with errno=%d\",\n-\t\t    vcpu-\u003eid, r);\n-\tTEST_ASSERT(retval == PTHREAD_CANCELED,\n-\t\t    \"expected retval=%p, got %p\", PTHREAD_CANCELED,\n-\t\t    retval);\n-}\n-\n int main(int argc, char *argv[])\n {\n \tstruct kvm_vm *vm;\n \tstruct kvm_vcpu *vcpu[3];\n \tgva_t hcall_page;\n \tpthread_t threads[2];\n-\tint stage = 1, r;\n+\tint stage = 1;\n \tstruct ucall uc;\n \n \tTEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_SEND_IPI));\n@@ -272,11 +255,8 @@ int main(int argc, char *argv[])\n \tvcpu_args_set(vcpu[0], 2, hcall_page, addr_gva2gpa(vm, hcall_page));\n \tvcpu_set_hv_cpuid(vcpu[0]);\n \n-\tr = pthread_create(\u0026threads[0], NULL, vcpu_thread, vcpu[1]);\n-\tTEST_ASSERT(!r, \"pthread_create failed errno=%d\", r);\n-\n-\tr = pthread_create(\u0026threads[1], NULL, vcpu_thread, vcpu[2]);\n-\tTEST_ASSERT(!r, \"pthread_create failed errno=%d\", errno);\n+\tkvm_pthread_create(\u0026threads[0], NULL, vcpu_thread, vcpu[1]);\n+\tkvm_pthread_create(\u0026threads[1], NULL, vcpu_thread, vcpu[2]);\n \n \twhile (true) {\n \t\tvcpu_run(vcpu[0]);\n@@ -302,9 +282,9 @@ int main(int argc, char *argv[])\n \t}\n \n done:\n-\tcancel_join_vcpu_thread(threads[0], vcpu[1]);\n-\tcancel_join_vcpu_thread(threads[1], vcpu[2]);\n+\tkvm_cancel_join_pthread_async(threads[0]);\n+\tkvm_cancel_join_pthread_async(threads[1]);\n \tkvm_vm_free(vm);\n \n-\treturn r;\n+\treturn 0;\n }\ndiff --git a/tools/testing/selftests/kvm/x86/hyperv_tlb_flush.c b/tools/testing/selftests/kvm/x86/hyperv_tlb_flush.c\nindex b4be9a175379f..84f22f39c8f21 100644\n--- a/tools/testing/selftests/kvm/x86/hyperv_tlb_flush.c\n+++ b/tools/testing/selftests/kvm/x86/hyperv_tlb_flush.c\n@@ -548,23 +548,6 @@ static void *vcpu_thread(void *arg)\n \treturn NULL;\n }\n \n-static void cancel_join_vcpu_thread(pthread_t thread, struct kvm_vcpu *vcpu)\n-{\n-\tvoid *retval;\n-\tint r;\n-\n-\tr = pthread_cancel(thread);\n-\tTEST_ASSERT(!r, \"pthread_cancel on vcpu_id=%d failed with errno=%d\",\n-\t\t    vcpu-\u003eid, r);\n-\n-\tr = pthread_join(thread, \u0026retval);\n-\tTEST_ASSERT(!r, \"pthread_join on vcpu_id=%d failed with errno=%d\",\n-\t\t    vcpu-\u003eid, r);\n-\tTEST_ASSERT(retval == PTHREAD_CANCELED,\n-\t\t    \"expected retval=%p, got %p\", PTHREAD_CANCELED,\n-\t\t    retval);\n-}\n-\n int main(int argc, char *argv[])\n {\n \tstruct kvm_vm *vm;\n@@ -575,7 +558,7 @@ int main(int argc, char *argv[])\n \tu64 *pte;\n \tstruct test_data *data;\n \tstruct ucall uc;\n-\tint stage = 1, r, i;\n+\tint stage = 1, i;\n \n \tTEST_REQUIRE(kvm_has_cap(KVM_CAP_HYPERV_TLBFLUSH));\n \n@@ -632,11 +615,8 @@ int main(int argc, char *argv[])\n \tvcpu_set_msr(vcpu[2], HV_X64_MSR_VP_INDEX, WORKER_VCPU_ID_2);\n \tvcpu_set_hv_cpuid(vcpu[2]);\n \n-\tr = pthread_create(\u0026threads[0], NULL, vcpu_thread, vcpu[1]);\n-\tTEST_ASSERT(!r, \"pthread_create() failed\");\n-\n-\tr = pthread_create(\u0026threads[1], NULL, vcpu_thread, vcpu[2]);\n-\tTEST_ASSERT(!r, \"pthread_create() failed\");\n+\tkvm_pthread_create(\u0026threads[0], NULL, vcpu_thread, vcpu[1]);\n+\tkvm_pthread_create(\u0026threads[1], NULL, vcpu_thread, vcpu[2]);\n \n \twhile (true) {\n \t\tvcpu_run(vcpu[0]);\n@@ -661,8 +641,8 @@ int main(int argc, char *argv[])\n \t}\n \n done:\n-\tcancel_join_vcpu_thread(threads[0], vcpu[1]);\n-\tcancel_join_vcpu_thread(threads[1], vcpu[2]);\n+\tkvm_cancel_join_pthread_async(threads[0]);\n+\tkvm_cancel_join_pthread_async(threads[1]);\n \tkvm_vm_free(vm);\n \n \treturn 0;\ndiff --git a/tools/testing/selftests/kvm/x86/private_mem_conversions_test.c b/tools/testing/selftests/kvm/x86/private_mem_conversions_test.c\nindex 1d2f5d4fd45d7..3aa0673f79f33 100644\n--- a/tools/testing/selftests/kvm/x86/private_mem_conversions_test.c\n+++ b/tools/testing/selftests/kvm/x86/private_mem_conversions_test.c\n@@ -412,13 +412,13 @@ static void test_mem_conversions(enum vm_mem_backing_src_type src_type, u32 nr_v\n \t\t */\n \t\tvirt_map(vm, gpa, gpa, PER_CPU_DATA_SIZE / vm-\u003epage_size);\n \n-\t\tpthread_create(\u0026threads[i], NULL, __test_mem_conversions, vcpus[i]);\n+\t\tkvm_pthread_create(\u0026threads[i], NULL, __test_mem_conversions, vcpus[i]);\n \t}\n \n \tWRITE_ONCE(run_vcpus, true);\n \n \tfor (i = 0; i \u003c nr_vcpus; i++)\n-\t\tpthread_join(threads[i], NULL);\n+\t\tkvm_pthread_join(threads[i], NULL);\n \n \tkvm_vm_free(vm);\n \ndiff --git a/tools/testing/selftests/kvm/x86/private_mem_kvm_exits_test.c b/tools/testing/selftests/kvm/x86/private_mem_kvm_exits_test.c\nindex 10db9fe6d9063..e6d16e9d61200 100644\n--- a/tools/testing/selftests/kvm/x86/private_mem_kvm_exits_test.c\n+++ b/tools/testing/selftests/kvm/x86/private_mem_kvm_exits_test.c\n@@ -65,13 +65,12 @@ static void test_private_access_memslot_deleted(void)\n \t/* Request to access page privately */\n \tvm_mem_set_private(vm, EXITS_TEST_GPA, EXITS_TEST_SIZE);\n \n-\tpthread_create(\u0026vm_thread, NULL,\n-\t\t       (void *(*)(void *))run_vcpu_get_exit_reason,\n-\t\t       (void *)vcpu);\n+\tkvm_pthread_create(\u0026vm_thread, NULL,\n+\t\t\t   (pthread_fn_t)run_vcpu_get_exit_reason, (void *)vcpu);\n \n \tvm_mem_region_delete(vm, EXITS_TEST_SLOT);\n \n-\tpthread_join(vm_thread, \u0026thread_return);\n+\tkvm_pthread_join(vm_thread, \u0026thread_return);\n \texit_reason = (u32)(u64)thread_return;\n \n \tTEST_ASSERT_EQ(exit_reason, KVM_EXIT_MEMORY_FAULT);\ndiff --git a/tools/testing/selftests/kvm/x86/recalc_apic_map_test.c b/tools/testing/selftests/kvm/x86/recalc_apic_map_test.c\nindex cbc92a862ea9c..7a0bd9f7ba6c9 100644\n--- a/tools/testing/selftests/kvm/x86/recalc_apic_map_test.c\n+++ b/tools/testing/selftests/kvm/x86/recalc_apic_map_test.c\n@@ -57,7 +57,7 @@ int main(void)\n \tfor (i = 0; i \u003c KVM_MAX_VCPUS; i++)\n \t\tvcpu_set_msr(vcpus[i], MSR_IA32_APICBASE, LAPIC_X2APIC);\n \n-\tTEST_ASSERT_EQ(pthread_create(\u0026thread, NULL, race, vcpus[0]), 0);\n+\tkvm_pthread_create(\u0026thread, NULL, race, vcpus[0]);\n \n \tvcpuN = vcpus[KVM_MAX_VCPUS - 1];\n \tfor (t = time(NULL) + TIMEOUT; time(NULL) \u003c t;) {\n@@ -65,8 +65,7 @@ int main(void)\n \t\tvcpu_set_msr(vcpuN, MSR_IA32_APICBASE, LAPIC_DISABLED);\n \t}\n \n-\tTEST_ASSERT_EQ(pthread_cancel(thread), 0);\n-\tTEST_ASSERT_EQ(pthread_join(thread, NULL), 0);\n+\tkvm_cancel_join_pthread(thread);\n \n \tkvm_vm_free(vm);\n \ndiff --git a/tools/testing/selftests/kvm/x86/sev_migrate_tests.c b/tools/testing/selftests/kvm/x86/sev_migrate_tests.c\nindex d59abb198d86f..de006e1c861c1 100644\n--- a/tools/testing/selftests/kvm/x86/sev_migrate_tests.c\n+++ b/tools/testing/selftests/kvm/x86/sev_migrate_tests.c\n@@ -128,10 +128,10 @@ static void test_sev_migrate_locking(void)\n \t\t       sizeof(input[i].source_vms));\n \n \tfor (i = 0; i \u003c NR_LOCK_TESTING_THREADS; ++i)\n-\t\tpthread_create(\u0026pt[i], NULL, locking_test_thread, \u0026input[i]);\n+\t\tkvm_pthread_create(\u0026pt[i], NULL, locking_test_thread, \u0026input[i]);\n \n \tfor (i = 0; i \u003c NR_LOCK_TESTING_THREADS; ++i)\n-\t\tpthread_join(pt[i], NULL);\n+\t\tkvm_pthread_join(pt[i], NULL);\n \tfor (i = 0; i \u003c NR_LOCK_TESTING_THREADS; ++i)\n \t\tkvm_vm_free(input[i].vm);\n }\ndiff --git a/tools/testing/selftests/kvm/x86/sync_regs_test.c b/tools/testing/selftests/kvm/x86/sync_regs_test.c\nindex 5b0c2359bbb43..9d76c2ed784b6 100644\n--- a/tools/testing/selftests/kvm/x86/sync_regs_test.c\n+++ b/tools/testing/selftests/kvm/x86/sync_regs_test.c\n@@ -181,7 +181,7 @@ static void race_sync_regs(struct kvm_vcpu *vcpu, void *racer)\n \t\t    !!(run-\u003es.regs.sregs.cr4 \u0026 X86_CR4_PAE),\n \t\t    !!(run-\u003es.regs.sregs.efer \u0026 EFER_LME));\n \n-\tTEST_ASSERT_EQ(pthread_create(\u0026thread, NULL, racer, (void *)run), 0);\n+\tkvm_pthread_create(\u0026thread, NULL, racer, (void *)run);\n \n \tfor (t = time(NULL) + TIMEOUT; time(NULL) \u003c t;) {\n \t\t/*\n@@ -199,8 +199,7 @@ static void race_sync_regs(struct kvm_vcpu *vcpu, void *racer)\n \t\t}\n \t}\n \n-\tTEST_ASSERT_EQ(pthread_cancel(thread), 0);\n-\tTEST_ASSERT_EQ(pthread_join(thread, NULL), 0);\n+\tkvm_cancel_join_pthread(thread);\n \n \tkvm_x86_state_cleanup(state);\n }\ndiff --git a/tools/testing/selftests/kvm/x86/tsc_scaling_sync.c b/tools/testing/selftests/kvm/x86/tsc_scaling_sync.c\nindex 59da8d4da6079..2a3a9bd8b338a 100644\n--- a/tools/testing/selftests/kvm/x86/tsc_scaling_sync.c\n+++ b/tools/testing/selftests/kvm/x86/tsc_scaling_sync.c\n@@ -94,12 +94,12 @@ int main(int argc, char *argv[])\n \tpthread_t cpu_threads[NR_TEST_VCPUS];\n \tunsigned long cpu;\n \tfor (cpu = 0; cpu \u003c NR_TEST_VCPUS; cpu++)\n-\t\tpthread_create(\u0026cpu_threads[cpu], NULL, run_vcpu, (void *)cpu);\n+\t\tkvm_pthread_create(\u0026cpu_threads[cpu], NULL, run_vcpu, (void *)cpu);\n \n \tunsigned long failures = 0;\n \tfor (cpu = 0; cpu \u003c NR_TEST_VCPUS; cpu++) {\n \t\tvoid *this_cpu_failures;\n-\t\tpthread_join(cpu_threads[cpu], \u0026this_cpu_failures);\n+\t\tkvm_pthread_join(cpu_threads[cpu], \u0026this_cpu_failures);\n \t\tfailures += (unsigned long)this_cpu_failures;\n \t}\n \ndiff --git a/tools/testing/selftests/kvm/x86/xapic_ipi_test.c b/tools/testing/selftests/kvm/x86/xapic_ipi_test.c\nindex 3a326c5e74cab..78e7aae8fab8d 100644\n--- a/tools/testing/selftests/kvm/x86/xapic_ipi_test.c\n+++ b/tools/testing/selftests/kvm/x86/xapic_ipi_test.c\n@@ -228,25 +228,6 @@ static void *vcpu_thread(void *arg)\n \treturn NULL;\n }\n \n-static void cancel_join_vcpu_thread(pthread_t thread, struct kvm_vcpu *vcpu)\n-{\n-\tvoid *retval;\n-\tint r;\n-\n-\tr = pthread_cancel(thread);\n-\tTEST_ASSERT(r == 0,\n-\t\t    \"pthread_cancel on vcpu_id=%d failed with errno=%d\",\n-\t\t    vcpu-\u003eid, r);\n-\n-\tr = pthread_join(thread, \u0026retval);\n-\tTEST_ASSERT(r == 0,\n-\t\t    \"pthread_join on vcpu_id=%d failed with errno=%d\",\n-\t\t    vcpu-\u003eid, r);\n-\tTEST_ASSERT(retval == PTHREAD_CANCELED,\n-\t\t    \"expected retval=%p, got %p\", PTHREAD_CANCELED,\n-\t\t    retval);\n-}\n-\n void do_migrations(struct test_data_page *data, int run_secs, int delay_usecs,\n \t\t   u64 *pipis_rcvd)\n {\n@@ -387,7 +368,6 @@ void get_cmdline_args(int argc, char *argv[], int *run_secs,\n \n int main(int argc, char *argv[])\n {\n-\tint r;\n \tint wait_secs;\n \tconst int max_halter_wait = 10;\n \tint run_secs = 0;\n@@ -428,9 +408,7 @@ int main(int argc, char *argv[])\n \tparams[1].pipis_rcvd = pipis_rcvd;\n \n \t/* Start halter vCPU thread and wait for it to execute first HLT. */\n-\tr = pthread_create(\u0026threads[0], NULL, vcpu_thread, \u0026params[0]);\n-\tTEST_ASSERT(r == 0,\n-\t\t    \"pthread_create halter failed errno=%d\", errno);\n+\tkvm_pthread_create(\u0026threads[0], NULL, vcpu_thread, \u0026params[0]);\n \tfprintf(stderr, \"Halter vCPU thread started\\n\");\n \n \twait_secs = 0;\n@@ -447,8 +425,7 @@ int main(int argc, char *argv[])\n \t\t\"Halter vCPU thread reported its APIC ID: %u after %d seconds.\\n\",\n \t\tdata-\u003ehalter_apic_id, wait_secs);\n \n-\tr = pthread_create(\u0026threads[1], NULL, vcpu_thread, \u0026params[1]);\n-\tTEST_ASSERT(r == 0, \"pthread_create sender failed errno=%d\", errno);\n+\tkvm_pthread_create(\u0026threads[1], NULL, vcpu_thread, \u0026params[1]);\n \n \tfprintf(stderr,\n \t\t\"IPI sender vCPU thread started. Letting vCPUs run for %d seconds.\\n\",\n@@ -462,8 +439,8 @@ int main(int argc, char *argv[])\n \t/*\n \t * Cancel threads and wait for them to stop.\n \t */\n-\tcancel_join_vcpu_thread(threads[0], params[0].vcpu);\n-\tcancel_join_vcpu_thread(threads[1], params[1].vcpu);\n+\tkvm_cancel_join_pthread_async(threads[0]);\n+\tkvm_cancel_join_pthread_async(threads[1]);\n \n \t/*\n \t * If the host support Idle HLT, i.e. KVM *might* be using Idle HLT,\ndiff --git a/tools/testing/selftests/kvm/x86/xen_shinfo_test.c b/tools/testing/selftests/kvm/x86/xen_shinfo_test.c\nindex 5076f6a754557..a226a2fd61d94 100644\n--- a/tools/testing/selftests/kvm/x86/xen_shinfo_test.c\n+++ b/tools/testing/selftests/kvm/x86/xen_shinfo_test.c\n@@ -437,7 +437,6 @@ int main(int argc, char *argv[])\n \tstruct kvm_vm *vm;\n \tpthread_t thread;\n \tbool verbose;\n-\tint ret;\n \n \tverbose = argc \u003e 1 \u0026\u0026 (!strncmp(argv[1], \"-v\", 3) ||\n \t\t\t       !strncmp(argv[1], \"--verbose\", 10));\n@@ -894,8 +893,7 @@ int main(int argc, char *argv[])\n \t\t\t\tif (verbose)\n \t\t\t\t\tprintf(\"Testing shinfo lock corruption (KVM_XEN_HVM_EVTCHN_SEND)\\n\");\n \n-\t\t\t\tret = pthread_create(\u0026thread, NULL, \u0026juggle_shinfo_state, (void *)vm);\n-\t\t\t\tTEST_ASSERT(ret == 0, \"pthread_create() failed: %s\", strerror(ret));\n+\t\t\t\tkvm_pthread_create(\u0026thread, NULL, \u0026juggle_shinfo_state, (void *)vm);\n \n \t\t\t\tstruct kvm_irq_routing_xen_evtchn uxe = {\n \t\t\t\t\t.port = 1,\n@@ -949,11 +947,7 @@ int main(int argc, char *argv[])\n \t\t\t\tTEST_ASSERT(!evtchn_irq_expected,\n \t\t\t\t\t    \"Expected event channel IRQ but it didn't happen\");\n \n-\t\t\t\tret = pthread_cancel(thread);\n-\t\t\t\tTEST_ASSERT(ret == 0, \"pthread_cancel() failed: %s\", strerror(ret));\n-\n-\t\t\t\tret = pthread_join(thread, 0);\n-\t\t\t\tTEST_ASSERT(ret == 0, \"pthread_join() failed: %s\", strerror(ret));\n+\t\t\t\tkvm_cancel_join_pthread(thread);\n \t\t\t\tgoto done;\n \n \t\t\tcase TEST_GUEST_SAW_IRQ:\n"
}

2/1 2026/08/01 07:22 agent patch-evaluator
0m Model:
best-expensive

Args:
null

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch only modifies userspace KVM selftests (tools/testing/selftests/kvm/*) to use custom pthread wrappers. It does not make any functional changes to the kernel itself.",
  "WorthFuzzing": false
}

Instruction:
You are an expert Linux kernel maintainer.
Your job is to review a provided patch series and determine
if it makes functional changes to the kernel that should be fuzzed.

IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on your internal knowledge of the kernel. You must actively
use your code access tools to examine the actual source code and confirm any assumptions.

Return WorthFuzzing=false if the patch only contains:
- Modifications to Documentation/, Kconfig files, or code comments.
- Purely decorative changes, such as logging (e.g., pr_err, printk) or tracepoints.
- Changes to numeric constants or macros that do not functionally alter execution flow.
- Code paths that are impossible to reach in virtualized environments like GCE or QEMU,
  even when utilizing software-emulated hardware (e.g., usb gadget, mac80211_hwsim).
- Code in vendor-specific PCIe switch, SmartNIC, or GPU drivers (e.g., mlxsw, pds_core, qed,
  ionic, amdgpu) that require physical PCIe hardware cards not emulated in standard QEMU.
- Driver .remove, .shutdown, or pci_unregister_driver teardown callbacks (e.g., igb_remove)
  that are executed only during PCI hot-unplug or sysfs driver unbind operations.

If it modifies reachable core kernel logic, drivers, or architectures, use your code search
tools to verify the code can be executed, then return WorthFuzzing=true.

When returning WorthFuzzing=true, you MUST ALSO:
1. Extract any specific kernel functions that should be heavily fuzzed into FocusSymbols.
   Avoid listing generic hot-path functions to prevent skewed test distributions.
   Prefer non-static, non-inlined API entrypoint functions over internal static helper functions
   (which are inlined by the compiler and do not have distinct symbol addresses).
2. Identify any specific CONFIG_ options required to properly test this new/modified feature.
   Go and look into the Kconfig files and check for ifdefs around the code, do not make assumptions.
   Also check "depends on" lines in Kconfig to include any non-standard parent subsystem configs
   needed for Kbuild to compile the code statically into vmlinux. List them in the EnableConfigs
   output array, and DO NOT add a 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4").
Prefer calling several tools at the same time to save round-trips.


Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.

Prompt:
For your convenience, here is the diff of the changes:
commit 5ecc5ac3dfacfb5a33ff75f1df4a9f9562dbd262
Author: syz-cluster <triage@syzkaller.com>
Date:   Sat Aug 1 07:22:47 2026 +0000

    syz-cluster: applied patch under review

diff --git a/tools/testing/selftests/kvm/arch_timer.c b/tools/testing/selftests/kvm/arch_timer.c
index f8b02597897bd..03160ad666f58 100644
--- a/tools/testing/selftests/kvm/arch_timer.c
+++ b/tools/testing/selftests/kvm/arch_timer.c
@@ -141,33 +141,27 @@ 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);
+		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);
 }
diff --git a/tools/testing/selftests/kvm/arm64/vgic_irq.c b/tools/testing/selftests/kvm/arm64/vgic_irq.c
index 5e231998617e7..3cb85932ee85c 100644
--- a/tools/testing/selftests/kvm/arm64/vgic_irq.c
+++ b/tools/testing/selftests/kvm/arm64/vgic_irq.c
@@ -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,15 +1004,11 @@ 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);
+	kvm_pthread_join(thr[0], NULL);
+	kvm_pthread_join(thr[1], NULL);
 
 	close(gic_fd);
 	kvm_vm_free(vm);
diff --git a/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c b/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c
index d64d434d3f06e..9a69c439a0f8f 100644
--- a/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c
+++ b/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c
@@ -311,23 +311,23 @@ 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);
 
 	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);
 }
diff --git a/tools/testing/selftests/kvm/dirty_log_test.c b/tools/testing/selftests/kvm/dirty_log_test.c
index e8419d7da1eab..af5eb0334a74f 100644
--- a/tools/testing/selftests/kvm/dirty_log_test.c
+++ b/tools/testing/selftests/kvm/dirty_log_test.c
@@ -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;
@@ -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);
diff --git a/tools/testing/selftests/kvm/hardware_disable_test.c b/tools/testing/selftests/kvm/hardware_disable_test.c
index 3147f5c97e943..4abad71589899 100644
--- a/tools/testing/selftests/kvm/hardware_disable_test.c
+++ b/tools/testing/selftests/kvm/hardware_disable_test.c
@@ -5,7 +5,6 @@
  * return notifiers.
  */
 #include <fcntl.h>
-#include <pthread.h>
 #include <semaphore.h>
 #include <stdint.h>
 #include <stdlib.h>
@@ -14,20 +13,23 @@
 
 #include <test_util.h>
 
+#include "kvm_syscalls.h"
 #include "kvm_util.h"
+#include "ucall_common.h"
 
-#define VCPU_NUM 4
-#define SLEEPING_THREAD_NUM (1 << 4)
-#define FORK_NUM (1ULL << 9)
-#define DELAY_US_MAX 2000
+#define NR_VCPUS		4
+#define NR_SLEEPERS_PER_VCPU	16
+#define NR_ITERATIONS		512
+#define DELAY_US_MAX		2000
 
 sem_t *sem;
+static cpu_set_t child_cpu_set;
 
 static void guest_code(void)
 {
 	for (;;)
 		;  /* Some busy work */
-	printf("Should not be reached.\n");
+	GUEST_ASSERT(0);
 }
 
 static void *run_vcpu(void *arg)
@@ -37,84 +39,47 @@ static void *run_vcpu(void *arg)
 
 	vcpu_run(vcpu);
 
-	TEST_ASSERT(false, "%s: exited with reason %d: %s",
-		    __func__, run->exit_reason,
-		    exit_reason_str(run->exit_reason));
-	pthread_exit(NULL);
+	TEST_FAIL("vCPU%d exited with reason %d: %s",
+		  vcpu->id, run->exit_reason, exit_reason_str(run->exit_reason));
 }
 
 static void *sleeping_thread(void *arg)
 {
 	int fd;
 
-	while (true) {
+	while (1) {
 		fd = open("/dev/null", O_RDWR);
 		close(fd);
 	}
-	TEST_ASSERT(false, "%s: exited", __func__);
-	pthread_exit(NULL);
-}
-
-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 inline void check_set_affinity(pthread_t thread, cpu_set_t *cpu_set)
-{
-	int r;
-
-	r = pthread_setaffinity_np(thread, sizeof(cpu_set_t), cpu_set);
-	TEST_ASSERT(r == 0, "%s: failed set affinity", __func__);
-}
-
-static inline void check_join(pthread_t thread, void **retval)
-{
-	int r;
-
-	r = pthread_join(thread, retval);
-	TEST_ASSERT(r == 0, "%s: failed to join thread", __func__);
+	TEST_FAIL("%s: exited", __func__);
 }
 
 static void run_test(u32 run)
 {
 	struct kvm_vcpu *vcpu;
 	struct kvm_vm *vm;
-	cpu_set_t cpu_set;
-	pthread_t threads[VCPU_NUM];
-	pthread_t throw_away;
-	void *b;
+	pthread_t thread;
 	u32 i, j;
 
-	CPU_ZERO(&cpu_set);
-	for (i = 0; i < VCPU_NUM; i++)
-		CPU_SET(i, &cpu_set);
-
-	vm = vm_create(VCPU_NUM);
+	vm = vm_create(NR_VCPUS);
 
 	pr_debug("%s: [%d] start vcpus\n", __func__, run);
-	for (i = 0; i < VCPU_NUM; ++i) {
+	for (i = 0; i < NR_VCPUS; ++i) {
 		vcpu = vm_vcpu_add(vm, i, guest_code);
 
-		check_create_thread(&threads[i], NULL, run_vcpu, vcpu);
-		check_set_affinity(threads[i], &cpu_set);
+		kvm_pthread_create(&thread, NULL, run_vcpu, vcpu);
+		kvm_pthread_setaffinity(thread, &child_cpu_set);
 
-		for (j = 0; j < SLEEPING_THREAD_NUM; ++j) {
-			check_create_thread(&throw_away, NULL, sleeping_thread,
-					    (void *)NULL);
-			check_set_affinity(throw_away, &cpu_set);
+		for (j = 0; j < NR_SLEEPERS_PER_VCPU; ++j) {
+			kvm_pthread_create(&thread, NULL, sleeping_thread, (void *)NULL);
+			kvm_pthread_setaffinity(thread, &child_cpu_set);
 		}
 	}
 	pr_debug("%s: [%d] all threads launched\n", __func__, run);
 	sem_post(sem);
-	for (i = 0; i < VCPU_NUM; ++i)
-		check_join(threads[i], &b);
-	/* Should not be reached */
-	TEST_ASSERT(false, "%s: [%d] child escaped the ninja", __func__, run);
+
+	/* Wait for the parent to SIGKILL this child. */
+	while (1);
 }
 
 void wait_for_child_setup(pid_t pid)
@@ -147,16 +112,34 @@ void wait_for_child_setup(pid_t pid)
 	}
 }
 
+static void setup_child_cpu_set(void)
+{
+	int cpu;
+
+	kvm_sched_getaffinity(0, sizeof(child_cpu_set), &child_cpu_set);
+
+	if (CPU_COUNT(&child_cpu_set) < 2)
+		return;
+
+	cpu = pin_task_to_random_cpu(pthread_self(), &child_cpu_set);
+	CPU_CLR(cpu, &child_cpu_set);
+
+	while (CPU_COUNT(&child_cpu_set) > NR_VCPUS)
+		CPU_CLR(kvm_pick_random_cpu(&child_cpu_set), &child_cpu_set);
+}
+
 int main(int argc, char **argv)
 {
 	u32 i;
 	int s, r;
 	pid_t pid;
 
+	setup_child_cpu_set();
+
 	sem = sem_open("vm_sem", O_CREAT | O_EXCL, 0644, 0);
 	sem_unlink("vm_sem");
 
-	for (i = 0; i < FORK_NUM; ++i) {
+	for (i = 0; i < NR_ITERATIONS; ++i) {
 		pid = fork();
 		TEST_ASSERT(pid >= 0, "%s: unable to fork", __func__);
 		if (pid == 0)
diff --git a/tools/testing/selftests/kvm/include/kvm_syscalls.h b/tools/testing/selftests/kvm/include/kvm_syscalls.h
index 5dae6143ddb04..3d82351bef92e 100644
--- a/tools/testing/selftests/kvm/include/kvm_syscalls.h
+++ b/tools/testing/selftests/kvm/include/kvm_syscalls.h
@@ -12,6 +12,7 @@
 #include <sys/mman.h>
 #include <sys/syscall.h>
 
+#include <pthread.h>
 #include <sched.h>
 #include <test_util.h>
 
@@ -96,6 +97,52 @@ __KVM_SYSCALL_DEFINE(ftruncate, 2, unsigned int, fd, off_t, length);
 __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(pthread_getaffinity_np, 3, pthread_t, thread,
+		     size_t, cpusetsize, cpu_set_t *, cpuset);
+__KVM_SYSCALL_DEFINE(pthread_setaffinity_np, 3, pthread_t, thread,
+		     size_t, cpusetsize, const cpu_set_t *, cpuset);
+
+static inline void kvm_pthread_getaffinity(pthread_t thread, cpu_set_t *cpuset)
+{
+	kvm_pthread_getaffinity_np(thread, sizeof(cpu_set_t), cpuset);
+}
+
+static inline void kvm_pthread_setaffinity(pthread_t thread,
+					   const cpu_set_t *cpuset)
+{
+	kvm_pthread_setaffinity_np(thread, sizeof(cpu_set_t), cpuset);
+}
+
+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);
+
+static inline void __kvm_cancel_join_pthread(pthread_t thread, void **r)
+{
+	kvm_pthread_cancel(thread);
+	kvm_pthread_join(thread, r);
+}
+
+static inline void kvm_cancel_join_pthread(pthread_t thread)
+{
+	__kvm_cancel_join_pthread(thread, NULL);
+}
+
+/*
+ * Cancel+Join a pthread that was configured with PTHREAD_CANCEL_ASYNCHRONOUS
+ * and is expected to exit only in response to cancellation.
+ */
+static inline void kvm_cancel_join_pthread_async(pthread_t thread)
+{
+	void *r;
+
+	__kvm_cancel_join_pthread(thread, &r);
+	TEST_ASSERT(r == PTHREAD_CANCELED,
+		    "expected retval=%p, got %p", PTHREAD_CANCELED, r);
+}
+
 #define kvm_free_fd(fd)		\
 do {				\
 	kvm_close(fd);		\
diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h
index b39e713c30a46..5a7a455b53875 100644
--- a/tools/testing/selftests/kvm/include/kvm_util.h
+++ b/tools/testing/selftests/kvm/include/kvm_util.h
@@ -1084,6 +1084,8 @@ struct kvm_vcpu *vm_recreate_with_one_vcpu(struct kvm_vm *vm);
 
 void kvm_set_files_rlimit(u32 nr_vcpus);
 
+int kvm_pick_random_cpu(cpu_set_t *possible_cpus);
+
 int __pin_task_to_cpu(pthread_t task, int cpu);
 
 static inline void pin_task_to_cpu(pthread_t task, int cpu)
@@ -1094,7 +1096,14 @@ static inline void pin_task_to_cpu(pthread_t task, int cpu)
 	TEST_ASSERT(!r, "Failed to set thread affinity to pCPU '%u'", cpu);
 }
 
-void pin_task_to_random_cpu(pthread_t task, cpu_set_t *possible_cpus);
+static inline int pin_task_to_random_cpu(pthread_t task, cpu_set_t *possible_cpus)
+{
+	int cpu;
+
+	cpu = kvm_pick_random_cpu(possible_cpus);
+	pin_task_to_cpu(task, cpu);
+	return cpu;
+}
 
 static inline int pin_task_to_any_cpu(pthread_t task)
 {
diff --git a/tools/testing/selftests/kvm/irq_test.c b/tools/testing/selftests/kvm/irq_test.c
index 240f6f0fdbe43..168c52734fef5 100644
--- a/tools/testing/selftests/kvm/irq_test.c
+++ b/tools/testing/selftests/kvm/irq_test.c
@@ -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];
@@ -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;
 }
diff --git a/tools/testing/selftests/kvm/irqfd_test.c b/tools/testing/selftests/kvm/irqfd_test.c
index 5d7590d018681..ebb2478878de8 100644
--- a/tools/testing/selftests/kvm/irqfd_test.c
+++ b/tools/testing/selftests/kvm/irqfd_test.c
@@ -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());
@@ -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);
 }
diff --git a/tools/testing/selftests/kvm/kvm_page_table_test.c b/tools/testing/selftests/kvm/kvm_page_table_test.c
index a910e3abb8c71..974813ea89533 100644
--- a/tools/testing/selftests/kvm/kvm_page_table_test.c
+++ b/tools/testing/selftests/kvm/kvm_page_table_test.c
@@ -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");
@@ -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");
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index 3794575d2ca0c..9ddc047d5c275 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -668,7 +668,7 @@ void kvm_print_vcpu_pinning_help(void)
 	       "     (default: no pinning)\n", name, name);
 }
 
-void pin_task_to_random_cpu(pthread_t task, cpu_set_t *possible_cpus)
+int kvm_pick_random_cpu(cpu_set_t *possible_cpus)
 {
 	int target_idx;
 	int nr_cpus;
@@ -680,13 +680,11 @@ void pin_task_to_random_cpu(pthread_t task, cpu_set_t *possible_cpus)
 	target_idx = kvm_random_u64(&kvm_rng) % nr_cpus;
 
 	for (cpu = 0; cpu < CPU_SETSIZE; cpu++) {
-		if (CPU_ISSET(cpu, possible_cpus) && target_idx-- == 0) {
-			pin_task_to_cpu(task, cpu);
-			return;
-		}
+		if (CPU_ISSET(cpu, possible_cpus) && target_idx-- == 0)
+			return cpu;
 	}
-
 	TEST_FAIL("Failed to find random CPU in possible_cpus");
+	return -1;
 }
 
 void kvm_parse_vcpu_pinning(const char *pcpus_string, u32 vcpu_to_pcpu[],
diff --git a/tools/testing/selftests/kvm/lib/memstress.c b/tools/testing/selftests/kvm/lib/memstress.c
index 3599b75d97c91..2864562f57b40 100644
--- a/tools/testing/selftests/kvm/lib/memstress.c
+++ b/tools/testing/selftests/kvm/lib/memstress.c
@@ -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++) {
@@ -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)
diff --git a/tools/testing/selftests/kvm/lib/userfaultfd_util.c b/tools/testing/selftests/kvm/lib/userfaultfd_util.c
index ef8d76f71f837..f7ce5a6ddcc22 100644
--- a/tools/testing/selftests/kvm/lib/userfaultfd_util.c
+++ b/tools/testing/selftests/kvm/lib/userfaultfd_util.c
@@ -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);
@@ -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);
 
diff --git a/tools/testing/selftests/kvm/memslot_perf_test.c b/tools/testing/selftests/kvm/memslot_perf_test.c
index 4d9ad6104a6ed..e1299611be322 100644
--- a/tools/testing/selftests/kvm/memslot_perf_test.c
+++ b/tools/testing/selftests/kvm/memslot_perf_test.c
@@ -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();
@@ -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)
diff --git a/tools/testing/selftests/kvm/mmu_stress_test.c b/tools/testing/selftests/kvm/mmu_stress_test.c
index 3d5f33a63b2b4..741e343962edf 100644
--- a/tools/testing/selftests/kvm/mmu_stress_test.c
+++ b/tools/testing/selftests/kvm/mmu_stress_test.c
@@ -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;
 }
@@ -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
diff --git a/tools/testing/selftests/kvm/pre_fault_memory_test.c b/tools/testing/selftests/kvm/pre_fault_memory_test.c
index a0fcae3cb7a8b..c57631aab3d38 100644
--- a/tools/testing/selftests/kvm/pre_fault_memory_test.c
+++ b/tools/testing/selftests/kvm/pre_fault_memory_test.c
@@ -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();
@@ -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;
 
 			/*
diff --git a/tools/testing/selftests/kvm/rseq_test.c b/tools/testing/selftests/kvm/rseq_test.c
index 557e393c223b9..df3e5ad1c3939 100644
--- a/tools/testing/selftests/kvm/rseq_test.c
+++ b/tools/testing/selftests/kvm/rseq_test.c
@@ -241,8 +241,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) {
 		/*
@@ -314,7 +314,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);
 
diff --git a/tools/testing/selftests/kvm/s390/memop.c b/tools/testing/selftests/kvm/s390/memop.c
index 0244848621b34..ce8db96ccf7e2 100644
--- a/tools/testing/selftests/kvm/s390/memop.c
+++ b/tools/testing/selftests/kvm/s390/memop.c
@@ -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 {
@@ -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),
diff --git a/tools/testing/selftests/kvm/set_memory_region_test.c b/tools/testing/selftests/kvm/set_memory_region_test.c
index a152ab65c6577..dffe9654f45bd 100644
--- a/tools/testing/selftests/kvm/set_memory_region_test.c
+++ b/tools/testing/selftests/kvm/set_memory_region_test.c
@@ -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();
@@ -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;
 
diff --git a/tools/testing/selftests/kvm/steal_time.c b/tools/testing/selftests/kvm/steal_time.c
index 0b88c743ee7d5..bc3c62b72c58c 100644
--- a/tools/testing/selftests/kvm/steal_time.c
+++ b/tools/testing/selftests/kvm/steal_time.c
@@ -548,15 +548,15 @@ 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, NULL, do_steal_time, NULL);
-		pthread_getaffinity_np(thread, sizeof(cpuset), &cpuset);
+		kvm_pthread_create(&thread, NULL, do_steal_time, NULL);
+		kvm_pthread_getaffinity(thread, &cpuset);
 		TEST_ASSERT(CPU_COUNT(&cpuset) == 1 && CPU_ISSET(cpu, &cpuset),
 			    "Worker failed to inherit parent's CPU affinity");
 
 		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",
diff --git a/tools/testing/selftests/kvm/x86/hyperv_ipi.c b/tools/testing/selftests/kvm/x86/hyperv_ipi.c
index 771535f9aad3c..fe38cc4cba051 100644
--- a/tools/testing/selftests/kvm/x86/hyperv_ipi.c
+++ b/tools/testing/selftests/kvm/x86/hyperv_ipi.c
@@ -222,30 +222,13 @@ static void *vcpu_thread(void *arg)
 	return NULL;
 }
 
-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);
-	TEST_ASSERT(retval == PTHREAD_CANCELED,
-		    "expected retval=%p, got %p", PTHREAD_CANCELED,
-		    retval);
-}
-
 int main(int argc, char *argv[])
 {
 	struct kvm_vm *vm;
 	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 +255,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]);
@@ -302,9 +282,9 @@ int main(int argc, char *argv[])
 	}
 
 done:
-	cancel_join_vcpu_thread(threads[0], vcpu[1]);
-	cancel_join_vcpu_thread(threads[1], vcpu[2]);
+	kvm_cancel_join_pthread_async(threads[0]);
+	kvm_cancel_join_pthread_async(threads[1]);
 	kvm_vm_free(vm);
 
-	return r;
+	return 0;
 }
diff --git a/tools/testing/selftests/kvm/x86/hyperv_tlb_flush.c b/tools/testing/selftests/kvm/x86/hyperv_tlb_flush.c
index b4be9a175379f..84f22f39c8f21 100644
--- a/tools/testing/selftests/kvm/x86/hyperv_tlb_flush.c
+++ b/tools/testing/selftests/kvm/x86/hyperv_tlb_flush.c
@@ -548,23 +548,6 @@ static void *vcpu_thread(void *arg)
 	return NULL;
 }
 
-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);
-	TEST_ASSERT(retval == PTHREAD_CANCELED,
-		    "expected retval=%p, got %p", PTHREAD_CANCELED,
-		    retval);
-}
-
 int main(int argc, char *argv[])
 {
 	struct kvm_vm *vm;
@@ -575,7 +558,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 +615,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]);
@@ -661,8 +641,8 @@ int main(int argc, char *argv[])
 	}
 
 done:
-	cancel_join_vcpu_thread(threads[0], vcpu[1]);
-	cancel_join_vcpu_thread(threads[1], vcpu[2]);
+	kvm_cancel_join_pthread_async(threads[0]);
+	kvm_cancel_join_pthread_async(threads[1]);
 	kvm_vm_free(vm);
 
 	return 0;
diff --git a/tools/testing/selftests/kvm/x86/private_mem_conversions_test.c b/tools/testing/selftests/kvm/x86/private_mem_conversions_test.c
index 1d2f5d4fd45d7..3aa0673f79f33 100644
--- a/tools/testing/selftests/kvm/x86/private_mem_conversions_test.c
+++ b/tools/testing/selftests/kvm/x86/private_mem_conversions_test.c
@@ -412,13 +412,13 @@ 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);
 
 	for (i = 0; i < nr_vcpus; i++)
-		pthread_join(threads[i], NULL);
+		kvm_pthread_join(threads[i], NULL);
 
 	kvm_vm_free(vm);
 
diff --git a/tools/testing/selftests/kvm/x86/private_mem_kvm_exits_test.c b/tools/testing/selftests/kvm/x86/private_mem_kvm_exits_test.c
index 10db9fe6d9063..e6d16e9d61200 100644
--- a/tools/testing/selftests/kvm/x86/private_mem_kvm_exits_test.c
+++ b/tools/testing/selftests/kvm/x86/private_mem_kvm_exits_test.c
@@ -65,13 +65,12 @@ 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);
 
-	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);
diff --git a/tools/testing/selftests/kvm/x86/recalc_apic_map_test.c b/tools/testing/selftests/kvm/x86/recalc_apic_map_test.c
index cbc92a862ea9c..7a0bd9f7ba6c9 100644
--- a/tools/testing/selftests/kvm/x86/recalc_apic_map_test.c
+++ b/tools/testing/selftests/kvm/x86/recalc_apic_map_test.c
@@ -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;) {
@@ -65,8 +65,7 @@ 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_cancel_join_pthread(thread);
 
 	kvm_vm_free(vm);
 
diff --git a/tools/testing/selftests/kvm/x86/sev_migrate_tests.c b/tools/testing/selftests/kvm/x86/sev_migrate_tests.c
index d59abb198d86f..de006e1c861c1 100644
--- a/tools/testing/selftests/kvm/x86/sev_migrate_tests.c
+++ b/tools/testing/selftests/kvm/x86/sev_migrate_tests.c
@@ -128,10 +128,10 @@ 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);
+		kvm_pthread_join(pt[i], NULL);
 	for (i = 0; i < NR_LOCK_TESTING_THREADS; ++i)
 		kvm_vm_free(input[i].vm);
 }
diff --git a/tools/testing/selftests/kvm/x86/sync_regs_test.c b/tools/testing/selftests/kvm/x86/sync_regs_test.c
index 5b0c2359bbb43..9d76c2ed784b6 100644
--- a/tools/testing/selftests/kvm/x86/sync_regs_test.c
+++ b/tools/testing/selftests/kvm/x86/sync_regs_test.c
@@ -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;) {
 		/*
@@ -199,8 +199,7 @@ 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_cancel_join_pthread(thread);
 
 	kvm_x86_state_cleanup(state);
 }
diff --git a/tools/testing/selftests/kvm/x86/tsc_scaling_sync.c b/tools/testing/selftests/kvm/x86/tsc_scaling_sync.c
index 59da8d4da6079..2a3a9bd8b338a 100644
--- a/tools/testing/selftests/kvm/x86/tsc_scaling_sync.c
+++ b/tools/testing/selftests/kvm/x86/tsc_scaling_sync.c
@@ -94,12 +94,12 @@ 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++) {
 		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;
 	}
 
diff --git a/tools/testing/selftests/kvm/x86/xapic_ipi_test.c b/tools/testing/selftests/kvm/x86/xapic_ipi_test.c
index 3a326c5e74cab..78e7aae8fab8d 100644
--- a/tools/testing/selftests/kvm/x86/xapic_ipi_test.c
+++ b/tools/testing/selftests/kvm/x86/xapic_ipi_test.c
@@ -228,25 +228,6 @@ static void *vcpu_thread(void *arg)
 	return NULL;
 }
 
-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);
-	TEST_ASSERT(retval == PTHREAD_CANCELED,
-		    "expected retval=%p, got %p", PTHREAD_CANCELED,
-		    retval);
-}
-
 void do_migrations(struct test_data_page *data, int run_secs, int delay_usecs,
 		   u64 *pipis_rcvd)
 {
@@ -387,7 +368,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 +408,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 +425,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",
@@ -462,8 +439,8 @@ int main(int argc, char *argv[])
 	/*
 	 * Cancel threads and wait for them to stop.
 	 */
-	cancel_join_vcpu_thread(threads[0], params[0].vcpu);
-	cancel_join_vcpu_thread(threads[1], params[1].vcpu);
+	kvm_cancel_join_pthread_async(threads[0]);
+	kvm_cancel_join_pthread_async(threads[1]);
 
 	/*
 	 * If the host support Idle HLT, i.e. KVM *might* be using Idle HLT,
diff --git a/tools/testing/selftests/kvm/x86/xen_shinfo_test.c b/tools/testing/selftests/kvm/x86/xen_shinfo_test.c
index 5076f6a754557..a226a2fd61d94 100644
--- a/tools/testing/selftests/kvm/x86/xen_shinfo_test.c
+++ b/tools/testing/selftests/kvm/x86/xen_shinfo_test.c
@@ -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));
@@ -894,8 +893,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,
@@ -949,11 +947,7 @@ 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_cancel_join_pthread(thread);
 				goto done;
 
 			case TEST_GUEST_SAW_IRQ:

3/2 2026/08/01 07:22 llm patch-evaluator
0m Model:
gemini-3.1-pro-preview

Args:
null

Results:
null

Tokens:
							input: 18693
							output: 73
							thoughts: 1029
						

Thoughts:
**WorthFuzzing Decision: No**

Okay, let's break this down. My initial thought was to determine if this patch introduces any functional changes to the kernel that would warrant fuzzing. The patch touches the `tools/testing/selftests/kvm/` directory, specifically replacing `pthread_create` and `pthread_join` with their KVM-specific counterparts (`kvm_pthread_create`, `kvm_pthread_join`) and adding some wrappers in `kvm_syscalls.h`.

But wait a minute... `tools/testing/selftests/` is *userspace* test code! It's not part of the kernel itself. The instructions clearly state that changes to Documentation, Kconfig files, comments, purely decorative changes, or unreachable code paths do not warrant fuzzing.  This falls under that category. The patch modifies selftests and that's it; that doesn't modify the kernel source that *runs* in the kernel space. So, based on that, I'm thinking this is a straightforward "no".

To be absolutely sure, let me double-check the file list. The patch modifies:

*   `tools/testing/selftests/kvm/arch_timer.c`
*   `tools/testing/selftests/kvm/arm64/vgic_irq.c`
*   `tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c`
*   `tools/testing/selftests/kvm/dirty_log_test.c`
*   `tools/testing/selftests/kvm/hardware_disable_test.c`
*   `tools/testing/selftests/kvm/include/kvm_syscalls.h`
*   `tools/testing/selftests/kvm/include/kvm_util.h`
*   `tools/testing/selftests/kvm/irq_test.c`
*   `tools/testing/selftests/kvm/irqfd_test.c`
*   `tools/testing/selftests/kvm/kvm_page_table_test.c`
*   `tools/testing/selftests/kvm/lib/kvm_util.c`
*   `tools/testing/selftests/kvm/lib/memstress.c`
*   `tools/testing/selftests/kvm/lib/userfaultfd_util.c`
*   `tools/testing/selftests/kvm/memslot_perf_test.c`
*   `tools/testing/selftests/kvm/mmu_stress_test.c`
*   `tools/testing/selftests/kvm/pre_fault_memory_test.c`
*   `tools/testing/selftests/kvm/rseq_test.c`
*   `tools/testing/selftests/kvm/s390/memop.c`
*   `tools/testing/selftests/kvm/set_memory_region_test.c`
*   `tools/testing/selftests/kvm/steal_time.c`
*   `tools/testing/selftests/kvm/x86/hyperv_ipi.c`
*   `tools/testing/selftests/kvm/x86/hyperv_tlb_flush.c`
*   `tools/testing/selftests/kvm/x86/private_mem_conversions_test.c`
*   `tools/testing/selftests/kvm/x86/private_mem_kvm_exits_test.c`
*   `tools/testing/selftests/kvm/x86/recalc_apic_map_test.c`
*   `tools/testing/selftests/kvm/x86/sev_migrate_tests.c`
*   `tools/testing/selftests/kvm/x86/sync_regs_test.c`
*   `tools/testing/selftests/kvm/x86/tsc_scaling_sync.c`
*   `tools/testing/selftests/kvm/x86/xapic_ipi_test.c`
*   `tools/testing/selftests/kvm/x86/xen_shinfo_test.c`

All the modifications are within `tools/testing/


4/2 2026/08/01 07:23 tool set-results
0m Args:
{
  "EnableConfigs": [],
  "FocusSymbols": [],
  "Reasoning": "The patch only modifies userspace KVM selftests (tools/testing/selftests/kvm/*) to use custom pthread wrappers. It does not make any functional changes to the kernel itself.",
  "WorthFuzzing": false
}

Results:
{
  "EnableConfigs": null,
  "FocusSymbols": [],
  "Reasoning": "The patch only modifies userspace KVM selftests (tools/testing/selftests/kvm/*) to use custom pthread wrappers. It does not make any functional changes to the kernel itself.",
  "WorthFuzzing": false
}

LLM Calls Summary:
Total Calls Total Tokens Avg Tokens Total Duration (Seconds) Avg Duration (Seconds)
Tool Calls Summary:
Total Calls Total Duration (Seconds) Avg Duration (Seconds)