Skip to content

Commit dde5892

Browse files
Merge pull request #440 from adierking/windowstests
tests: port the test harness to Windows
2 parents 618b070 + 6e78b6d commit dde5892

File tree

8 files changed

+412
-39
lines changed

8 files changed

+412
-39
lines changed

tests/CMakeLists.txt

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
if(CMAKE_SYSTEM_NAME STREQUAL Windows)
33
execute_process(COMMAND
4-
"${CMAKE_COMMAND}" -E copy "${PROJECT_SOURCE_DIR}/private"
4+
"${CMAKE_COMMAND}" -E copy_directory "${PROJECT_SOURCE_DIR}/private"
55
"${CMAKE_CURRENT_BINARY_DIR}/dispatch")
66
execute_process(COMMAND
77
"${CMAKE_COMMAND}" -E copy "${CMAKE_CURRENT_SOURCE_DIR}/leaks-wrapper.sh"
@@ -36,6 +36,15 @@ if(BSD_OVERLAY_FOUND)
3636
PRIVATE
3737
${BSD_OVERLAY_CFLAGS})
3838
endif()
39+
if (WIN32)
40+
target_sources(bsdtests
41+
PRIVATE
42+
generic_win_port.c)
43+
target_compile_definitions(bsdtests
44+
PUBLIC
45+
_CRT_NONSTDC_NO_WARNINGS
46+
_CRT_SECURE_NO_WARNINGS)
47+
endif ()
3948

