summaryrefslogtreecommitdiffstats
path: root/userspace/src/exec.c
diff options
context:
space:
mode:
Diffstat (limited to 'userspace/src/exec.c')
-rw-r--r--userspace/src/exec.c142
1 files changed, 128 insertions, 14 deletions
diff --git a/userspace/src/exec.c b/userspace/src/exec.c
index b9ba1336..8a99437b 100644
--- a/userspace/src/exec.c
+++ b/userspace/src/exec.c
@@ -21,6 +21,10 @@
21 */ 21 */
22 22
23#include <stdlib.h> 23#include <stdlib.h>
24#include <string.h>
25#include <pthread.h>
26#include <semaphore.h>
27#include <signal.h>
24 28
25#include <unit/io.h> 29#include <unit/io.h>
26#include <unit/core.h> 30#include <unit/core.h>
@@ -31,19 +35,39 @@
31#include <nvgpu/posix/probe.h> 35#include <nvgpu/posix/probe.h>
32 36
33/* 37/*
38 * Sempaphore to limit the number of threads
39 */
40sem_t unit_thread_semaphore;
41
42/*
43 * C11 thread local storage, used to access test context when a signal is
44 * received (ex: SIGSEGV) in a thread.
45 */
46_Thread_local struct unit_module *thread_local_module;
47_Thread_local struct unit_module_test *thread_local_test;
48
49/*
34 * Execute a module and all its subtests. This function builds a gk20a for the 50 * Execute a module and all its subtests. This function builds a gk20a for the
35 * test to use by executing nvgpu_posix_probe() and nvgpu_posix_cleanup(); 51 * test to use by executing nvgpu_posix_probe() and nvgpu_posix_cleanup();
36 */ 52 */
37static int core_exec_module(struct unit_fw *fw, 53static void *core_exec_module(void *module_param)
38 struct unit_module *module)
39{ 54{
40 unsigned int i; 55 unsigned int i;
41 struct gk20a *g = fw->nvgpu.nvgpu_posix_probe(); 56 struct unit_module *module = (struct unit_module *) module_param;
57 struct gk20a *g;
58
59 g = module->fw->nvgpu.nvgpu_posix_probe();
60
61 if (!g) {
62 core_msg_color(module->fw, C_RED,
63 " nvgpu_posix_probe failed: Module %s\n",
64 module->name);
65 goto thread_exit;
66 }
42 67
43 if (!g) 68 core_vbs(module->fw, 1, "Execing module: %s\n", module->name);
44 return -1;
45 69
46 core_vbs(fw, 1, "Execing module: %s\n", module->name); 70 thread_local_module = module;
47 71
48 /* 72 /*
49 * Execute each test within the module. No reinit is done between tests. 73 * Execute each test within the module. No reinit is done between tests.
@@ -53,21 +77,86 @@ static int core_exec_module(struct unit_fw *fw,
53 for (i = 0; i < module->nr_tests; i++) { 77 for (i = 0; i < module->nr_tests; i++) {
54 struct unit_module_test *t = module->tests + i; 78 struct unit_module_test *t = module->tests + i;
55 int test_status; 79 int test_status;
80 thread_local_test = t;
56 81
57 core_msg(fw, "Running %s.%s\n", module->name, t->name); 82 core_msg(module->fw, "Running %s.%s\n", module->name,
83 t->name);
58 test_status = t->fn(module, g, t->args); 84 test_status = t->fn(module, g, t->args);
59 85
60 if (test_status != UNIT_SUCCESS) 86 if (test_status != UNIT_SUCCESS)
61 core_msg_color(fw, C_RED, 87 core_msg_color(module->fw, C_RED,
62 " Unit error! Test %s.%s FAILED!\n", 88 " Unit error! Test %s.%s FAILED!\n",
63 module->name, t->name); 89 module->name, t->name);
64 90
65 core_add_test_record(fw, module, t, 91 core_add_test_record(module->fw, module, t,
66 test_status == UNIT_SUCCESS); 92 test_status == UNIT_SUCCESS);
67 } 93 }
68 94
69 fw->nvgpu.nvgpu_posix_cleanup(g); 95 module->fw->nvgpu.nvgpu_posix_cleanup(g);
96
97 core_vbs(module->fw, 1, "Module completed: %s\n", module->name);
98thread_exit:
99 sem_post(&unit_thread_semaphore);
100 return NULL;
101}
102
103/*
104 * According to POSIX, "Signals which are generated by some action attributable
105 * to a particular thread, such as a hardware fault, shall be generated for the
106 * thread that caused the signal to be generated."
107 * This custom signal handler will be run from within the thread that caused the
108 * exception. Thanks to the context being saved in local thread storage, it is
109 * then trivial to report which test case failed, and then terminate the thread.
110 */
111static void thread_error_handler(int sig, siginfo_t *siginfo, void *context)
112{
113 core_msg_color(thread_local_module->fw, C_RED,
114 " Signal %d in Test: %s.%s!\n", sig,
115 thread_local_module->name, thread_local_test->name);
116 core_add_test_record(thread_local_module->fw, thread_local_module,
117 thread_local_test, false);
118 sem_post(&unit_thread_semaphore);
119 pthread_exit(NULL);
120}
121
122/*
123 * Install a custom signal handler for several signals to be used when running
124 * in multithreaded environment.
125 */
126static int install_thread_error_handler(void)
127{
128 struct sigaction action;
129 int err;
130
131 memset(&action, 0, sizeof(action));
132 action.sa_sigaction = &thread_error_handler;
133 action.sa_flags = SA_SIGINFO;
70 134
135 /* SIGSEGV: Invalid memory reference */
136 err = sigaction(SIGSEGV, &action, NULL);
137 if (err < 0) {
138 return err;
139 }
140 /* SIGILL: Illegal Instruction */
141 err = sigaction(SIGILL, &action, NULL);
142 if (err < 0) {
143 return err;
144 }
145 /* SIGFPE: Floating-point exception */
146 err = sigaction(SIGFPE, &action, NULL);
147 if (err < 0) {
148 return err;
149 }
150 /* SIGBUS: Bus error */
151 err = sigaction(SIGBUS, &action, NULL);
152 if (err < 0) {
153 return err;
154 }
155 /* SIGSYS: Bad system call */
156 err = sigaction(SIGSYS, &action, NULL);
157 if (err < 0) {
158 return err;
159 }
71 return 0; 160 return 0;
72} 161}
73 162
@@ -76,14 +165,39 @@ static int core_exec_module(struct unit_fw *fw,
76 */ 165 */
77int core_exec(struct unit_fw *fw) 166int core_exec(struct unit_fw *fw)
78{ 167{
79 int ret;
80 struct unit_module **modules; 168 struct unit_module **modules;
169 int err = 0;
170
171 core_vbs(fw, 1, "Using %d threads\n", fw->args->thread_count);
172 sem_init(&unit_thread_semaphore, 0, fw->args->thread_count);
173
174 /*
175 * If running single threaded, keep the default SIGSEGV handler to make
176 * interactive debugging easier, otherwise install the custom one.
177 */
178 if (fw->args->thread_count > 1) {
179 err = install_thread_error_handler();
180 if (err != 0) {
181 core_msg_color(fw, C_RED,
182 " Failed to install signal handler!\n");
183 return err;
184 }
185 }
81 186
82 for (modules = fw->modules; *modules != NULL; modules++) { 187 for (modules = fw->modules; *modules != NULL; modules++) {
83 ret = core_exec_module(fw, *modules); 188 if (fw->args->thread_count == 1) {
189 core_exec_module(*modules);
190 } else {
191 sem_wait(&unit_thread_semaphore);
192 pthread_create(&((*modules)->thread), NULL,
193 core_exec_module, (void *) *modules);
194 }
195 }
84 196
85 if (ret != 0) 197 if (fw->args->thread_count > 1) {
86 return ret; 198 for (modules = fw->modules; *modules != NULL; modules++) {
199 pthread_join((*modules)->thread, NULL);
200 }
87 } 201 }
88 202
89 return 0; 203 return 0;