]> asedeno.scripts.mit.edu Git - linux.git/blob - lib/kunit/try-catch.c
kunit: hide unexported try-catch interface in try-catch-impl.h
[linux.git] / lib / kunit / try-catch.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * An API to allow a function, that may fail, to be executed, and recover in a
4  * controlled manner.
5  *
6  * Copyright (C) 2019, Google LLC.
7  * Author: Brendan Higgins <brendanhiggins@google.com>
8  */
9
10 #include <kunit/test.h>
11 #include <linux/completion.h>
12 #include <linux/kernel.h>
13 #include <linux/kthread.h>
14 #include <linux/sched/sysctl.h>
15
16 #include "try-catch-impl.h"
17
18 void __noreturn kunit_try_catch_throw(struct kunit_try_catch *try_catch)
19 {
20         try_catch->try_result = -EFAULT;
21         complete_and_exit(try_catch->try_completion, -EFAULT);
22 }
23
24 static int kunit_generic_run_threadfn_adapter(void *data)
25 {
26         struct kunit_try_catch *try_catch = data;
27
28         try_catch->try(try_catch->context);
29
30         complete_and_exit(try_catch->try_completion, 0);
31 }
32
33 static unsigned long kunit_test_timeout(void)
34 {
35         unsigned long timeout_msecs;
36
37         /*
38          * TODO(brendanhiggins@google.com): We should probably have some type of
39          * variable timeout here. The only question is what that timeout value
40          * should be.
41          *
42          * The intention has always been, at some point, to be able to label
43          * tests with some type of size bucket (unit/small, integration/medium,
44          * large/system/end-to-end, etc), where each size bucket would get a
45          * default timeout value kind of like what Bazel does:
46          * https://docs.bazel.build/versions/master/be/common-definitions.html#test.size
47          * There is still some debate to be had on exactly how we do this. (For
48          * one, we probably want to have some sort of test runner level
49          * timeout.)
50          *
51          * For more background on this topic, see:
52          * https://mike-bland.com/2011/11/01/small-medium-large.html
53          */
54         if (sysctl_hung_task_timeout_secs) {
55                 /*
56                  * If sysctl_hung_task is active, just set the timeout to some
57                  * value less than that.
58                  *
59                  * In regards to the above TODO, if we decide on variable
60                  * timeouts, this logic will likely need to change.
61                  */
62                 timeout_msecs = (sysctl_hung_task_timeout_secs - 1) *
63                                 MSEC_PER_SEC;
64         } else {
65                 timeout_msecs = 300 * MSEC_PER_SEC; /* 5 min */
66         }
67
68         return timeout_msecs;
69 }
70
71 void kunit_try_catch_run(struct kunit_try_catch *try_catch, void *context)
72 {
73         DECLARE_COMPLETION_ONSTACK(try_completion);
74         struct kunit *test = try_catch->test;
75         struct task_struct *task_struct;
76         int exit_code, time_remaining;
77
78         try_catch->context = context;
79         try_catch->try_completion = &try_completion;
80         try_catch->try_result = 0;
81         task_struct = kthread_run(kunit_generic_run_threadfn_adapter,
82                                   try_catch,
83                                   "kunit_try_catch_thread");
84         if (IS_ERR(task_struct)) {
85                 try_catch->catch(try_catch->context);
86                 return;
87         }
88
89         time_remaining = wait_for_completion_timeout(&try_completion,
90                                                      kunit_test_timeout());
91         if (time_remaining == 0) {
92                 kunit_err(test, "try timed out\n");
93                 try_catch->try_result = -ETIMEDOUT;
94         }
95
96         exit_code = try_catch->try_result;
97
98         if (!exit_code)
99                 return;
100
101         if (exit_code == -EFAULT)
102                 try_catch->try_result = 0;
103         else if (exit_code == -EINTR)
104                 kunit_err(test, "wake_up_process() was never called\n");
105         else if (exit_code)
106                 kunit_err(test, "Unknown error: %d\n", exit_code);
107
108         try_catch->catch(try_catch->context);
109 }