4049
add_executable(bsdtestharness
4150
bsdtestharness.c)
@@ -91,11 +100,11 @@ function(add_unit_test name)
91100
endif()
92101
if("${CMAKE_C_SIMULATE_ID}" STREQUAL "MSVC")
93102
target_compile_options(${name} PRIVATE -Xclang -fblocks)
103+
target_compile_options(${name} PRIVATE /W3 -Wno-deprecated-declarations)
94104
else()
95105
target_compile_options(${name} PRIVATE -fblocks)
106+
target_compile_options(${name} PRIVATE -Wall -Wno-deprecated-declarations)
96107
endif()
97-
# TODO(compnerd) make this portable
98-
target_compile_options(${name} PRIVATE -Wall -Wno-deprecated-declarations)
99108
dispatch_set_linker(${name})
100109
target_link_libraries(${name}
101110
PRIVATE
@@ -187,4 +196,4 @@ target_link_libraries(dispatch_group PRIVATE m)
187196
target_link_libraries(dispatch_timer_short PRIVATE m)
188197

189198
# test-specific compile options
190-
target_compile_options(dispatch_c99 PRIVATE -std=c99)
199+
set_target_properties(dispatch_c99 PROPERTIES C_STANDARD 99)

tests/bsdtestharness.c

Lines changed: 71 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,33 +20,29 @@
2020

2121
#include <dispatch/dispatch.h>
2222
#include <assert.h>
23-
#include <spawn.h>
2423
#include <stdio.h>
2524
#include <stdlib.h>
2625
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
26+
#include <spawn.h>
27+
#include <sys/resource.h>
28+
#include <sys/time.h>
29+
#include <sys/wait.h>
2730
#include <unistd.h>
31+
#elif defined(_WIN32)
32+
#include <generic_win_port.h>
33+
#include <Psapi.h>
34+
#include <Windows.h>
2835
#endif
2936
#include <signal.h>
3037
#ifdef __APPLE__
3138
#include <mach/clock_types.h>
3239
#include <mach-o/arch.h>
3340
#endif
34-
#include <sys/resource.h>
35-
#include <sys/time.h>
36-
#if defined(__linux__) || defined(__FreeBSD__)
37-
#include <sys/wait.h>
38-
#endif
3941

4042
#include <bsdtests.h>
4143

44+
#if !defined(_WIN32)
4245
extern char **environ;
43-
44-
#ifdef __linux__
45-
// Linux lacks the DISPATCH_SOURCE_TYPE_PROC functionality
46-
// the real test harness needs.
47-
#define SIMPLE_TEST_HARNESS 1
48-
#else
49-
#define SIMPLE_TEST_HARNESS 0
5046
#endif
5147

5248
int
@@ -131,25 +127,43 @@ main(int argc, char *argv[])
131127
_Exit(EXIT_FAILURE);
132128
}
133129
}
130+
#elif defined(_WIN32)
131+
(void)res;
132+
WCHAR *cmdline = argv_to_command_line(newargv);
133+
if (!cmdline) {
134+
fprintf(stderr, "argv_to_command_line() failed\n");
135+
exit(EXIT_FAILURE);
136+
}
137+
STARTUPINFOW si = {.cb = sizeof(si)};
138+
PROCESS_INFORMATION pi;
139+
BOOL created = CreateProcessW(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
140+
DWORD error = GetLastError();
141+
free(cmdline);
142+
if (!created) {
143+
print_winapi_error("CreateProcessW", error);
144+
exit(EXIT_FAILURE);
145+
}
146+
pid = (pid_t)pi.dwProcessId;
134147
#else
135148
#error "bsdtestharness not implemented on this platform"
136149
#endif
137150

138151
//fprintf(stderr, "pid = %d\n", pid);
139152
assert(pid > 0);
140153

141-
#if SIMPLE_TEST_HARNESS
154+
#if defined(__linux__)
142155
int status;
143156
struct rusage usage;
144157
struct timeval tv_stop, tv_wall;
145158

159+
int res2 = wait4(pid, &status, 0, &usage);
160+
(void)res2;
161+
146162
gettimeofday(&tv_stop, NULL);
147163
tv_wall.tv_sec = tv_stop.tv_sec - tv_start.tv_sec;
148164
tv_wall.tv_sec -= (tv_stop.tv_usec < tv_start.tv_usec);
149165
tv_wall.tv_usec = labs(tv_stop.tv_usec - tv_start.tv_usec);
150166

151-
int res2 = wait4(pid, &status, 0, &usage);
152-
(void)res2;
153167
assert(res2 != -1);
154168
test_long("Process exited", (WIFEXITED(status) && WEXITSTATUS(status) && WEXITSTATUS(status) != 0xff) || WIFSIGNALED(status), 0);
155169
printf("[PERF]\twall time: %ld.%06ld\n", tv_wall.tv_sec, tv_wall.tv_usec);
@@ -161,6 +175,46 @@ main(int argc, char *argv[])
161175
printf("[PERF]\tvoluntary context switches: %ld\n", usage.ru_nvcsw);
162176
printf("[PERF]\tinvoluntary context switches: %ld\n", usage.ru_nivcsw);
163177
exit((WIFEXITED(status) && WEXITSTATUS(status)) || WIFSIGNALED(status));
178+
#elif defined(_WIN32)
179+
if (WaitForSingleObject(pi.hProcess, INFINITE) != WAIT_OBJECT_0) {
180+
print_winapi_error("WaitForSingleObject", GetLastError());
181+
exit(EXIT_FAILURE);
182+
}
183+
184+
struct timeval tv_stop, tv_wall;
185+
gettimeofday(&tv_stop, NULL);
186+
tv_wall.tv_sec = tv_stop.tv_sec - tv_start.tv_sec;
187+
tv_wall.tv_sec -= (tv_stop.tv_usec < tv_start.tv_usec);
188+
tv_wall.tv_usec = labs(tv_stop.tv_usec - tv_start.tv_usec);
189+
190+
DWORD status;
191+
if (!GetExitCodeProcess(pi.hProcess, &status)) {
192+
print_winapi_error("GetExitCodeProcess", GetLastError());
193+
exit(EXIT_FAILURE);
194+
}
195+
196+
FILETIME create_time, exit_time, kernel_time, user_time;
197+
if (!GetProcessTimes(pi.hProcess, &create_time, &exit_time, &kernel_time, &user_time)) {
198+
print_winapi_error("GetProcessTimes", GetLastError());
199+
exit(EXIT_FAILURE);
200+
}
201+
struct timeval utime, stime;
202+
filetime_to_timeval(&utime, &user_time);
203+
filetime_to_timeval(&stime, &kernel_time);
204+
205+
PROCESS_MEMORY_COUNTERS counters;
206+
if (!GetProcessMemoryInfo(pi.hProcess, &counters, sizeof(counters))) {
207+
print_winapi_error("GetProcessMemoryInfo", GetLastError());
208+
exit(EXIT_FAILURE);
209+
}
210+
211+
test_long("Process exited", status == 0 || status == 0xff, 1);
212+
printf("[PERF]\twall time: %ld.%06ld\n", tv_wall.tv_sec, tv_wall.tv_usec);
213+
printf("[PERF]\tuser time: %ld.%06ld\n", utime.tv_sec, utime.tv_usec);
214+
printf("[PERF]\tsystem time: %ld.%06ld\n", stime.tv_sec, stime.tv_usec);
215+
printf("[PERF]\tmax working set size: %zu\n", counters.PeakWorkingSetSize);
216+
printf("[PERF]\tpage faults: %lu\n", counters.PageFaultCount);
217+
exit(status ? EXIT_FAILURE : EXIT_SUCCESS);
164218
#else
165219
dispatch_queue_t main_q = dispatch_get_main_queue();
166220

@@ -219,7 +273,7 @@ main(int argc, char *argv[])
219273
kill(pid, SIGCONT);
220274

221275
dispatch_main();
222-
#endif // SIMPLE_TEST_HARNESS
276+
#endif
223277

224278
return 0;
225279
}

