/* * completions.c */ #include #include /* for IS_ERR() */ #include #include #include #include #include static struct { struct completion crank_comp; struct completion flywheel_comp; } machine; static int machine_crank_thread(void *arg) { pr_info("Turn the crank\n"); complete_all(&machine.crank_comp); #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0) kthread_complete_and_exit(&machine.crank_comp, 0); #else complete_and_exit(&machine.crank_comp, 0); #endif } static int machine_flywheel_spinup_thread(void *arg) { wait_for_completion(&machine.crank_comp); pr_info("Flywheel spins up\n"); complete_all(&machine.flywheel_comp); #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0) kthread_complete_and_exit(&machine.flywheel_comp, 0); #else complete_and_exit(&machine.flywheel_comp, 0); #endif } static int completions_init(void) { struct task_struct *crank_thread; struct task_struct *flywheel_thread; pr_info("completions example\n"); init_completion(&machine.crank_comp); init_completion(&machine.flywheel_comp); crank_thread = kthread_create(machine_crank_thread, NULL, "KThread Crank"); if (IS_ERR(crank_thread)) goto ERROR_THREAD_1; flywheel_thread = kthread_create(machine_flywheel_spinup_thread, NULL, "KThread Flywheel"); if (IS_ERR(flywheel_thread)) goto ERROR_THREAD_2; wake_up_process(flywheel_thread); wake_up_process(crank_thread); return 0; ERROR_THREAD_2: kthread_stop(crank_thread); ERROR_THREAD_1: return -1; } static void completions_exit(void) { wait_for_completion(&machine.crank_comp); wait_for_completion(&machine.flywheel_comp); pr_info("completions exit\n"); } module_init(completions_init); module_exit(completions_exit); MODULE_DESCRIPTION("Completions example"); MODULE_LICENSE("GPL");