int ret;
        char tmp_chr;
 
+       if (!args->handle_fault)
+               args->handle_fault = uffd_handle_page_fault;
+
        pollfd[0].fd = uffd;
        pollfd[0].events = POLLIN;
        pollfd[1].fd = pipefd[cpu*2];
                        err("unexpected msg event %u\n", msg.event);
                        break;
                case UFFD_EVENT_PAGEFAULT:
-                       uffd_handle_page_fault(&msg, args);
+                       args->handle_fault(&msg, args);
                        break;
                case UFFD_EVENT_FORK:
                        close(uffd);
 
        unsigned long missing_faults;
        unsigned long wp_faults;
        unsigned long minor_faults;
+
+       /* A custom fault handler; defaults to uffd_handle_page_fault. */
+       void (*handle_fault)(struct uffd_msg *msg, struct uffd_args *args);
 };
 
 struct uffd_test_ops {
 
                                   locking_thread, (void *)cpu))
                        return 1;
                if (bounces & BOUNCE_POLL) {
-                       if (pthread_create(&uffd_threads[cpu], &attr,
-                                          uffd_poll_thread,
-                                          (void *)&args[cpu]))
-                               return 1;
+                       if (pthread_create(&uffd_threads[cpu], &attr, uffd_poll_thread, &args[cpu]))
+                               err("uffd_poll_thread create");
                } else {
                        if (pthread_create(&uffd_threads[cpu], &attr,
                                           uffd_read_thread,
        struct uffd_args args[nr_cpus];
        uint64_t mem_size = nr_pages * page_size;
 
+       memset(args, 0, sizeof(struct uffd_args) * nr_cpus);
+
        if (uffd_test_ctx_init(UFFD_FEATURE_WP_UNPOPULATED, NULL))
                err("context init failed");