1 /*
2 * Copyright (c) The Piglit project 2007
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
18 * VA LINUX SYSTEM, IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 * USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24 #if defined(_WIN32)
25 #ifndef WIN32_LEAN_AND_MEAN
26 #define WIN32_LEAN_AND_MEAN
27 #endif
28 #include <windows.h>
29 #endif
30
31 #ifdef __linux__
32 #include <sys/types.h>
33 #include <sys/syscall.h>
34 #endif
35
36 #include <assert.h>
37 #include <math.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <errno.h>
42 #include <inttypes.h>
43 #include <time.h>
44
45 #if defined(PIGLIT_HAS_POSIX_CLOCK_MONOTONIC) && defined(PIGLIT_HAS_POSIX_TIMER_NOTIFY_THREAD)
46 #include <pthread.h>
47 #include <signal.h>
48 #endif
49
50 #include "config.h"
51 #if defined(HAVE_SYS_TIME_H) && defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_SETRLIMIT)
52 #include <sys/time.h>
53 #include <sys/resource.h>
54 #define USE_SETRLIMIT
55 #endif
56
57 #if defined(HAVE_FCNTL_H) && defined(HAVE_SYS_STAT_H) && defined(HAVE_SYS_TYPES_H) && defined(HAVE_UNISTD_H) && !defined(_WIN32)
58 # include <sys/types.h>
59 # include <sys/stat.h>
60 # include <fcntl.h>
61 # include <unistd.h>
62 #else
63 # define USE_STDIO
64 #endif
65
66 #if defined(HAVE_UNISTD_H)
67 #include <unistd.h> // for usleep
68 #endif
69
70 #ifdef _MSC_VER
71 #define strcasecmp _stricmp
72 #endif
73
74 #include "piglit-util.h"
75
76
77 #ifndef HAVE_ASPRINTF
78
79 /* Some versions of MinGW are missing _vscprintf's declaration, although they
80 * still provide the symbol in the import library.
81 */
82 #ifdef __MINGW32__
83 _CRTIMP int _vscprintf(const char *format, va_list argptr);
84 #endif
85
asprintf(char ** strp,const char * fmt,...)86 int asprintf(char **strp, const char *fmt, ...)
87 {
88 va_list args;
89 va_list args_copy;
90 int length;
91 size_t size;
92
93 va_start(args, fmt);
94
95 va_copy(args_copy, args);
96
97 #ifdef _WIN32
98 /* We need to use _vcsprintf to calculate the length as vsnprintf returns -1
99 * if the number of characters to write is greater than count.
100 */
101 length = _vscprintf(fmt, args_copy);
102 #else
103 char dummy;
104 length = vsnprintf(&dummy, sizeof dummy, fmt, args_copy);
105 #endif
106
107 va_end(args_copy);
108
109 assert(length >= 0);
110 size = length + 1;
111
112 *strp = malloc(size);
113 if (!*strp) {
114 return -1;
115 }
116
117 va_start(args, fmt);
118 vsnprintf(*strp, size, fmt, args);
119 va_end(args);
120
121 return length;
122 }
123
124 #endif /* HAVE_ASPRINTF */
125
126 #if defined(__FreeBSD__) || defined(__DragonFly__)
127 #include <libgen.h> /* For basename(3) */
128 #endif
129
130 /**
131 * \brief Split \a string into an array of strings.
132 *
133 * The null-terminated string \a separators is a list of characters at
134 * which to perform the splits. For example, if separators is " ,", then
135 * the function will split the string at each occurence of ' ' and ','.
136 */
137 const char**
piglit_split_string_to_array(const char * string,const char * separators)138 piglit_split_string_to_array(const char *string, const char *separators)
139 {
140 char **strings, *string_copy;
141 int i, length, max_words;
142
143 length = strlen(string);
144 max_words = length / 2;
145 strings = malloc((sizeof(char*) * (max_words + 1)) +
146 (sizeof(char) * (length + 1)));
147 assert(strings != NULL);
148
149 string_copy = (char*) &strings[max_words + 1];
150 strcpy(string_copy, string);
151
152 strings[0] = strtok(string_copy, separators);
153 for (i = 0; strings[i] != NULL; ++i) {
154 strings[i + 1] = strtok(NULL, separators);
155 }
156
157 return (const char**) strings;
158 }
159
piglit_is_extension_in_array(const char ** haystack,const char * needle)160 bool piglit_is_extension_in_array(const char **haystack, const char *needle)
161 {
162 if (needle[0] == 0)
163 return false;
164
165 while (*haystack != NULL) {
166 if (strcmp(*haystack, needle) == 0) {
167 return true;
168 }
169 haystack++;
170 }
171
172 return false;
173 }
174
piglit_is_extension_in_string(const char * haystack,const char * needle)175 bool piglit_is_extension_in_string(const char *haystack, const char *needle)
176 {
177 const unsigned needle_len = strlen(needle);
178
179 if (needle_len == 0)
180 return false;
181
182 while (true) {
183 const char *const s = strstr(haystack, needle);
184
185 if (s == NULL)
186 return false;
187
188 if (s[needle_len] == ' ' || s[needle_len] == '\0') {
189 return true;
190 }
191
192 /* strstr found an extension whose name begins with
193 * needle, but whose name is not equal to needle.
194 * Restart the search at s + needle_len so that we
195 * don't just find the same extension again and go
196 * into an infinite loop.
197 */
198 haystack = s + needle_len;
199 }
200
201 return false;
202 }
203
204 /** Returns the line in the program string given the character position. */
piglit_find_line(const char * program,int position)205 int piglit_find_line(const char *program, int position)
206 {
207 int i, line = 1;
208 for (i = 0; i < position; i++) {
209 if (program[i] == '0')
210 return -1; /* unknown line */
211 if (program[i] == '\n')
212 line++;
213 }
214 return line;
215 }
216
217 const char *
piglit_result_to_string(enum piglit_result result)218 piglit_result_to_string(enum piglit_result result)
219 {
220 switch (result) {
221 case PIGLIT_FAIL: return "fail";
222 case PIGLIT_SKIP: return "skip";
223 case PIGLIT_WARN: return "warn";
224 case PIGLIT_PASS: return "pass";
225 }
226 return "Unknown result";
227 }
228
229 void
piglit_report_result(enum piglit_result result)230 piglit_report_result(enum piglit_result result)
231 {
232 const char *result_str = piglit_result_to_string(result);
233
234 #ifdef PIGLIT_HAS_POSIX_TIMER_NOTIFY_THREAD
235 /* Ensure we only report one result in case we race with timeout */
236 static pthread_mutex_t result_lock = PTHREAD_MUTEX_INITIALIZER;
237 pthread_mutex_lock(&result_lock);
238 #endif
239
240 fflush(stderr);
241
242 printf("PIGLIT: {\"result\": \"%s\" }\n", result_str);
243 fflush(stdout);
244
245 switch(result) {
246 case PIGLIT_PASS:
247 case PIGLIT_SKIP:
248 case PIGLIT_WARN:
249 exit(0);
250 default:
251 exit(1);
252 }
253 }
254
255 #ifdef PIGLIT_HAS_POSIX_TIMER_NOTIFY_THREAD
256 static void
timeout_expired(union sigval val)257 timeout_expired(union sigval val)
258 {
259 piglit_loge("Test timed out.");
260 piglit_report_result(val.sival_int);
261 }
262 #endif
263
264 void
piglit_set_timeout(double seconds,enum piglit_result timeout_result)265 piglit_set_timeout(double seconds, enum piglit_result timeout_result)
266 {
267 #ifdef PIGLIT_HAS_POSIX_TIMER_NOTIFY_THREAD
268 struct sigevent sev = {
269 .sigev_notify = SIGEV_THREAD,
270 .sigev_notify_function = timeout_expired,
271 .sigev_value = { .sival_int = timeout_result },
272 };
273 time_t sec = seconds;
274 struct itimerspec spec = {
275 .it_value = { .tv_sec = sec, .tv_nsec = (seconds - sec) * 1e9 },
276 };
277 timer_t timerid;
278 timer_create(CLOCK_MONOTONIC, &sev, &timerid);
279 timer_settime(timerid, 0, &spec, NULL);
280 #else
281 piglit_logi("Cannot abort this test for timeout on this platform");
282 #endif
283 }
284
285 void
piglit_report_subtest_result(enum piglit_result result,const char * format,...)286 piglit_report_subtest_result(enum piglit_result result, const char *format, ...)
287 {
288 const char *result_str = piglit_result_to_string(result);
289 va_list ap;
290
291 va_start(ap, format);
292
293 printf("PIGLIT: {\"subtest\": {\"");
294 vprintf(format, ap);
295 printf("\" : \"%s\"}}\n", result_str);
296 fflush(stdout);
297
298 va_end(ap);
299 }
300
301
302 static void
piglit_disable_error_message_boxes(void)303 piglit_disable_error_message_boxes(void)
304 {
305 /* When Windows' error message boxes are disabled for this process (as
306 * is always the case when running through `piglit run`) we disable CRT
307 * message boxes too.
308 *
309 * This will disable the CRT message boxes for the main executable, but
310 * it will not disable message boxes for assertion failures inside
311 * OpenGL ICD, unless this test's executable and the OpenGL ICD DLL are
312 * both dynamically linked to the same CRT DLL. If the OpenGL ICD is
313 * statically linked to the CRT then it must do these calls itself.
314 */
315 #ifdef _WIN32
316 UINT uMode;
317 #if _WIN32_WINNT >= 0x0600
318 uMode = GetErrorMode();
319 #else
320 uMode = SetErrorMode(0);
321 SetErrorMode(uMode);
322 #endif
323 if (uMode & SEM_FAILCRITICALERRORS) {
324 /* Disable assertion failure message box.
325 * http://msdn.microsoft.com/en-us/library/sas1dkb2.aspx
326 */
327 _set_error_mode(_OUT_TO_STDERR);
328 }
329 #endif /* _WIN32 */
330 }
331
332
333 static void
piglit_set_line_buffering(void)334 piglit_set_line_buffering(void)
335 {
336 /* Windows doesn't immediately flush stdout/stderr after printf
337 * calls as we see on Linux. To get immediate flushing, we disable
338 * buffering here.
339 */
340 #ifdef _WIN32
341 setbuf(stdout, NULL);
342 setbuf(stderr, NULL);
343 #endif
344 }
345
346
347 void
piglit_general_init(void)348 piglit_general_init(void)
349 {
350 piglit_disable_error_message_boxes();
351 piglit_set_line_buffering();
352 }
353
354
355 void
piglit_set_rlimit(unsigned long lim)356 piglit_set_rlimit(unsigned long lim)
357 {
358 #if defined(USE_SETRLIMIT) && defined(RLIMIT_AS)
359 struct rlimit rl;
360 if (getrlimit(RLIMIT_AS, &rl) != -1) {
361 piglit_logi("Address space limit = %lu, max = %lu",
362 (unsigned long) rl.rlim_cur,
363 (unsigned long) rl.rlim_max);
364
365 if (rl.rlim_max > lim) {
366 piglit_logi("Resetting limit to %lu", lim);
367
368 rl.rlim_cur = lim;
369 rl.rlim_max = lim;
370 if (setrlimit(RLIMIT_AS, &rl) == -1) {
371 piglit_loge("Could not set rlimit "
372 "due to: %s (%d)",
373 strerror(errno), errno);
374 }
375 }
376 }
377 #else
378 piglit_loge("Cannot reset rlimit on this platform");
379 #endif
380 }
381
382 /* Merges the PASS/FAIL/SKIP for @subtest into the overall result
383 * @all.
384 *
385 * The @all should start out initialized to PIGLIT_SKIP.
386 */
387 void
piglit_merge_result(enum piglit_result * all,enum piglit_result subtest)388 piglit_merge_result(enum piglit_result *all, enum piglit_result subtest)
389 {
390 switch (subtest) {
391 case PIGLIT_FAIL:
392 *all = PIGLIT_FAIL;
393 break;
394 case PIGLIT_WARN:
395 if (*all == PIGLIT_SKIP || *all == PIGLIT_PASS)
396 *all = PIGLIT_WARN;
397 break;
398 case PIGLIT_PASS:
399 if (*all == PIGLIT_SKIP)
400 *all = PIGLIT_PASS;
401 break;
402 case PIGLIT_SKIP:
403 break;
404 }
405 }
406
piglit_load_text_file(const char * file_name,unsigned * size)407 char *piglit_load_text_file(const char *file_name, unsigned *size)
408 {
409 char *text = NULL;
410
411 #if defined(USE_STDIO)
412 FILE *fp;
413
414 # ifdef HAVE_FOPEN_S
415 errno_t err;
416
417 if (file_name == NULL) {
418 return NULL;
419 }
420
421 err = fopen_s(&fp, file_name, "r");
422
423 if (err || (fp == NULL)) {
424 return NULL;
425 }
426 # else
427 fp = fopen(file_name, "r");
428 if (fp == NULL) {
429 return NULL;
430 }
431 # endif
432
433 if (fseek(fp, 0, SEEK_END) == 0) {
434 size_t len = (size_t) ftell(fp);
435 rewind(fp);
436
437 text = malloc(len + 1);
438 if (text != NULL) {
439 size_t total_read = 0;
440
441 do {
442 size_t bytes = fread(text + total_read, 1,
443 len - total_read, fp);
444
445 total_read += bytes;
446 if (feof(fp)) {
447 break;
448 }
449
450 if (ferror(fp)) {
451 free(text);
452 text = NULL;
453 break;
454 }
455 } while (total_read < len);
456
457 if (text != NULL) {
458 text[total_read] = '\0';
459 }
460
461 if (size != NULL) {
462 *size = total_read;
463 }
464 }
465 }
466
467 fclose(fp);
468 return text;
469 #else
470 struct stat st;
471 int fd = open(file_name, O_RDONLY);
472
473 if (fd < 0) {
474 return NULL;
475 }
476
477 if (fstat(fd, & st) == 0) {
478 ssize_t total_read = 0;
479
480 if (!S_ISREG(st.st_mode) &&
481 !S_ISLNK(st.st_mode)) {
482 /* not a regular file or symlink */
483 close(fd);
484 return NULL;
485 }
486
487 text = malloc(st.st_size + 1);
488 if (text != NULL) {
489 do {
490 ssize_t bytes = read(fd, text + total_read,
491 st.st_size - total_read);
492 if (bytes < 0) {
493 free(text);
494 text = NULL;
495 break;
496 }
497
498 if (bytes == 0) {
499 break;
500 }
501
502 total_read += bytes;
503 } while (total_read < st.st_size);
504
505 text[total_read] = '\0';
506 if (size != NULL) {
507 *size = total_read;
508 }
509 }
510 }
511
512 close(fd);
513
514 return text;
515 #endif
516 }
517
518 const char*
piglit_source_dir(void)519 piglit_source_dir(void)
520 {
521
522 const char *s = getenv("PIGLIT_SOURCE_DIR");
523
524 if (s == NULL) {
525 piglit_loge("env var PIGLIT_SOURCE_DIR is undefined");
526 piglit_report_result(PIGLIT_FAIL);
527 }
528
529 return s;
530 }
531
532 size_t
piglit_join_paths(char buf[],size_t buf_size,int n,...)533 piglit_join_paths(char buf[], size_t buf_size, int n, ...)
534 {
535 char *dest = buf;
536 size_t size_written = 0;
537
538 int i;
539 va_list va;
540
541 if (buf_size == 0 || n < 1)
542 return 0;
543
544 va_start(va, n);
545
546 i = 0;
547 while (true) {
548 const char *p = va_arg(va, const char*);
549
550 while (*p != 0) {
551 if (size_written == buf_size - 1)
552 goto write_null;
553
554 *dest = *p;
555 ++dest;
556 ++p;
557 ++size_written;
558 }
559
560 ++i;
561 if (i == n)
562 break;
563
564 *dest = PIGLIT_PATH_SEP;
565 ++dest;
566 ++size_written;
567 }
568
569 write_null:
570 *dest = '\0';
571 ++size_written;
572
573 va_end(va);
574 return size_written;
575 }
576
577 bool
piglit_time_is_monotonic(void)578 piglit_time_is_monotonic(void)
579 {
580 #ifdef PIGLIT_HAS_POSIX_CLOCK_MONOTONIC
581 struct timespec t;
582 int r = clock_gettime(CLOCK_MONOTONIC, &t);
583
584 return r == 0 || (r == -1 && errno != EINVAL);
585 #else
586 return false;
587 #endif
588 }
589
590 int64_t
piglit_time_get_nano(void)591 piglit_time_get_nano(void)
592 {
593 #if !defined(_WIN32)
594 struct timeval tv;
595
596 #ifdef PIGLIT_HAS_POSIX_CLOCK_MONOTONIC
597 struct timespec t;
598 int r = clock_gettime(CLOCK_MONOTONIC, &t);
599
600 if (r == 0 || (r == -1 && errno != EINVAL))
601 return (t.tv_sec * INT64_C(1000000000)) + t.tv_nsec;
602 #endif
603
604 gettimeofday(&tv, NULL);
605 return tv.tv_usec * INT64_C(1000) + tv.tv_sec * INT64_C(1000000000);
606 #else
607 static LARGE_INTEGER frequency;
608 LARGE_INTEGER counter;
609
610 if (!frequency.QuadPart)
611 QueryPerformanceFrequency(&frequency);
612 QueryPerformanceCounter(&counter);
613 return counter.QuadPart * INT64_C(1000000000)/frequency.QuadPart;
614 #endif
615 }
616
617 int64_t
piglit_delay_ns(int64_t time_ns)618 piglit_delay_ns(int64_t time_ns)
619 {
620 int64_t start = piglit_time_get_nano();
621 int64_t end;
622
623 #ifdef __linux__
624 struct timespec ts;
625
626 ts.tv_sec = time_ns / 1000000000LL;
627 ts.tv_nsec = time_ns - ts.tv_sec * 1000000000LL;
628
629 while (nanosleep(&ts, &ts) == -1 && errno == EINTR)
630 ;
631 #elif defined(_MSC_VER)
632 Sleep(time_ns / 1000000);
633 #else
634 usleep(time_ns / 1000);
635 #endif
636
637 end = piglit_time_get_nano();
638
639 return end - start;
640 }
641
642 /**
643 * Search for an argument with the given name in the argument list.
644 * If it is found, remove it and return true.
645 */
646 bool
piglit_strip_arg(int * argc,char * argv[],const char * arg)647 piglit_strip_arg(int *argc, char *argv[], const char *arg)
648 {
649 int i;
650 for (i = 1; i < *argc; i++) {
651 if (strcmp(argv[i], arg) != 0)
652 continue;
653
654 for (i += 1; i < *argc; ++i)
655 argv[i-1] = argv[i];
656
657 *argc -= 1;
658 return true;
659 }
660
661 return false;
662 }
663
664 void
piglit_parse_subtest_args(int * argc,char * argv[],const struct piglit_subtest * subtests,const char *** out_selected_subtests,size_t * out_num_selected_subtests)665 piglit_parse_subtest_args(int *argc, char *argv[],
666 const struct piglit_subtest *subtests,
667 const char ***out_selected_subtests,
668 size_t *out_num_selected_subtests)
669 {
670 int j;
671 const char **selected_subtests = NULL;
672 size_t num_selected_subtests = 0;
673
674 const char *usage =
675 "usage:\n"
676 " %1$s\n"
677 " Run all subtests.\n"
678 "\n"
679 " %1$s -list-subtests\n"
680 " List all subtests.\n"
681 "\n"
682 " %1$s -subtest SUBTEST [-subtest SUBTEST [...]]\n"
683 " Run only the given subtests.\n"
684 "\n"
685 " %1$s -h|--help\n"
686 " Print this help message.\n"
687 ;
688
689 for (j = 1; j < *argc; j++) {
690 if (streq(argv[j], "-h") || streq(argv[j], "--help")) {
691 printf(usage, basename(argv[0]));
692 exit(EXIT_SUCCESS);
693 } else if (streq(argv[j], "-subtest")) {
694 int i;
695
696 ++j;
697 if (j >= *argc) {
698 piglit_loge("-subtest requires an argument");
699 piglit_report_result(PIGLIT_FAIL);
700 }
701
702 if (!piglit_find_subtest(subtests, argv[j])) {
703 piglit_loge("Test defines no subtest with "
704 "name '%s'", argv[j]);
705 piglit_report_result(PIGLIT_FAIL);
706 }
707
708 selected_subtests =
709 realloc(selected_subtests,
710 (num_selected_subtests + 1)
711 * sizeof(char*));
712 selected_subtests[num_selected_subtests] = argv[j];
713 ++num_selected_subtests;
714
715 /* Remove 2 arguments from the command line. */
716 for (i = j + 1; i < *argc; i++) {
717 argv[i - 2] = argv[i];
718 }
719 *argc -= 2;
720 j -= 2;
721 } else if (streq(argv[j], "-list-subtests")) {
722 int i;
723
724 if (subtests == NULL) {
725 piglit_loge("Test defines no subtests!");
726 exit(EXIT_FAILURE);
727 }
728
729 for (i = 0; !PIGLIT_SUBTEST_END(&subtests[i]); ++i) {
730 printf("%s: %s\n",
731 subtests[i].option,
732 subtests[i].name);
733 }
734
735 exit(EXIT_SUCCESS);
736 }
737 }
738
739 *out_selected_subtests = selected_subtests;
740 *out_num_selected_subtests = num_selected_subtests;
741 }
742
743
744 const struct piglit_subtest *
piglit_find_subtest(const struct piglit_subtest * subtests,const char * name)745 piglit_find_subtest(const struct piglit_subtest *subtests, const char *name)
746 {
747 unsigned i;
748
749 for (i = 0; !PIGLIT_SUBTEST_END(&subtests[i]); i++) {
750 if (strcmp(subtests[i].option, name) == 0)
751 return &subtests[i];
752 }
753
754 return NULL;
755 }
756
757 enum piglit_result
piglit_run_selected_subtests(const struct piglit_subtest * all_subtests,const char ** selected_subtests,size_t num_selected_subtests,enum piglit_result previous_result)758 piglit_run_selected_subtests(const struct piglit_subtest *all_subtests,
759 const char **selected_subtests,
760 size_t num_selected_subtests,
761 enum piglit_result previous_result)
762 {
763 enum piglit_result result = previous_result;
764
765 /* print JSON list of subtests */
766 printf("PIGLIT: {\"enumerate subtests\": [");
767 if (num_selected_subtests) {
768 const char *prefix = "";
769 for (int i = 0; i < num_selected_subtests; i++) {
770 const char *const name = selected_subtests[i];
771 const struct piglit_subtest *subtest =
772 piglit_find_subtest(all_subtests, name);
773
774 if (subtest == NULL) {
775 printf("]}\n");
776 fflush(stdout);
777 piglit_loge("Unknown subtest \"%s\"", name);
778 piglit_report_result(PIGLIT_FAIL);
779 }
780 printf("%s\"%s\"", prefix, name);
781 prefix = ", ";
782
783 }
784 } else {
785 const char *prefix = "";
786 for (int i = 0; !PIGLIT_SUBTEST_END(&all_subtests[i]); i++) {
787 printf("%s\"%s\"", prefix, all_subtests[i].name);
788 prefix = ", ";
789 }
790 }
791 printf("]}\n");
792 fflush(stdout);
793
794 if (num_selected_subtests) {
795 for (int i = 0; i < num_selected_subtests; i++) {
796 enum piglit_result subtest_result;
797 const char *const name = selected_subtests[i];
798 const struct piglit_subtest *subtest =
799 piglit_find_subtest(all_subtests, name);
800
801 subtest_result = subtest->subtest_func(subtest->data);
802 piglit_report_subtest_result(subtest_result, "%s",
803 subtest->name);
804
805 piglit_merge_result(&result, subtest_result);
806 }
807 } else {
808 for (int i = 0; !PIGLIT_SUBTEST_END(&all_subtests[i]); i++) {
809 const enum piglit_result subtest_result =
810 all_subtests[i].subtest_func(all_subtests[i].data);
811 piglit_report_subtest_result(subtest_result, "%s",
812 all_subtests[i].name);
813
814 piglit_merge_result(&result, subtest_result);
815 }
816 }
817
818 return result;
819 }
820
821 void
piglit_register_subtests(const char * names[])822 piglit_register_subtests(const char *names[])
823 {
824 printf("PIGLIT: {\"enumerate subtests\": [\"%s\"", names[0]);
825 for (int i = 1; names[i]; i++) {
826 printf(", \"%s\"", names[i]);
827 }
828 printf("]}\n");
829 fflush(stdout);
830 }
831
832 uint64_t
piglit_gettid(void)833 piglit_gettid(void)
834 {
835 #ifdef __linux__
836 return syscall(SYS_gettid);
837 #else
838 return 0;
839 #endif
840 }
841
842
843 size_t
piglit_get_page_size(void)844 piglit_get_page_size(void)
845 {
846 #if defined(_WIN32)
847 SYSTEM_INFO system_info;
848 GetSystemInfo(&system_info);
849 return system_info.dwPageSize;
850 #else
851 return sysconf(_SC_PAGESIZE);
852 #endif
853 }
854
855
856 void *
piglit_alloc_aligned(size_t alignment,size_t size)857 piglit_alloc_aligned(size_t alignment, size_t size)
858 {
859 #if defined(_WIN32)
860 return _aligned_malloc(size, alignment);
861 #else
862 void *p;
863 if (posix_memalign(&p, alignment, size) != 0) {
864 return NULL;
865 }
866 return p;
867 #endif
868 }
869
870
871 void
piglit_free_aligned(void * p)872 piglit_free_aligned(void *p)
873 {
874 #if defined(_WIN32)
875 _aligned_free(p);
876 #else
877 free(p);
878 #endif
879 }
880
881
882 /**
883 * \brief Reads an environment variable and interprets its value as a boolean.
884 *
885 * Recognizes 0/false/no and 1/true/yes. Other values result in the
886 * \a default_value.
887 */
888 bool
piglit_env_var_as_boolean(const char * var_name,bool default_value)889 piglit_env_var_as_boolean(const char *var_name, bool default_value)
890 {
891 const char *str = getenv(var_name);
892 if (str == NULL)
893 return default_value;
894
895 if (strcmp(str, "1") == 0 ||
896 strcasecmp(str, "true") == 0 ||
897 strcasecmp(str, "yes") == 0) {
898 return true;
899 } else if (strcmp(str, "0") == 0 ||
900 strcasecmp(str, "false") == 0 ||
901 strcasecmp(str, "no") == 0) {
902 return false;
903 } else {
904 return default_value;
905 }
906 }
907