2 * Copyright (c) The Piglit project 2007
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:
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
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.
25 #ifndef WIN32_LEAN_AND_MEAN
26 #define WIN32_LEAN_AND_MEAN
32 #include <sys/types.h>
33 #include <sys/syscall.h>
45 #if defined(PIGLIT_HAS_POSIX_CLOCK_MONOTONIC) && defined(PIGLIT_HAS_POSIX_TIMER_NOTIFY_THREAD)
51 #if defined(HAVE_SYS_TIME_H) && defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_SETRLIMIT)
53 #include <sys/resource.h>
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>
66 #if defined(HAVE_UNISTD_H)
67 #include <unistd.h> // for usleep
71 #define strcasecmp _stricmp
74 #include "piglit-util.h"
79 /* Some versions of MinGW are missing _vscprintf's declaration, although they
80 * still provide the symbol in the import library.
83 _CRTIMP
int _vscprintf(const char *format
, va_list argptr
);
86 int asprintf(char **strp
, const char *fmt
, ...)
95 va_copy(args_copy
, args
);
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.
101 length
= _vscprintf(fmt
, args_copy
);
104 length
= vsnprintf(&dummy
, sizeof dummy
, fmt
, args_copy
);
112 *strp
= malloc(size
);
118 vsnprintf(*strp
, size
, fmt
, args
);
124 #endif /* HAVE_ASPRINTF */
127 * \brief Split \a string into an array of strings.
129 * The null-terminated string \a separators is a list of characters at
130 * which to perform the splits. For example, if separators is " ,", then
131 * the function will split the string at each occurrence of ' ' and ','.
134 piglit_split_string_to_array(const char *string
, const char *separators
)
136 char **strings
, *string_copy
;
137 int i
, length
, max_words
;
139 length
= strlen(string
);
140 max_words
= length
/ 2;
141 strings
= malloc((sizeof(char*) * (max_words
+ 1)) +
142 (sizeof(char) * (length
+ 1)));
143 assert(strings
!= NULL
);
145 string_copy
= (char*) &strings
[max_words
+ 1];
146 strcpy(string_copy
, string
);
148 strings
[0] = strtok(string_copy
, separators
);
149 for (i
= 0; strings
[i
] != NULL
; ++i
) {
150 strings
[i
+ 1] = strtok(NULL
, separators
);
153 return (const char**) strings
;
156 bool piglit_is_extension_in_array(const char **haystack
, const char *needle
)
161 while (*haystack
!= NULL
) {
162 if (strcmp(*haystack
, needle
) == 0) {
171 bool piglit_is_extension_in_string(const char *haystack
, const char *needle
)
173 const unsigned needle_len
= strlen(needle
);
179 const char *const s
= strstr(haystack
, needle
);
184 if (s
[needle_len
] == ' ' || s
[needle_len
] == '\0') {
188 /* strstr found an extension whose name begins with
189 * needle, but whose name is not equal to needle.
190 * Restart the search at s + needle_len so that we
191 * don't just find the same extension again and go
192 * into an infinite loop.
194 haystack
= s
+ needle_len
;
200 /** Returns the line in the program string given the character position. */
201 int piglit_find_line(const char *program
, int position
)
204 for (i
= 0; i
< position
; i
++) {
205 if (program
[i
] == '0')
206 return -1; /* unknown line */
207 if (program
[i
] == '\n')
214 piglit_result_to_string(enum piglit_result result
)
217 case PIGLIT_FAIL
: return "fail";
218 case PIGLIT_SKIP
: return "skip";
219 case PIGLIT_WARN
: return "warn";
220 case PIGLIT_PASS
: return "pass";
222 return "Unknown result";
225 static void (*destroy_func
)(void*);
226 static void *destroy_data
;
229 piglit_report_result(enum piglit_result result
)
231 const char *result_str
= piglit_result_to_string(result
);
233 #ifdef PIGLIT_HAS_POSIX_TIMER_NOTIFY_THREAD
234 /* Ensure we only report one result in case we race with timeout */
235 static pthread_mutex_t result_lock
= PTHREAD_MUTEX_INITIALIZER
;
236 pthread_mutex_lock(&result_lock
);
241 printf("PIGLIT: {\"result\": \"%s\" }\n", result_str
);
245 destroy_func(destroy_data
);
256 #ifdef PIGLIT_HAS_POSIX_TIMER_NOTIFY_THREAD
258 timeout_expired(union sigval val
)
260 piglit_loge("Test timed out.");
261 piglit_report_result(val
.sival_int
);
266 piglit_set_timeout(double seconds
, enum piglit_result timeout_result
)
268 #ifdef PIGLIT_HAS_POSIX_TIMER_NOTIFY_THREAD
269 struct sigevent sev
= {
270 .sigev_notify
= SIGEV_THREAD
,
271 .sigev_notify_function
= timeout_expired
,
272 .sigev_value
= { .sival_int
= timeout_result
},
274 time_t sec
= seconds
;
275 struct itimerspec spec
= {
276 .it_value
= { .tv_sec
= sec
, .tv_nsec
= (seconds
- sec
) * 1e9
},
279 timer_create(CLOCK_MONOTONIC
, &sev
, &timerid
);
280 timer_settime(timerid
, 0, &spec
, NULL
);
282 piglit_logi("Cannot abort this test for timeout on this platform");
287 piglit_report_subtest_result(enum piglit_result result
, const char *format
, ...)
289 const char *result_str
= piglit_result_to_string(result
);
292 va_start(ap
, format
);
294 printf("PIGLIT: {\"subtest\": {\"");
296 printf("\" : \"%s\"}}\n", result_str
);
304 piglit_disable_error_message_boxes(void)
306 /* When Windows' error message boxes are disabled for this process (as
307 * is always the case when running through `piglit run`) we disable CRT
310 * This will disable the CRT message boxes for the main executable, but
311 * it will not disable message boxes for assertion failures inside
312 * OpenGL ICD, unless this test's executable and the OpenGL ICD DLL are
313 * both dynamically linked to the same CRT DLL. If the OpenGL ICD is
314 * statically linked to the CRT then it must do these calls itself.
318 #if _WIN32_WINNT >= 0x0600
319 uMode
= GetErrorMode();
321 uMode
= SetErrorMode(0);
324 if (uMode
& SEM_FAILCRITICALERRORS
) {
325 /* Disable assertion failure message box.
326 * http://msdn.microsoft.com/en-us/library/sas1dkb2.aspx
328 _set_error_mode(_OUT_TO_STDERR
);
335 piglit_set_line_buffering(void)
337 /* Windows doesn't immediately flush stdout/stderr after printf
338 * calls as we see on Linux. To get immediate flushing, we disable
342 setbuf(stdout
, NULL
);
343 setbuf(stderr
, NULL
);
349 piglit_general_init(void)
351 piglit_disable_error_message_boxes();
352 piglit_set_line_buffering();
357 piglit_set_rlimit(unsigned long lim
)
359 #if defined(USE_SETRLIMIT) && defined(RLIMIT_AS)
361 if (getrlimit(RLIMIT_AS
, &rl
) != -1) {
362 piglit_logi("Address space limit = %lu, max = %lu",
363 (unsigned long) rl
.rlim_cur
,
364 (unsigned long) rl
.rlim_max
);
366 if (rl
.rlim_max
> lim
) {
367 piglit_logi("Resetting limit to %lu", lim
);
371 if (setrlimit(RLIMIT_AS
, &rl
) == -1) {
372 piglit_loge("Could not set rlimit "
374 strerror(errno
), errno
);
379 piglit_loge("Cannot reset rlimit on this platform");
383 /* Merges the PASS/FAIL/SKIP for @subtest into the overall result
386 * The @all should start out initialized to PIGLIT_SKIP.
389 piglit_merge_result(enum piglit_result
*all
, enum piglit_result subtest
)
396 if (*all
== PIGLIT_SKIP
|| *all
== PIGLIT_PASS
)
400 if (*all
== PIGLIT_SKIP
)
408 char *piglit_load_text_file(const char *file_name
, unsigned *size
)
412 #if defined(USE_STDIO)
418 if (file_name
== NULL
) {
422 err
= fopen_s(&fp
, file_name
, "r");
424 if (err
|| (fp
== NULL
)) {
428 fp
= fopen(file_name
, "r");
434 if (fseek(fp
, 0, SEEK_END
) == 0) {
435 size_t len
= (size_t) ftell(fp
);
438 text
= malloc(len
+ 1);
440 size_t total_read
= 0;
443 size_t bytes
= fread(text
+ total_read
, 1,
444 len
- total_read
, fp
);
456 } while (total_read
< len
);
459 text
[total_read
] = '\0';
472 int fd
= open(file_name
, O_RDONLY
);
478 if (fstat(fd
, & st
) == 0) {
479 ssize_t total_read
= 0;
481 if (!S_ISREG(st
.st_mode
) &&
482 !S_ISLNK(st
.st_mode
)) {
483 /* not a regular file or symlink */
488 text
= malloc(st
.st_size
+ 1);
491 ssize_t bytes
= read(fd
, text
+ total_read
,
492 st
.st_size
- total_read
);
504 } while (total_read
< st
.st_size
);
506 text
[total_read
] = '\0';
520 piglit_source_dir(void)
523 const char *s
= getenv("PIGLIT_SOURCE_DIR");
526 piglit_loge("env var PIGLIT_SOURCE_DIR is undefined");
527 piglit_report_result(PIGLIT_FAIL
);
534 piglit_join_paths(char buf
[], size_t buf_size
, int n
, ...)
537 size_t size_written
= 0;
542 if (buf_size
== 0 || n
< 1)
549 const char *p
= va_arg(va
, const char*);
552 if (size_written
== buf_size
- 1)
565 *dest
= PIGLIT_PATH_SEP
;
579 piglit_time_is_monotonic(void)
581 #ifdef PIGLIT_HAS_POSIX_CLOCK_MONOTONIC
583 int r
= clock_gettime(CLOCK_MONOTONIC
, &t
);
585 return r
== 0 || (r
== -1 && errno
!= EINVAL
);
592 piglit_time_get_nano(void)
597 #ifdef PIGLIT_HAS_POSIX_CLOCK_MONOTONIC
599 int r
= clock_gettime(CLOCK_MONOTONIC
, &t
);
601 if (r
== 0 || (r
== -1 && errno
!= EINVAL
))
602 return (t
.tv_sec
* INT64_C(1000000000)) + t
.tv_nsec
;
605 gettimeofday(&tv
, NULL
);
606 return tv
.tv_usec
* INT64_C(1000) + tv
.tv_sec
* INT64_C(1000000000);
608 static LARGE_INTEGER frequency
;
609 LARGE_INTEGER counter
;
611 if (!frequency
.QuadPart
)
612 QueryPerformanceFrequency(&frequency
);
613 QueryPerformanceCounter(&counter
);
614 return counter
.QuadPart
* INT64_C(1000000000)/frequency
.QuadPart
;
619 piglit_delay_ns(int64_t time_ns
)
621 int64_t start
= piglit_time_get_nano();
627 ts
.tv_sec
= time_ns
/ 1000000000LL;
628 ts
.tv_nsec
= time_ns
- ts
.tv_sec
* 1000000000LL;
630 while (nanosleep(&ts
, &ts
) == -1 && errno
== EINTR
)
632 #elif defined(_MSC_VER)
633 Sleep(time_ns
/ 1000000);
635 usleep(time_ns
/ 1000);
638 end
= piglit_time_get_nano();
644 * Search for an argument with the given name in the argument list.
645 * If it is found, remove it and return true.
648 piglit_strip_arg(int *argc
, char *argv
[], const char *arg
)
651 for (i
= 1; i
< *argc
; i
++) {
652 if (strcmp(argv
[i
], arg
) != 0)
655 for (i
+= 1; i
< *argc
; ++i
)
666 piglit_parse_subtest_args(int *argc
, char *argv
[],
667 const struct piglit_subtest
*subtests
,
668 const char ***out_selected_subtests
,
669 size_t *out_num_selected_subtests
)
672 const char **selected_subtests
= NULL
;
673 size_t num_selected_subtests
= 0;
678 " Run all subtests.\n"
680 " %1$s -list-subtests\n"
681 " List all subtests.\n"
683 " %1$s -subtest SUBTEST [-subtest SUBTEST [...]]\n"
684 " Run only the given subtests.\n"
687 " Print this help message.\n"
690 for (j
= 1; j
< *argc
; j
++) {
691 if (streq(argv
[j
], "-h") || streq(argv
[j
], "--help")) {
692 printf(usage
, basename(argv
[0]));
694 } else if (streq(argv
[j
], "-subtest")) {
699 piglit_loge("-subtest requires an argument");
700 piglit_report_result(PIGLIT_FAIL
);
703 if (!piglit_find_subtest(subtests
, argv
[j
])) {
704 piglit_loge("Test defines no subtest with "
705 "name '%s'", argv
[j
]);
706 piglit_report_result(PIGLIT_FAIL
);
710 realloc(selected_subtests
,
711 (num_selected_subtests
+ 1)
713 selected_subtests
[num_selected_subtests
] = argv
[j
];
714 ++num_selected_subtests
;
716 /* Remove 2 arguments from the command line. */
717 for (i
= j
+ 1; i
< *argc
; i
++) {
718 argv
[i
- 2] = argv
[i
];
722 } else if (streq(argv
[j
], "-list-subtests")) {
725 if (subtests
== NULL
) {
726 piglit_loge("Test defines no subtests!");
730 for (i
= 0; !PIGLIT_SUBTEST_END(&subtests
[i
]); ++i
) {
740 *out_selected_subtests
= selected_subtests
;
741 *out_num_selected_subtests
= num_selected_subtests
;
745 const struct piglit_subtest
*
746 piglit_find_subtest(const struct piglit_subtest
*subtests
, const char *name
)
751 for (i
= 0; !PIGLIT_SUBTEST_END(&subtests
[i
]); i
++) {
752 if (strcmp(subtests
[i
].option
, name
) == 0)
760 piglit_run_selected_subtests(const struct piglit_subtest
*all_subtests
,
761 const char **selected_subtests
,
762 size_t num_selected_subtests
,
763 enum piglit_result previous_result
)
765 enum piglit_result result
= previous_result
;
767 /* print JSON list of subtests */
768 printf("PIGLIT: {\"enumerate subtests\": [");
769 if (num_selected_subtests
) {
770 const char *prefix
= "";
771 for (int i
= 0; i
< num_selected_subtests
; i
++) {
772 const char *const name
= selected_subtests
[i
];
773 const struct piglit_subtest
*subtest
=
774 piglit_find_subtest(all_subtests
, name
);
776 if (subtest
== NULL
) {
779 piglit_loge("Unknown subtest \"%s\"", name
);
780 piglit_report_result(PIGLIT_FAIL
);
782 printf("%s\"%s\"", prefix
, name
);
787 const char *prefix
= "";
788 for (int i
= 0; !PIGLIT_SUBTEST_END(&all_subtests
[i
]); i
++) {
789 printf("%s\"%s\"", prefix
, all_subtests
[i
].name
);
796 if (num_selected_subtests
) {
797 for (int i
= 0; i
< num_selected_subtests
; i
++) {
798 enum piglit_result subtest_result
;
799 const char *const name
= selected_subtests
[i
];
800 const struct piglit_subtest
*subtest
=
801 piglit_find_subtest(all_subtests
, name
);
803 subtest_result
= subtest
->subtest_func(subtest
->data
);
804 piglit_report_subtest_result(subtest_result
, "%s",
807 piglit_merge_result(&result
, subtest_result
);
810 for (int i
= 0; !PIGLIT_SUBTEST_END(&all_subtests
[i
]); i
++) {
811 const enum piglit_result subtest_result
=
812 all_subtests
[i
].subtest_func(all_subtests
[i
].data
);
813 piglit_report_subtest_result(subtest_result
, "%s",
814 all_subtests
[i
].name
);
816 piglit_merge_result(&result
, subtest_result
);
824 piglit_register_subtests(const char *names
[])
826 printf("PIGLIT: {\"enumerate subtests\": [\"%s\"", names
[0]);
827 for (int i
= 1; names
[i
]; i
++) {
828 printf(", \"%s\"", names
[i
]);
838 return syscall(SYS_gettid
);
846 piglit_get_page_size(void)
849 SYSTEM_INFO system_info
;
850 GetSystemInfo(&system_info
);
851 return system_info
.dwPageSize
;
853 return sysconf(_SC_PAGESIZE
);
859 piglit_alloc_aligned(size_t alignment
, size_t size
)
862 return _aligned_malloc(size
, alignment
);
865 if (posix_memalign(&p
, alignment
, size
) != 0) {
874 piglit_free_aligned(void *p
)
885 * \brief Reads an environment variable and interprets its value as a boolean.
887 * Recognizes 0/false/no and 1/true/yes. Other values result in the
891 piglit_env_var_as_boolean(const char *var_name
, bool default_value
)
893 const char *str
= getenv(var_name
);
895 return default_value
;
897 if (strcmp(str
, "1") == 0 ||
898 strcasecmp(str
, "true") == 0 ||
899 strcasecmp(str
, "yes") == 0) {
901 } else if (strcmp(str
, "0") == 0 ||
902 strcasecmp(str
, "false") == 0 ||
903 strcasecmp(str
, "no") == 0) {
906 return default_value
;
911 piglit_set_destroy_func(void (*destroy
)(void*), void *data
)
913 destroy_func
= destroy
;