|
11 | 11 | #include <linux/completion.h> |
12 | 12 | #include <linux/kernel.h> |
13 | 13 | #include <linux/kthread.h> |
| 14 | +#include <linux/sched/task.h> |
14 | 15 |
|
15 | 16 | #include "try-catch-impl.h" |
16 | 17 |
|
17 | 18 | void __noreturn kunit_try_catch_throw(struct kunit_try_catch *try_catch) |
18 | 19 | { |
19 | 20 | try_catch->try_result = -EFAULT; |
20 | | - kthread_complete_and_exit(try_catch->try_completion, -EFAULT); |
| 21 | + kthread_exit(0); |
21 | 22 | } |
22 | 23 | EXPORT_SYMBOL_GPL(kunit_try_catch_throw); |
23 | 24 |
|
24 | 25 | static int kunit_generic_run_threadfn_adapter(void *data) |
25 | 26 | { |
26 | 27 | struct kunit_try_catch *try_catch = data; |
27 | 28 |
|
| 29 | + try_catch->try_result = -EINTR; |
28 | 30 | try_catch->try(try_catch->context); |
| 31 | + if (try_catch->try_result == -EINTR) |
| 32 | + try_catch->try_result = 0; |
29 | 33 |
|
30 | | - kthread_complete_and_exit(try_catch->try_completion, 0); |
| 34 | + return 0; |
31 | 35 | } |
32 | 36 |
|
33 | 37 | static unsigned long kunit_test_timeout(void) |
@@ -57,39 +61,53 @@ static unsigned long kunit_test_timeout(void) |
57 | 61 |
|
58 | 62 | void kunit_try_catch_run(struct kunit_try_catch *try_catch, void *context) |
59 | 63 | { |
60 | | - DECLARE_COMPLETION_ONSTACK(try_completion); |
61 | 64 | struct kunit *test = try_catch->test; |
62 | 65 | struct task_struct *task_struct; |
| 66 | + struct completion *task_done; |
63 | 67 | int exit_code, time_remaining; |
64 | 68 |
|
65 | 69 | try_catch->context = context; |
66 | | - try_catch->try_completion = &try_completion; |
67 | 70 | try_catch->try_result = 0; |
68 | | - task_struct = kthread_run(kunit_generic_run_threadfn_adapter, |
69 | | - try_catch, |
70 | | - "kunit_try_catch_thread"); |
| 71 | + task_struct = kthread_create(kunit_generic_run_threadfn_adapter, |
| 72 | + try_catch, "kunit_try_catch_thread"); |
71 | 73 | if (IS_ERR(task_struct)) { |
| 74 | + try_catch->try_result = PTR_ERR(task_struct); |
72 | 75 | try_catch->catch(try_catch->context); |
73 | 76 | return; |
74 | 77 | } |
| 78 | + get_task_struct(task_struct); |
| 79 | + /* |
| 80 | + * As for a vfork(2), task_struct->vfork_done (pointing to the |
| 81 | + * underlying kthread->exited) can be used to wait for the end of a |
| 82 | + * kernel thread. It is set to NULL when the thread exits, so we |
| 83 | + * keep a copy here. |
| 84 | + */ |
| 85 | + task_done = task_struct->vfork_done; |
| 86 | + wake_up_process(task_struct); |
75 | 87 |
|
76 | | - time_remaining = wait_for_completion_timeout(&try_completion, |
| 88 | + time_remaining = wait_for_completion_timeout(task_done, |
77 | 89 | kunit_test_timeout()); |
78 | 90 | if (time_remaining == 0) { |
79 | | - kunit_err(test, "try timed out\n"); |
80 | 91 | try_catch->try_result = -ETIMEDOUT; |
81 | 92 | kthread_stop(task_struct); |
82 | 93 | } |
83 | 94 |
|
| 95 | + put_task_struct(task_struct); |
84 | 96 | exit_code = try_catch->try_result; |
85 | 97 |
|
86 | 98 | if (!exit_code) |
87 | 99 | return; |
88 | 100 |
|
89 | 101 | if (exit_code == -EFAULT) |
90 | 102 | try_catch->try_result = 0; |
91 | | - else if (exit_code == -EINTR) |
92 | | - kunit_err(test, "wake_up_process() was never called\n"); |
| 103 | + else if (exit_code == -EINTR) { |
| 104 | + if (test->last_seen.file) |
| 105 | + kunit_err(test, "try faulted: last line seen %s:%d\n", |
| 106 | + test->last_seen.file, test->last_seen.line); |
| 107 | + else |
| 108 | + kunit_err(test, "try faulted\n"); |
| 109 | + } else if (exit_code == -ETIMEDOUT) |
| 110 | + kunit_err(test, "try timed out\n"); |
93 | 111 | else if (exit_code) |
94 | 112 | kunit_err(test, "Unknown error: %d\n", exit_code); |
95 | 113 |
|
|
0 commit comments