| OLD | NEW |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include <fcntl.h> | 5 #include <fcntl.h> |
| 6 #include <launchpad/launchpad.h> | 6 #include <launchpad/launchpad.h> |
| 7 #include <launchpad/vmo.h> |
| 7 #include <magenta/syscalls.h> | 8 #include <magenta/syscalls.h> |
| 8 #include <mxio/util.h> | 9 #include <mxio/util.h> |
| 9 #include <pthread.h> | 10 #include <pthread.h> |
| 11 #include <runtime/status.h> |
| 12 #include <runtime/sysinfo.h> |
| 10 #include <stdbool.h> | 13 #include <stdbool.h> |
| 11 #include <stdio.h> | 14 #include <stdio.h> |
| 12 #include <stdlib.h> | 15 #include <stdlib.h> |
| 13 #include <string.h> | 16 #include <string.h> |
| 14 #include <unistd.h> | 17 #include <unistd.h> |
| 15 | 18 |
| 16 // This program runs Dart VM unit tests. The Dart VM unit tests are contained | 19 // This program runs Dart VM unit tests. The Dart VM unit tests are contained |
| 17 // in a separate binary whose location is defined in kRunVmTestsPath below. | 20 // in a separate binary whose location is defined in kRunVmTestsPath below. |
| 18 // That program accepts a command line argument --list to list all the available | 21 // That program accepts a command line argument --list to list all the available |
| 19 // tests, or the name of a single test to run. This program accepts a single | 22 // tests, or the name of a single test to run. This program grabs the list of |
| 20 // command line argument which is the path to a file containing a list of tests | 23 // tests, and then runs them. |
| 21 // to run, one per line. | |
| 22 | 24 |
| 23 // TODO(zra): Make this a command line argument | 25 // TODO(zra): Make this a command line argument |
| 24 const char* kRunVmTestsPath = "/boot/bin/dart_vm_tests"; | 26 const char* kRunVmTestsPath = "/boot/bin/dart_vm_tests"; |
| 25 | 27 |
| 26 // The simulator only has 512MB; | |
| 27 const intptr_t kOldGenHeapSizeMB = 256; | |
| 28 | |
| 29 // Tests that are invalid, wedge, or cause panics. | 28 // Tests that are invalid, wedge, or cause panics. |
| 30 const char* kSkip[] = { | 29 const char* kSkip[] = { |
| 31 // These expect a file to exist that we aren't putting in the image. | 30 // These expect a file to exist that we aren't putting in the image. |
| 32 "Read", | 31 "Read", |
| 33 "FileLength", | 32 "FileLength", |
| 34 "FilePosition", | 33 "FilePosition", |
| 35 // Crash and then Hang. | 34 // Crash and then Hang. |
| 36 "ArrayLengthMaxElements", | 35 "ArrayLengthMaxElements", |
| 37 "Int8ListLengthMaxElements", | 36 "Int8ListLengthMaxElements", |
| 38 // Crashes in realloc. | 37 // Crashes in realloc. |
| (...skipping 17 matching lines...) Expand all Loading... |
| 56 "Profiler_SampleBufferWrapTest", | 55 "Profiler_SampleBufferWrapTest", |
| 57 "Profiler_SourcePosition", | 56 "Profiler_SourcePosition", |
| 58 "Profiler_SourcePositionOptimized", | 57 "Profiler_SourcePositionOptimized", |
| 59 "Profiler_StringAllocation", | 58 "Profiler_StringAllocation", |
| 60 "Profiler_StringInterpolation", | 59 "Profiler_StringInterpolation", |
| 61 "Profiler_ToggleRecordAllocation", | 60 "Profiler_ToggleRecordAllocation", |
| 62 "Profiler_TrivialRecordAllocation", | 61 "Profiler_TrivialRecordAllocation", |
| 63 "Profiler_TypedArrayAllocation", | 62 "Profiler_TypedArrayAllocation", |
| 64 "Profiler_GetSourceReport", | 63 "Profiler_GetSourceReport", |
| 65 "Service_Profile", | 64 "Service_Profile", |
| 66 // No realpath. | 65 // No realpath, files not in image. |
| 67 "Dart2JSCompilerStats", | 66 "Dart2JSCompilerStats", |
| 68 "Dart2JSCompileAll", | 67 "Dart2JSCompileAll", |
| 69 // Uses too much memory. | 68 // Uses too much memory. |
| 70 "PrintJSON", | 69 "PrintJSON", |
| 71 }; | 70 }; |
| 72 | 71 |
| 73 // Expected to fail/crash. | 72 // Expected to fail/crash. |
| 74 const char* kExpectFail[] = { | 73 const char* kExpectFail[] = { |
| 75 "Fail0", | 74 "Fail0", |
| 76 "Fail1", | 75 "Fail1", |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 136 return contains( | 135 return contains( |
| 137 kExpectFail, sizeof(kExpectFail) / sizeof(kExpectFail[0]), test); | 136 kExpectFail, sizeof(kExpectFail) / sizeof(kExpectFail[0]), test); |
| 138 } | 137 } |
| 139 | 138 |
| 140 | 139 |
| 141 static bool isBug(const char* test) { | 140 static bool isBug(const char* test) { |
| 142 return contains(kBugs, sizeof(kBugs) / sizeof(kBugs[0]), test); | 141 return contains(kBugs, sizeof(kBugs) / sizeof(kBugs[0]), test); |
| 143 } | 142 } |
| 144 | 143 |
| 145 | 144 |
| 146 static int run_test(const char* test_name) { | 145 #define RETURN_IF_ERROR(status) \ |
| 147 const intptr_t kArgc = 3; | 146 if (status < 0) { \ |
| 147 fprintf(stderr, "%s:%d: Magenta call failed: %s\n", \ |
| 148 __FILE__, __LINE__, mx_strstatus(static_cast<mx_status_t>(status))); \ |
| 149 fflush(0); \ |
| 150 return status; \ |
| 151 } \ |
| 152 |
| 153 |
| 154 // This is mostly taken from //magenta/system/uapp/mxsh with the addtion of |
| 155 // launchpad_add_pipe calls to setup pipes for stdout and stderr. |
| 156 static mx_status_t lp_setup(launchpad_t** lp_out, mx_handle_t binary_vmo, |
| 157 int argc, const char* const* argv, |
| 158 int *stdout_out, int *stderr_out) { |
| 159 if ((lp_out == NULL) || (stdout_out == NULL) || (stderr_out == NULL)) { |
| 160 return ERR_INVALID_ARGS; |
| 161 } |
| 162 launchpad_t* lp; |
| 163 mx_status_t status; |
| 164 status = launchpad_create(argv[0], &lp); |
| 165 RETURN_IF_ERROR(status); |
| 166 status = launchpad_arguments(lp, argc, argv); |
| 167 RETURN_IF_ERROR(status); |
| 168 status = launchpad_clone_mxio_root(lp); |
| 169 RETURN_IF_ERROR(status); |
| 170 status = launchpad_add_pipe(lp, stdout_out, 1); |
| 171 RETURN_IF_ERROR(status); |
| 172 status = launchpad_add_pipe(lp, stderr_out, 2); |
| 173 RETURN_IF_ERROR(status); |
| 174 status = launchpad_elf_load(lp, binary_vmo); |
| 175 RETURN_IF_ERROR(status); |
| 176 *lp_out = lp; |
| 177 return status; |
| 178 } |
| 179 |
| 180 |
| 181 // Start the test running and return file descriptors for the stdout and stderr |
| 182 // pipes. |
| 183 static mx_handle_t start_test(mx_handle_t binary_vmo, const char* test_name, |
| 184 int* stdout_out, int* stderr_out) { |
| 185 const intptr_t kArgc = 2; |
| 148 const char* argv[kArgc]; | 186 const char* argv[kArgc]; |
| 149 | 187 |
| 150 char old_gen_arg[64]; | 188 argv[0] = kRunVmTestsPath; |
| 151 snprintf(old_gen_arg, sizeof(old_gen_arg), "--old_gen_heap_size=%ld", | 189 argv[1] = test_name; |
| 152 kOldGenHeapSizeMB); | |
| 153 | 190 |
| 154 argv[0] = kRunVmTestsPath; | 191 launchpad_t* lp = NULL; |
| 155 argv[1] = old_gen_arg; | 192 int stdout_pipe = -1; |
| 156 argv[2] = test_name; | 193 int stderr_pipe = -1; |
| 194 mx_status_t status = lp_setup( |
| 195 &lp, binary_vmo, kArgc, argv, &stdout_pipe, &stderr_pipe); |
| 196 if (status != NO_ERROR) { |
| 197 if (lp != NULL) { |
| 198 launchpad_destroy(lp); |
| 199 } |
| 200 if (stdout_pipe != -1) { |
| 201 close(stdout_pipe); |
| 202 } |
| 203 if (stderr_pipe != -1) { |
| 204 close(stderr_pipe); |
| 205 } |
| 206 } |
| 207 RETURN_IF_ERROR(status); |
| 157 | 208 |
| 158 mx_handle_t p = launchpad_launch_mxio(argv[0], kArgc, argv); | 209 mx_handle_t p = launchpad_start(lp); |
| 210 launchpad_destroy(lp); |
| 159 if (p < 0) { | 211 if (p < 0) { |
| 160 fprintf(stderr, "process failed to start\n"); | 212 close(stdout_pipe); |
| 161 return -1; | 213 close(stderr_pipe); |
| 162 } | 214 } |
| 215 RETURN_IF_ERROR(p); |
| 216 |
| 217 if (stdout_out != NULL) { |
| 218 *stdout_out = stdout_pipe; |
| 219 } else { |
| 220 close(stdout_pipe); |
| 221 } |
| 222 if (stderr_out != NULL) { |
| 223 *stderr_out = stderr_pipe; |
| 224 } else { |
| 225 close(stderr_pipe); |
| 226 } |
| 227 return p; |
| 228 } |
| 229 |
| 230 |
| 231 // Drain fd into a buffer pointed to by 'buffer'. Assumes that the data is a |
| 232 // C string, and null-terminates it. Returns the number of bytes read. |
| 233 static intptr_t drain_fd(int fd, char** buffer) { |
| 234 const intptr_t kDrainInitSize = 64; |
| 235 char* buf = reinterpret_cast<char*>(malloc(kDrainInitSize)); |
| 236 intptr_t free_space = kDrainInitSize; |
| 237 intptr_t total_read = 0; |
| 238 intptr_t read_size = 0; |
| 239 while ((read_size = read(fd, buf + total_read, free_space)) != 0) { |
| 240 if (read_size == -1) { |
| 241 break; |
| 242 } |
| 243 total_read += read_size; |
| 244 free_space -= read_size; |
| 245 if (free_space <= 1) { |
| 246 // new_size = size * 1.5. |
| 247 intptr_t new_size = (total_read << 1) - (total_read >> 1); |
| 248 buf = reinterpret_cast<char*>(realloc(buf, new_size)); |
| 249 free_space = new_size - total_read; |
| 250 } |
| 251 } |
| 252 buf[total_read] = '\0'; |
| 253 close(fd); |
| 254 *buffer = buf; |
| 255 return total_read; |
| 256 } |
| 257 |
| 258 |
| 259 // Runs test 'test_name' and gives stdout and stderr for the test in |
| 260 // 'test_stdout' and 'test_stderr'. Returns the exit code from the test. |
| 261 static int run_test(mx_handle_t binary_vmo, const char* test_name, |
| 262 char** test_stdout, char** test_stderr) { |
| 263 int stdout_pipe = -1; |
| 264 int stderr_pipe = -1; |
| 265 mx_handle_t p = start_test(binary_vmo, test_name, &stdout_pipe, &stderr_pipe); |
| 266 RETURN_IF_ERROR(p); |
| 267 |
| 268 drain_fd(stdout_pipe, test_stdout); |
| 269 drain_fd(stderr_pipe, test_stderr); |
| 163 | 270 |
| 164 mx_signals_state_t state; | 271 mx_signals_state_t state; |
| 165 mx_status_t r = mx_handle_wait_one( | 272 mx_status_t r = mx_handle_wait_one( |
| 166 p, MX_SIGNAL_SIGNALED, MX_TIME_INFINITE, &state); | 273 p, MX_SIGNAL_SIGNALED, MX_TIME_INFINITE, &state); |
| 167 if (r != NO_ERROR) { | 274 RETURN_IF_ERROR(r); |
| 168 fprintf(stderr, "[process(%x): wait failed? %d]\n", p, r); | |
| 169 return -1; | |
| 170 } | |
| 171 | 275 |
| 172 mx_process_info_t proc_info; | 276 mx_process_info_t proc_info; |
| 173 mx_ssize_t ret = mx_handle_get_info( | 277 mx_ssize_t info_size = mx_handle_get_info( |
| 174 p, MX_INFO_PROCESS, &proc_info, sizeof(proc_info)); | 278 p, MX_INFO_PROCESS, &proc_info, sizeof(proc_info)); |
| 175 if (ret != sizeof(proc_info)) { | 279 RETURN_IF_ERROR(info_size); |
| 176 fprintf(stderr, "[process(%x): handle_get_info failed? %ld]\n", p, ret); | |
| 177 return -1; | |
| 178 } | |
| 179 | 280 |
| 180 mx_handle_close(p); | 281 r = mx_handle_close(p); |
| 282 RETURN_IF_ERROR(r); |
| 181 return proc_info.return_code; | 283 return proc_info.return_code; |
| 182 } | 284 } |
| 183 | 285 |
| 184 | 286 |
| 185 static void handle_result(intptr_t result, const char* test) { | 287 static void handle_result( |
| 288 intptr_t result, char* test_stdout, char* test_stderr, const char* test) { |
| 186 if (result != 0) { | 289 if (result != 0) { |
| 187 if (!isExpectFail(test) && !isBug(test)) { | 290 if (!isExpectFail(test) && !isBug(test)) { |
| 188 printf("******** Test %s FAILED\n", test); | 291 printf("**** Test %s FAILED\n\nstdout:\n%s\nstderr:\n%s\n", |
| 292 test, test_stdout, test_stderr); |
| 293 } else { |
| 294 printf("Test %s FAILED and is expected to fail\n", test); |
| 189 } | 295 } |
| 190 } else { | 296 } else { |
| 191 if (isExpectFail(test)) { | 297 if (isExpectFail(test)) { |
| 192 printf("******** Test %s is expected to fail, but PASSED\n", test); | 298 printf("**** Test %s is expected to fail, but PASSED\n\n" |
| 193 } | 299 "stdout:\n%s\nstderr:\n%s\n", |
| 194 if (isBug(test)) { | 300 test, test_stdout, test_stderr); |
| 195 printf("******** Test %s is marked as a bug, but PASSED\n", test); | 301 } else if (isBug(test)) { |
| 302 printf("**** Test %s is marked as a bug, but PASSED\n", test); |
| 303 } else { |
| 304 printf("Test %s PASSED\n", test); |
| 196 } | 305 } |
| 197 } | 306 } |
| 198 } | 307 } |
| 199 | 308 |
| 200 | 309 |
| 201 typedef struct { | 310 typedef struct { |
| 202 pthread_mutex_t* test_list_lock; | 311 pthread_mutex_t* test_list_lock; |
| 203 char** test_list; | 312 char** test_list; |
| 204 intptr_t test_list_length; | 313 intptr_t test_list_length; |
| 205 intptr_t* test_list_index; | 314 intptr_t* test_list_index; |
| 315 mx_handle_t binary_vmo; |
| 206 } runner_args_t; | 316 } runner_args_t; |
| 207 | 317 |
| 208 | 318 |
| 209 static void* test_runner_thread(void* arg) { | 319 static void* test_runner_thread(void* arg) { |
| 210 runner_args_t* args = reinterpret_cast<runner_args_t*>(arg); | 320 runner_args_t* args = reinterpret_cast<runner_args_t*>(arg); |
| 211 | 321 |
| 212 pthread_mutex_lock(args->test_list_lock); | 322 pthread_mutex_lock(args->test_list_lock); |
| 323 mx_handle_t binary_vmo = args->binary_vmo; |
| 213 while (*args->test_list_index < args->test_list_length) { | 324 while (*args->test_list_index < args->test_list_length) { |
| 214 const intptr_t index = *args->test_list_index; | 325 const intptr_t index = *args->test_list_index; |
| 215 *args->test_list_index = index + 1; | 326 *args->test_list_index = index + 1; |
| 216 pthread_mutex_unlock(args->test_list_lock); | 327 pthread_mutex_unlock(args->test_list_lock); |
| 328 |
| 217 const char* test = args->test_list[index]; | 329 const char* test = args->test_list[index]; |
| 218 handle_result(run_test(test), test); | 330 char* test_stdout = NULL; |
| 331 char* test_stderr = NULL; |
| 332 mx_handle_t vmo_dup = mx_handle_duplicate(binary_vmo, MX_RIGHT_SAME_RIGHTS); |
| 333 int test_status = run_test(vmo_dup, test, &test_stdout, &test_stderr); |
| 334 handle_result(test_status, test_stdout, test_stderr, test); |
| 335 free(test_stdout); |
| 336 free(test_stderr); |
| 219 pthread_mutex_lock(args->test_list_lock); | 337 pthread_mutex_lock(args->test_list_lock); |
| 220 } | 338 } |
| 221 pthread_mutex_unlock(args->test_list_lock); | 339 pthread_mutex_unlock(args->test_list_lock); |
| 222 | 340 |
| 223 return NULL; | 341 return NULL; |
| 224 } | 342 } |
| 225 | 343 |
| 226 | 344 |
| 227 static void trim(char* line) { | 345 static void run_all_tests(runner_args_t* args) { |
| 228 const intptr_t line_len = strlen(line); | 346 const intptr_t num_cpus = sysconf(_SC_NPROCESSORS_CONF); |
| 229 if (line[line_len - 1] == '\n') { | 347 pthread_t* threads = |
| 230 line[line_len - 1] = '\0'; | 348 reinterpret_cast<pthread_t*>(malloc(num_cpus * sizeof(pthread_t))); |
| 349 for (int i = 0; i < num_cpus; i++) { |
| 350 pthread_create(&threads[i], NULL, test_runner_thread, args); |
| 231 } | 351 } |
| 352 for (int i = 0; i < num_cpus; i++) { |
| 353 pthread_join(threads[i], NULL); |
| 354 } |
| 355 free(threads); |
| 232 } | 356 } |
| 233 | 357 |
| 234 | 358 |
| 235 static bool should_run(const char* test) { | 359 static bool should_run(const char* test) { |
| 236 return !(test[0] == '#') && !isSkip(test); | 360 return !(test[0] == '#') && !isSkip(test); |
| 237 } | 361 } |
| 238 | 362 |
| 239 | 363 |
| 240 static intptr_t count_lines(FILE* fp) { | 364 static char** parse_test_list(char* list_output, intptr_t* length) { |
| 241 intptr_t lines = 0; | 365 const intptr_t list_output_length = strlen(list_output); |
| 242 | 366 intptr_t test_count = 0; |
| 243 // Make sure we're at the beginning of the file. | 367 for (int i = 0; i < list_output_length; i++) { |
| 244 rewind(fp); | 368 if (list_output[i] == '\n') { |
| 245 | 369 test_count++; |
| 246 intptr_t ch; | |
| 247 while ((ch = fgetc(fp)) != EOF) { | |
| 248 if (ch == '\n') { | |
| 249 lines++; | |
| 250 } | 370 } |
| 251 } | 371 } |
| 252 | 372 char** test_list; |
| 253 rewind(fp); | 373 test_list = reinterpret_cast<char**>(malloc(test_count * sizeof(*test_list))); |
| 254 return lines; | 374 char* test = list_output; |
| 255 } | 375 char* strtok_context; |
| 256 | 376 intptr_t idx = 0; |
| 257 | 377 while ((test = strtok_r(test, "\n", &strtok_context)) != NULL) { |
| 258 static intptr_t read_lines(FILE* fp, char** lines, intptr_t lines_length) { | 378 if (should_run(test)) { |
| 259 char* test = NULL; | 379 test_list[idx] = strdup(test); |
| 260 size_t len = 0; | 380 idx++; |
| 261 ssize_t read; | |
| 262 intptr_t i = 0; | |
| 263 while (((read = getline(&test, &len, fp)) != -1) && (i < lines_length)) { | |
| 264 trim(test); | |
| 265 if (!should_run(test)) { | |
| 266 continue; | |
| 267 } | 381 } |
| 268 lines[i] = strdup(test); | 382 test = NULL; |
| 269 i++; | |
| 270 } | 383 } |
| 271 | 384 |
| 272 if (test != NULL) { | 385 *length = idx; |
| 273 free(test); | 386 return test_list; |
| 274 } | |
| 275 return i; | |
| 276 } | 387 } |
| 277 | 388 |
| 278 | 389 |
| 279 int main(int argc, char** argv) { | 390 int main(int argc, char** argv) { |
| 280 if (argc <= 1) { | 391 // TODO(zra): Read test binary path from the command line. |
| 281 fprintf(stderr, "Pass the path to a file containing the list of tests\n"); | |
| 282 return -1; | |
| 283 } | |
| 284 const char* tests_path = argv[1]; | |
| 285 | 392 |
| 286 FILE* fp = fopen(tests_path, "r"); | 393 // Load in the binary. |
| 287 if (fp == NULL) { | 394 mx_handle_t binary_vmo = launchpad_vmo_from_file(kRunVmTestsPath); |
| 288 fprintf(stderr, "Failed to read the file: %s\n", tests_path); | 395 RETURN_IF_ERROR(binary_vmo); |
| 289 return -1; | 396 |
| 397 // Run with --list to grab the list of tests. |
| 398 char* list_stdout = NULL; |
| 399 char* list_stderr = NULL; |
| 400 mx_handle_t list_vmo = mx_handle_duplicate(binary_vmo, MX_RIGHT_SAME_RIGHTS); |
| 401 RETURN_IF_ERROR(list_vmo); |
| 402 int list_result = run_test(list_vmo, "--list", &list_stdout, &list_stderr); |
| 403 if (list_result != 0) { |
| 404 fprintf(stderr, "Failed to list tests: %s\n%s\n", list_stdout, list_stderr); |
| 405 fflush(0); |
| 406 free(list_stdout); |
| 407 free(list_stderr); |
| 408 return list_result; |
| 290 } | 409 } |
| 291 | 410 |
| 292 intptr_t lines_count = count_lines(fp); | 411 // Parse the test list into an array of C strings. |
| 293 char** test_list = | 412 intptr_t lines_count; |
| 294 reinterpret_cast<char**>(malloc(sizeof(*test_list) * lines_count)); | 413 char** test_list = parse_test_list(list_stdout, &lines_count); |
| 295 lines_count = read_lines(fp, test_list, lines_count); | 414 free(list_stdout); |
| 296 fclose(fp); | 415 free(list_stderr); |
| 297 | 416 |
| 417 fprintf(stdout, "Found %ld tests\n", lines_count); |
| 418 fflush(0); |
| 419 |
| 420 // Run the tests across a number of threads equal to the number of cores. |
| 298 pthread_mutex_t args_mutex; | 421 pthread_mutex_t args_mutex; |
| 299 pthread_mutex_init(&args_mutex, NULL); | 422 pthread_mutex_init(&args_mutex, NULL); |
| 300 intptr_t test_list_index = 0; | 423 intptr_t test_list_index = 0; |
| 301 runner_args_t args; | 424 runner_args_t args; |
| 302 args.test_list_lock = &args_mutex; | 425 args.test_list_lock = &args_mutex; |
| 303 args.test_list = test_list; | 426 args.test_list = test_list; |
| 304 args.test_list_length = lines_count; | 427 args.test_list_length = lines_count; |
| 305 args.test_list_index = &test_list_index; | 428 args.test_list_index = &test_list_index; |
| 429 args.binary_vmo = binary_vmo; |
| 430 run_all_tests(&args); |
| 306 | 431 |
| 307 const intptr_t num_cpus = sysconf(_SC_NPROCESSORS_CONF); | 432 // Cleanup. |
| 308 pthread_t* threads = | |
| 309 reinterpret_cast<pthread_t*>(malloc(num_cpus * sizeof(pthread_t))); | |
| 310 for (int i = 0; i < num_cpus; i++) { | |
| 311 pthread_create(&threads[i], NULL, test_runner_thread, &args); | |
| 312 } | |
| 313 | |
| 314 for (int i = 0; i < num_cpus; i++) { | |
| 315 pthread_join(threads[i], NULL); | |
| 316 } | |
| 317 | |
| 318 free(threads); | |
| 319 for (int i = 0; i < lines_count; i++) { | 433 for (int i = 0; i < lines_count; i++) { |
| 320 free(test_list[i]); | 434 free(test_list[i]); |
| 321 } | 435 } |
| 322 free(test_list); | 436 free(test_list); |
| 323 pthread_mutex_destroy(&args_mutex); | 437 pthread_mutex_destroy(&args_mutex); |
| 438 mx_status_t status = mx_handle_close(binary_vmo); |
| 439 RETURN_IF_ERROR(status); |
| 324 | 440 |
| 441 // Complain if we didn't try to run all of the tests. |
| 325 if (test_list_index != lines_count) { | 442 if (test_list_index != lines_count) { |
| 326 fprintf(stderr, "Failed to attempt all the tests!\n"); | 443 fprintf(stderr, "Failed to attempt all the tests!\n"); |
| 444 fflush(0); |
| 327 return -1; | 445 return -1; |
| 328 } | 446 } |
| 329 | |
| 330 return 0; | 447 return 0; |
| 331 } | 448 } |
| OLD | NEW |