Repository navigation
Windows: Support native Windows x64 with MSVC, MASM, and WSAPoll. v1.9.2 - #40
Merged
Merged
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## srs #40 +/- ##
=======================================
Coverage 96.01% 96.01%
=======================================
Files 8 8
Lines 1129 1129
Branches 287 287
=======================================
Hits 1084 1084
Partials 45 45 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…optimized, and win64-debug-utest targets to the Makefile. The WIN64 section builds the static library with MSVC (cl and lib) through GNU make, run from Git Bash or PowerShell with the MSVC environment on PATH. It is separate from CYGWIN64, which is unchanged. - New variables CC_OUT, AR_OUT, DBG_FLAGS, and LINK_OBJ carry what differs on MSVC: cl ignores -o and needs -Fo, lib needs -OUT:, debug builds use -Z7 -Od, and obj is a directory junction (mklink /J) because Git Bash ln -s copies instead of linking. - WIN64 uses -nologo -W4, RANLIB is true, and no event system or assembly is defined yet; the ST sources compile with cl only after the portable headers and stubs of the next tasks. - win64-debug-utest builds the library and then runs the utest Makefile with OS=WIN64, which is ported in a later task. - Ignore the WIN64_*_DBG and WIN64_*_OPT build directories. Verified that make -n prints identical commands before and after this change for every POSIX target (linux, darwin, and cygwin64 debug, optimized, utest, and gcov, and clean), and that win64-debug and win64-optimized build, archive, and link obj with a probe source from both Git Bash and PowerShell, and that clean removes the junction. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…mes for callers. On _WIN32 or _MSC_VER, st.h includes winsock2.h and ws2tcpip.h instead of the POSIX headers, and defines ssize_t, mode_t, struct iovec, and struct msghdr with the POSIX field names, so SRS and the utest compile unchanged. struct pollfd and the POLL* names come from winsock. Detection uses compiler macros, not WIN64, because programs that include st.h do not pass -DWIN64; Cygwin GCC defines neither, so the POSIX and CYGWIN64 paths are unchanged. The POSIX include block is kept verbatim in the #else branch. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…on.h. md.h gets a WIN64 branch next to CYGWIN64, which is unchanged: __thread maps to __declspec(thread), the jmpbuf uses 36 long long slots on WIN64 because MSVC long is 32-bit (LLP64), MD_GET_SP is the 64-bit rsp slot 8 of the Win64 layout, MD_GET_UTIME uses QueryPerformanceCounter, and getpagesize uses GetSystemInfo. common.h and sched.c skip unistd.h, sys/time.h, and fcntl.h on WIN64, and st_thread_create stores the stack pointer through intptr_t instead of long, so it is no longer truncated on Windows. On POSIX the preprocessed sources are identical except for that cast, which keeps the same value. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
winlinvip
force-pushed
the
st-win-reviewed
branch
from
October 3, 2026 18:38
9960624 to
7871288
Compare
…SVC. make win64-debug and win64-optimized now build libst.a, and a program that uses every public function links against it. The Windows internals are stubs that fail at runtime: md_win64.c has _st_md_cxt_save and _st_md_cxt_restore that abort with "context switch not ported" (replaced by assembly later); event.c has a win64-stub default event system whose operations fail with ENOSYS; io.c stubs ioctl, fcntl, close, read, write, readv, writev, recvmsg, sendmsg, _st_io_init, and st_open with ENOSYS and brings ws2_32.lib for the winsock calls. md.h turns on MALLOC_STACK and MD_NO_PROTECT and maps random/srandom to rand/srand on WIN64. POSIX headers are skipped only on WIN64; the preprocessed LINUX, DARWIN, and CYGWIN64 sources and the POSIX make commands are unchanged. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…indows WIN64. make win64-debug-utest now builds gtest and every utest source with cl -W4 and links st_utest.exe against libst.a and ws2_32.lib; it starts and fails its first assertion, as expected while the Windows internals are stubs. utest/Makefile gets a WIN64 section (cl, lib, -Fo, -OUT:, -Fe, .exe, NOMINMAX) and output-flag variables whose POSIX values give the same commands as before. st_utest.hpp gets Windows test helpers: the stream pair is a stub that fails with ENOSYS until a loopback TCP pair replaces it, send, recv, close and would-block use winsock, setsockopt and getsockopt take any pointer, and __thread, __builtin_frame_address, getpagesize and usleep map to MSVC and Win32. POSIX-only includes, and the tests about POSIX features (fork, signals, pipes, pthread, mmap, fcntl, getrlimit, st_open, Unix sockets and CMSG), are skipped on _WIN32: 131 of 186 tests build on Windows. Removing the _WIN32 branches gives back the previous sources byte for byte, so POSIX tests and what they assert are unchanged. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The new windows job runs on windows-latest. A pwsh step finds Visual Studio with vswhere, runs vcvars64.bat, and passes INCLUDE, LIB, LIBPATH, and only the PATH directories vcvars64.bat adds to the next steps, so no third-party action is needed. A Git Bash step installs GNU make with choco only if the runner has none, then builds win64-debug-utest and win64-optimized and checks that st_utest.exe and libst.a exist. It does not run st_utest, which needs the context switch and event system that are not ported yet. The final job now also requires the windows job. The utest and coverage jobs are unchanged. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ct on native Windows. cmake/CMakeLists.txt gets an MSVC branch for the WIN64 platform of the Makefile, which stays the main build: no bash, ST_DIR from get_filename_component, -DWIN64 -DDEBUG -DNOMINMAX, st.h copied to the build directory so the obj junction of make is left alone, md_win64.asm with ASM_MASM when it exists and the md_win64.c stub before, Google Test with the shared CRT, ws2_32, and st_utest as the Visual Studio startup project. The tools are not built on Windows yet. On a Windows host the project does not enable the GNU ASM language, and non-MSVC compilers are rejected. The Linux and macOS paths are unchanged: the diff only adds lines, and the MSVC branch returns before them. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…_win64.asm. md_win64.asm replaces the md_win64.c stub that aborted. _st_md_cxt_save and _st_md_cxt_restore keep the contract of the other platforms, and save the whole Win64 callee-saved set: rbx, rbp, rdi, rsi, r12-r15, rsp, pc, xmm6-xmm15, MXCSR and the x87 control word, plus the TIB stack bounds (StackBase, StackLimit, DeallocationStack), so C++ exceptions and stack walks work on coroutine stacks. The layout matches MD_GET_SP (slot 8) and the 288-byte jmpbuf of md.h. The Makefile assembles it with ml64 -nologo -c through a %.asm rule only for WIN64, so POSIX make commands are unchanged. CMake always uses ASM_MASM now. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
st_thread_create now sets the stack bounds the OS keeps for a new thread through MD_INIT_STACK_BOUNDS, defined only for WIN64 in md.h: slots 10-12 of the jmpbuf, which md_win64.asm restores into the TIB, get the stack top as StackBase and the stack bottom as StackLimit and DeallocationStack. Before, a new thread inherited its creator's bounds, so a C++ exception thrown on a coroutine stack was not caught, and __chkstk could probe the wrong stack for frames over a page. Other platforms do not define the macro, so their sched.c is unchanged after preprocessing. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…native Windows x64. On WIN64, stacks no longer fall back to MALLOC_STACK. stk.c allocates each stack segment with VirtualAlloc and releases it with VirtualFree, and in a DEBUG build protects the lower and upper red zones with VirtualProtect (PAGE_NOACCESS), restoring them before the segment is freed, the same as mmap and mprotect on POSIX. With MALLOC_STACK, md.h still defines MD_NO_PROTECT on WIN64, because VirtualProtect rounds a heap address down to its page and would protect heap memory next to the stack. Linux, macOS, and Cygwin64 preprocess to the same code. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e sleep timeout. The WIN64 event system now initializes and its dispatch sleeps until the earliest sleeper is due (rounded up to milliseconds, INFINITE with no sleepers, like select() with no descriptors), because Windows select() with no sockets fails instead of sleeping. ST_EVENTSYS_DEFAULT and SELECT give the select-like backend and ST_EVENTSYS_ALT is accepted with the same dispatch (D8), so st_get_eventsys reports what was asked for. _st_io_init succeeds on WIN64 with no SIGPIPE or rlimit and reports the 2^24 per-process handle limit from st_getfdlimit. Descriptor polling still fails with ENOSYS until the WSAPoll backend. Linux, macOS, and Cygwin code paths are unchanged. st_init now succeeds on Windows, so the utest runs: 69 of 131 pass; the 62 failures are socket I/O, which is not ported yet. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… not after the context save. st_thread_create saves the context and patches its SP, so a new thread used to resume after _st_md_cxt_save in the frame of st_thread_create on its new stack. It worked under /Od, /O2, and /GL, but only by luck of codegen: at /O2 and with LTCG, MSVC inlines _st_thread_main there and reads the TLS base and _st_this_vp from registers loaded before the save, which survive only because they are callee-saved and so restored from the jmpbuf. On WIN64, MD_INIT_THREAD_ENTRY now points the PC (slot 9) at _st_md_thread_start in md_win64.asm and the SP (slot 8) at a null return address, 8 mod 16 as at a function entry. The entry has unwind info, calls _st_thread_main with the home space, and ends stack walks at address 0. sched.c calls the macro under #ifdef, so Linux, macOS, and Cygwin are unchanged and still use the save-then-patch-SP trick. The utest passes 69 of 131 on Windows with the library built /Od, /O2, and /O2 /GL, the same tests as before; the failures are socket I/O, not ported yet. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ion on coroutine stacks. CoroutineTest.LiveValuesSurviveSwitches keeps seven integers and six doubles live across st_usleep(0) in four coroutines and compares them to a run without switches. The function is optimized by itself (MSVC #pragma optimize, GCC optimize attribute), so the values live in callee-saved registers such as rdi, rsi and xmm6-xmm15 even in the -O0 utest build. CoroutineTest.DeepRecursionOnDefaultStack and DeepRecursionWithLargeFramesOnLargeStack recurse with a buffer per frame, switch at the deepest frame, and check every buffer on the way back. ExceptionTest.ThrowFromDeepRecursionWithLargeFrames throws from the bottom of such a recursion in three coroutines and checks every destructor runs in order. On Windows the new tests fail when the context switch misses rdi/rsi, xmm6-xmm15 or the TIB stack bounds, or when the requested stack size is ignored. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… tests. The windows job now runs obj/st_utest.exe after the win64-debug-utest build, in its own step with a 10-minute timeout, and builds win64-optimized in a separate step afterwards, because the obj junction then points to the optimized build. The coroutine, sync, key, sleep, and exception tests pass on Windows; the socket I/O tests do not until the Windows event system and I/O are ported, so a gtest negative filter skips the Io*, Poll, Tcp, and epoll suites and the seven other tests that open sockets. The filter is to be removed when socket I/O is ported. A failing selected test fails the job. The utest, coverage, and final jobs are unchanged. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Winsock reports errors by WSAGetLastError(), but ST's I/O loops and callers such as SRS check errno. _st_win64_errno() maps a Winsock error to errno in one place: WSAEWOULDBLOCK is EAGAIN, or EINPROGRESS for connect, WSAETIMEDOUT is ETIMEDOUT, WSAEINTR is EINTR, and so on; an error with no equivalent is EIO. The Winsock calls io.c makes (accept, connect, getsockopt, recvfrom, sendto) go through wrappers that set errno on failure, and accept returns the SOCKET as an int. Only the WIN64 code changes. Adds WinErrnoTest utests for the mapping table, connect, unknown errors, and errors from real non-blocking sockets. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ive Windows. Winsock needs WSAStartup before any socket call, and ST's callers such as SRS do not call it. On WIN64, _st_io_init starts Winsock 2.2 once per OS thread's ST, and st_destroy cleans up that start through _st_io_destroy, so st_init and st_destroy are balanced. A failed start sets errno. Only the WIN64 code changes. Adds WinsockTest utests: st_init starts Winsock; real SOCKET values of TCP, UDP, and IPv6 sockets round-trip through int and still work as the socket; and, in a child process, another OS thread's st_init/st_destroy leaves Winsock running while the last st_destroy stops it. With sockets now created, the tests' CRT close() on a socket hits the CRT invalid parameter handler and kills the suite, so the socket closes that build on Windows go through st_utest_close, which is close() on POSIX. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On WIN64, the POSIX calls of io.c, which were ENOSYS stubs, now use Winsock, for sockets only: ioctl(FIONBIO) is ioctlsocket; fcntl supports F_GETFL (checks for a socket) and F_SETFL with O_NONBLOCK; close is closesocket; read and write are recv and send; readv and writev are WSARecv and WSASend, with each iovec copied to a WSABUF (the field order differs); recvmsg is WSARecvMsg, loaded once with WSAIoctl(SIO_GET_EXTENSION_FUNCTION_POINTER), and sendmsg is WSASendMsg. Both fall back to WSARecv and WSASend on a TCP stream, which POSIX allows and the msg functions do not take. A truncated datagram returns the bytes that fit, with MSG_TRUNC for recvmsg, as on POSIX, where Winsock fails with WSAEMSGSIZE; recvfrom does the same. Control data is Winsock's layout. st_open, SIGPIPE, and rlimits stay unsupported. The calls are external and declared in common.h so the utest can call them. Only the WIN64 code changes. Adds WinIoTest utests with real loopback sockets for each call: non-blocking mode by ioctl and fcntl, stream read and write with end of stream, not connected errors, scatter and gather with more vectors than the stack holds, datagram sendmsg and recvmsg with the sender address, MSG_PEEK, truncated datagrams, an oversized datagram, sendmsg and recvmsg on a stream, and close. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e Windows. Windows has no socketpair, so st_utest_stream_pair, which the utest uses for two connected sockets ST can wait on, was a stub failing with ENOSYS. It is now a loopback TCP connection of two blocking sockets: a listener on 127.0.0.1 port 0, a connect, and an accept that keeps only the client's own connection (by peer address), with TCP_NODELAY on both ends so small writes are not delayed as on a Unix-domain socketpair. Errors map to errno through _st_win64_errno. The POSIX helper is unchanged. New UtestPairTest tests: data both ways (small and 64 KB) and end of stream on close, 64 pairs open at once each connected to its own end, and on Windows that both ends are loopback TCP peers of each other with Nagle off and blocking. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Windows event system now polls sockets with WSAPoll, for both ST_EVENTSYS_DEFAULT and ST_EVENTSYS_ALT, named "wsapoll". Each dispatch builds the WSAPOLLFD array from the pollsets on the I/O queue, so there are no per-descriptor counts: closing a descriptor fails with EBUSY while a pollset holds it. With nothing to poll it sleeps until the next timer. An error or hang-up wakes every waiter of the descriptor, as epoll does. st_poll refuses a negative descriptor (the Winsock SOCKET is unsigned), POLLPRI (WSAPoll has none, so EINVAL as on kqueue), and a part of Winsock's POLLIN such as POLLRDNORM. Opening anything but an open socket fails with EBADF. io.c: getsockopt(SO_ERROR), which st_connect reads, gives the POSIX errno instead of the Winsock code, and a receive on a datagram socket that got an ICMP port unreachable fails with ECONNREFUSED instead of ECONNRESET. New WsaPollTest tests: the backend name, and a refused connect reported by WSAPoll with ECONNREFUSED before the timeout. The Windows CI job now skips only the 9 tests that Windows TCP still fails: 8 IoWriteTest tests (Winsock takes a whole non-blocking send larger than SO_SNDBUF) and IoConnectTest.ConnectRefusedWhenNobodyListens (SYN retries take about 2 seconds, longer than its 100 ms timeout). --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Winsock takes a whole non-blocking send, however large, while the send buffer holds less than SO_SNDBUF, so a single large write to a slow player never waits. On Windows, three IoWriteTest tests now fill the send and receive buffers first, so the write under test waits and sees the reset or the stop as on POSIX: WriteFailsWhenPlayerResetsMidStream, WritevFailsWhenPlayerResetsMidStream, and WritevInterruptedWhenConnectionStops. ST reads its clock again after the fill, which sleeps outside ST. Winsock never sends part of a non-blocking send: it takes the whole buffer or fails with WSAEWOULDBLOCK and sends nothing. So the five tests that need a partial count skip on Windows: WriteWaitsForSlowPlayer, WritevWaitsForSlowPlayer, WritevWaitsForSlowPlayerWithMergedWrite, WritevResidResumesAfterTimeout, and WritevTimesOutAndLosesTheSentCount. IoConnectTest.ConnectRefusedWhenNobodyListens also skips on Windows, which retries a refused connect for about 2 seconds, longer than its timeout. io.c is unchanged. The Windows CI job now runs the whole st_utest without a filter. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
TcpTest.EchoManyConcurrentConnections starts an echo server on loopback and 1000 client coroutines. Every client connects and waits in a read for a go byte, which the server sends only when all clients are connected and every accepted connection has an echo coroutine waiting in a read, so all 2000 sockets are polled at the same time. Each client then sends three messages of its own, each in two writes, and checks every echo; the test checks the counts and the total bytes echoed. It is for correctness, not speed, and is portable. On POSIX it raises the soft descriptor limit toward the hard limit, and runs fewer clients only if the hard limit is too low. On Windows it passes with the WSAPoll backend; a backend that ignores descriptors past 1024 fails it. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The MSVC asan runtime (clang_rt.asan_dynamic, MSVC 14.44) exports __sanitizer_start_switch_fiber and __sanitizer_finish_switch_fiber, so MD_ASAN works with no library change: the whole utest passes on Windows built with -DMD_ASAN -fsanitize=address, with the library at -Od and -O2. Without MD_ASAN, ASan ignores __asan_handle_no_return on coroutine stacks and the ExceptionTest suite fails with a false stack-buffer-underflow. The Makefile documents the Windows asan command. Use-after-return (-fsanitize-address-use-after-return) is not usable: MSVC 14.44 reports false positives with it even in a small program without ST. PrimordialStackTest.DescribesTheMainThreadStack now runs on Windows too, reading the main thread's stack bounds with GetCurrentThreadStackLimits. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each tool Makefile detects native Windows by uname -s (MINGW64_NT-* in Git Bash, MSYS_NT-* from PowerShell) and builds with cl -W4, -Fe for the executable, a .exe suffix, and win64-debug for the library. The POSIX commands are unchanged (make -n on Linux and Darwin gives the same output). porting prints _WIN64, _M_X64, _M_ARM64, and _MSC_VER, and includes execinfo.h only off Windows. The CMake MSVC build adds the three tools too. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
README.md: build native Windows x64 with GNU make in the MSVC environment (x64 Native Tools Command Prompt, then Git Bash), with the win64-debug and win64-optimized targets, and with MSVC ASAN and MD_ASAN; run the utest with win64-debug-utest, and generate a Visual Studio solution with CMake. The old "Windows native build is unsupported" remark is gone, and the Cygwin build is replaced by a remark that Cygwin64 is deprecated, use native Windows. docs/notes.html: native Windows porting notes: the WIN64 platform, the MASM context switch with the TIB stack bounds, VirtualAlloc stacks, QueryPerformanceCounter, the WSAPoll event system, Winsock I/O with int descriptors and errno mapping, and what is unsupported or differs (st_open, SIGPIPE, rlimit, all-or-nothing sends, refused connect delay, no /CETCOMPAT, ASAN use-after-return). Bump the version to 1.9.2 in Makefile, public.h, and st.spec, with a CHANGELOG.md entry for the Windows port. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
auto/tools.sh builds win64-debug and runs <name>.exe under Git Bash on Windows (uname -s MINGW* or MSYS*), and takes the tools to run as arguments, every tool by default. Every tool Makefile gets the MSVC block of helloworld and verify, tool.h builds with cl (Winsock from st.h, closesocket, wsapoll names), porting accepts Windows x64, and verify.c drops a C4312 cast. The MSVC tool outputs are ignored, and .sh files keep LF so WSL runs a Windows checkout. On Windows, helloworld, porting, verify, sync, and thread pass; the others do not build yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
time: Windows has no fork, so the custom clock child is the tool run again with the argument custom-clock (_spawnl, waited for its exit code), and the real clock is QueryPerformanceCounter instead of clock_gettime. key: the key array is on the heap, because MSVC has no variable length arrays. lifecycle: the primordial stack comes from GetCurrentThreadStackLimits, and as Windows has no RLIMIT_NOFILE, the limit check is that st_getfdlimit reports the per-process handle limit 2^24, as documented. POSIX code is unchanged except the heap key array. On Windows, time, key, lifecycle, thread, and sync pass with select and alt. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The POSIX headers are only included off Windows, the raw socket is cast to int, and is_open asks getsockopt(SO_TYPE) on Windows, where a closed socket fails with WSAENOTSOCK, reported as EBADF like fcntl(F_GETFD) on POSIX. Winsock never sends part of a non-blocking send: it takes the whole buffer or fails with WSAEWOULDBLOCK. So on Windows, resid() skips only its three partial-write-on-timeout checks (st_write_resid, st_writev_resid, then st_write failing with ETIME), as the utest skips its partial-send tests. Every other check runs, including the residual counts at EOF. On Windows, tcp passes with select and alt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Windows has no rlimit, so it does not support the check that ST raises RLIMIT_NOFILE in st_init. Skip check_fdlimit on Windows with a comment, instead of the Windows-only st_getfdlimit() == 1<<24 check from the previous commit. Every other lifecycle check stays. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Include sys/uio.h only off _WIN32, since st.h brings Winsock 2 and the iovec and msghdr types on Windows. Cast the SOCKET from socket() to int, and close a raw socket with tool_close_socket, which is closesocket on Windows. Every udp check runs on Windows, over IPv4 and IPv6, with both event systems; no check changed and no ST library change. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ST on native Windows takes sockets only, so pipes and socketpair in the tools become connected socket pairs there (D26). tools/tool.h adds tool_pipe (pipe, or a loopback TCP pair on Windows), tool_socketpair (socketpair, or an AF_UNIX stream pair through a path in the temp folder on Windows), and tool_write (write, or send with EAGAIN on Windows). On POSIX each is the real call. poll.c uses them, includes fcntl.h and poll.h only off _WIN32, and skips only the O_NONBLOCK read-back with fcntl(F_GETFL) on Windows, which cannot read back a socket's mode. Every other check runs unchanged, with both event systems; no ST library change. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
stress.c includes netinet/tcp.h, sys/resource.h, and sys/uio.h only off _WIN32; on Windows st.h brings TCP_NODELAY and struct iovec from Winsock 2. Windows has no rlimit, so the getrlimit and setrlimit setup that raises the descriptor limit before st_init is under #ifndef _WIN32 with a comment (D25); the check that st_getfdlimit() covers the count still runs everywhere. Every other check is unchanged and passes with both event systems, also with a count of 1000; no ST library change. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Native Windows has no execinfo.h, so the backtrace tool gets the frames with CaptureStackBackTrace, which walks a coroutine stack with the unwind data and the TIB stack bounds ST sets, and names them with DbgHelp SymFromAddr in the glibc form "address (name+0xoffset)". __builtin_return_address maps to _ReturnAddress for level 0, all the builtin path requires. The checks that bar, foo and start are on the coroutine stack are unchanged; no ST library change. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ST on native Windows takes sockets only, with no pipes, FIFOs, files (st_open), or signals, so pipe.c is skipped there as a whole (D27): on _WIN32 it builds a main that prints "SKIP pipe: <why>" and exits 0, with a comment; the POSIX tool is unchanged under #else. Its socket fill-then-drain is covered by the poll and unix tools. auto/tools.sh shows a tool that prints only "SKIP <name>: <why>" as that line with its event system, not as OK. No tool prints it on Linux or macOS, so their output is unchanged. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Windows AF_UNIX is stream only (D28). unix.c includes sys/uio.h and sys/un.h only off _WIN32; on Windows the stream paths are in the temp folder, and unlink and access are the MSVC CRT calls. stream_echo and pair_stream run unchanged; pair_dgram runs over a connected loopback UDP pair, which tool_socketpair in tools/tool.h now makes for SOCK_DGRAM on Windows, a channel swap like D26, with every check unchanged. The dgram_echo test (AF_UNIX datagram paths) and the connect-to-missing-path ENOENT check (Windows gives ECONNREFUSED) are skipped on Windows with a comment (D25). socket() is cast to int and closed with tool_close_socket, which is close() off Windows. No ST library change. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… them for Windows. The windows job in .github/workflows/test.yml runs ./auto/tools.sh after the utest, in the ST default build and with EXTRA_CFLAGS=-DMALLOC_STACK (the SRS build), as the Linux and macOS jobs do. Each step uses Git Bash in the MSVC environment and fails on any tool failure; the utest, coverage, and final jobs are unchanged. README.md gets a Windows: Tools section: how to run auto/tools.sh, the pipe and socketpair channels as sockets, the pipe tool SKIP lines, and the checks Windows does not support. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…utine stacks. The 15 integration tools are C, so none threw, and only the utest ExceptionTest covered the TIB stack bounds that the Windows context switch must restore for SEH (D30). tools/exception/exception.cpp throws and catches on coroutine stacks: a throw in a coroutine, unwinding many frames in order after a switch, coroutines that switch before they throw on the default and a 32 KB stack, frames larger than a page down most of a 1 MB stack, a destructor that switches while unwound, an exception_ptr rethrown by another coroutine, and a throw in main while coroutines wait deep in their frames. On Windows it also raises and catches SEH itself: RaiseException with __finally and __except, and an access violation. auto/tools.sh relinks a C++ tool through <name>.cpp. README.md describes the tool in Windows: Tools. No ST library change. Without the TIB restore in _st_md_cxt_restore, the tool dies with 0xE06D7363, and its SEH checks alone with 0xE0535431. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ieces. StreamPairCarriesBothWays sent 64 KB on a blocking end before reading the other end, in one thread. A macOS socketpair holds only 8 KB each way (net.local.stream.sendspace and recvspace), so send blocked forever and the darwin-arm64 CI job hung; Linux socketpair buffers and the Windows loopback TCP pair are large enough to hide it. The test now sends the 64 KB in 4 KB pieces, each read at the other end before the next, in both directions, so it still carries more than a buffer each way. Verified on macOS and Linux, each with the utest and auto/tools.sh in the default, MALLOC_STACK, and ASAN builds. No ST library change. --------- Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR ports State Threads to native Windows x64. It builds with the Visual Studio toolchain (
cl,ml64, andlib) through GNU make and the same Makefile, and uses no Cygwin, MinGW, WSL, or POSIX emulation layer. It needs Windows 10 1809 or Windows Server 2019 or later.Linux, macOS, and Cygwin64 are unchanged: their code paths and their preprocessed sources are the same as before, and
make -nprints the same commands for every POSIX target. Cygwin64 is now marked deprecated in the README.Build
WIN64platform with thewin64-debug,win64-optimized, andwin64-debug-utesttargets. They build the static libraryobj/libst.awith MSVC.public.his portable to MSVC and keeps the POSIX names for callers.md.handcommon.hget aWIN64branch.cmake/CMakeLists.txtgenerates a Visual Studio solution for debugging the utest and thehelloworld,porting, andverifytools. The Makefile stays the main build.make win64-debug EXTRA_CFLAGS="-DMD_ASAN -fsanitize=address".Coroutines
md_win64.asmimplements the context switch in MASM for the Windows x64 ABI. It saves the nonvolatile registers, includingxmm6toxmm15.VirtualAlloc, with red zones.I/O and events
st_initstarts Winsock, andst_destroycleans it up. The library linksws2_32.libby itself.errno.ST_EVENTSYS_SELECTandST_EVENTSYS_ALTboth select it.st_open, pipes, FIFOs, signals, and rlimits stay unsupported. The porting notes list what works differently.