tests/bsdtests.c

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,16 @@
2929
#include <unistd.h>
3030
#endif
3131
#include <errno.h>
32-
#include <sys/errno.h>
33-
#include <sys/wait.h>
3432
#include <string.h>
3533
#ifdef __APPLE__
3634
#include <crt_externs.h>
3735
#include <mach/mach_error.h>
38-
#endif
3936
#include <spawn.h>
37+
#include <sys/wait.h>
38+
#endif
39+
#if defined(_WIN32)
40+
#include <generic_win_port.h>
41+
#endif
4042
#include <inttypes.h>
4143
#include "bsdtests.h"
4244

@@ -454,18 +456,11 @@ test_start(const char* desc)
454456
usleep(100000); // give 'gdb --waitfor=' a chance to find this proc
455457
}
456458

457-
#if defined(__linux__) || defined(__FreeBSD__)
458-
static char** get_environment(void)
459-
{
460-
extern char **environ;
461-
return environ;
462-
}
463-
#else
459+
#if defined(__APPLE__) && defined(__MACH__)
464460
static char** get_environment(void)
465461
{
466462
return (* _NSGetEnviron());
467463
}
468-
#endif
469464

470465
void
471466
test_leaks_pid(const char *name, pid_t pid)
@@ -517,15 +512,18 @@ test_leaks(const char *name)
517512
{
518513
test_leaks_pid(name, getpid());
519514
}
515+
#endif
520516

521517
void
522518
test_stop_after_delay(void *delay)
523519
{
524520
if (delay != NULL) {
525-
sleep((uint)(intptr_t)delay);
521+
sleep((unsigned int)(intptr_t)delay);
526522
}
527523

524+
#if defined(__APPLE__) && defined(__MACH__)
528525
test_leaks(NULL);
526+
#endif
529527

530528
fflush(stdout);
531529
_exit(_test_exit_code);

tests/bsdtests.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,18 +63,22 @@ __BASENAME__(const char *_str_)
6363
}
6464
#define __SOURCE_FILE__ __BASENAME__(__FILE__)
6565

66-
__BEGIN_DECLS
66+
#if defined(__cplusplus)
67+
extern "C" {
68+
#endif
6769

6870
/**
6971
* test_start() provides the TEST token. Use this once per test "tool"
7072
*/
7173
void test_start(const char* desc);
7274

75+
#if defined(__APPLE__) && defined(__MACH__)
7376
/**
7477
* Explicitly runs the 'leaks' test without stopping the process.
7578
*/
7679
void test_leaks_pid(const char *name, pid_t pid);
7780
void test_leaks(const char *name);
81+
#endif
7882

7983
/**
8084
* test_stop() checks for leaks during the tests using leaks-wrapper. Use this at the end of each "tool"
@@ -179,6 +183,8 @@ void _test_skip(const char* file, long line, const char* desc);
179183
#define test_skip2(m) _test_skip("", 0, m)
180184
void test_skip_format(const char *format, ...) __printflike(1,2);
181185

182-
__END_DECLS
186+
#if defined(__cplusplus)
187+
} /* extern "C" */
188+
#endif
183189

184190
#endif /* __BSD_TEST_H__ */

tests/dispatch_test.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,16 @@
2929
#include <stdio.h>
3030
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
3131
#include <unistd.h>
32-
#endif
3332
#if __has_include(<sys/event.h>)
3433
#define HAS_SYS_EVENT_H 1
3534
#include <sys/event.h>
3635
#else
3736
#include <sys/poll.h>
3837
#endif
38+
#elif defined(_WIN32)
39+
#include <io.h>
40+
#include <Windows.h>
41+
#endif
3942
#include <assert.h>
4043

4144
#include <dispatch/dispatch.h>
@@ -68,6 +71,20 @@ dispatch_test_check_evfilt_read_for_fd(int fd)
6871
int r = kevent(kq, &ke, 1, &ke, 1, &t);
6972
close(kq);
7073
return r > 0;
74+
#elif defined(_WIN32)
75+
HANDLE handle = (HANDLE)_get_osfhandle(fd);
76+
// A zero-distance move retrieves the file pointer
77+
LARGE_INTEGER currentPosition;
78+
LARGE_INTEGER distance = {.QuadPart = 0};
79+
if (!SetFilePointerEx(handle, distance, &currentPosition, FILE_CURRENT)) {
80+
return false;
81+
}
82+
// If we are not at the end, assume the file is readable
83+
LARGE_INTEGER fileSize;
84+
if (GetFileSizeEx(handle, &fileSize) == 0) {
85+
return false;
86+
}
87+
return currentPosition.QuadPart < fileSize.QuadPart;
7188
#else
7289
struct pollfd pfd = {
7390
.fd = fd,
@@ -141,6 +158,10 @@ dispatch_test_get_large_file(void)
141158
close(temp_fd);
142159
free(file_buf);
143160
return path;
161+
#elif defined(_WIN32)
162+
// TODO
163+
fprintf(stderr, "dispatch_test_get_large_file() not implemented on Windows\n");
164+
abort();
144165
#else
145166
#error "dispatch_test_get_large_file not implemented on this platform"
146167
#endif
@@ -154,6 +175,8 @@ dispatch_test_release_large_file(const char *path)
154175
(void)path;
155176
#elif defined(__unix__)
156177
unlink(path);
178+
#elif defined(_WIN32)
179+
// TODO
157180
#else
158181
#error "dispatch_test_release_large_file not implemented on this platform"
159182
#endif

tests/dispatch_test.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@
1818
* @APPLE_APACHE_LICENSE_HEADER_END@
1919
*/
2020

21-
#include <sys/cdefs.h>
2221
#include <stdbool.h>
2322
#include <dispatch/dispatch.h>
2423

2524
#if defined(__linux__) || defined(__FreeBSD__)
2625
#include <generic_unix_port.h>
26+
#elif defined(_WIN32)
27+
#include <generic_win_port.h>
2728
#endif
2829

2930
#define test_group_wait(g) do { \
@@ -33,7 +34,9 @@
3334
test_stop(); \
3435
} } while (0)
3536

36-
__BEGIN_DECLS
37+
#if defined(__cplusplus)
38+
extern "C" {
39+
#endif
3740

3841
void dispatch_test_start(const char* desc);
3942

@@ -50,4 +53,6 @@ int sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp,
5053
size_t *newpl);
5154
#endif
5255

53-
__END_DECLS
56+
#if defined(__cplusplus)
57+
} /* extern "C" */
58+
#endif

0 commit comments

Comments
 (0)