Skip to content

Commit

Permalink
all: support Windows with Go 1.23
Browse files Browse the repository at this point in the history
  • Loading branch information
hajimehoshi committed Aug 14, 2024
1 parent 8de20e4 commit af4a98a
Show file tree
Hide file tree
Showing 7 changed files with 203 additions and 4 deletions.
6 changes: 2 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ jobs:
GOARCH=arm64 go run test.go -qemu -args="-test.run=^Test -test.v internal/runtime/atomic"
- name: Test (amd64)
if: runner.os == 'Linux' || (runner.os == 'Windows' && !startsWith(matrix.go, '1.23.'))
run: |
go run test.go -args="-test.run=^Test -test.v fmt"
go run test.go -args="-test.run=^Test -test.v internal/abi"
Expand Down Expand Up @@ -97,13 +96,12 @@ jobs:
go run test.go -args="-test.run=^Test -test.v runtime/internal/atomic"
- name: Test (amd64, Go >=1.23)
if: (runner.os == 'Linux' || (runner.os == 'Windows' && !startsWith(matrix.go, '1.23.'))) && startsWith(matrix.go, '1.23.')
if: startsWith(matrix.go, '1.23.')
run: |
go run test.go -args="-test.run=^Test -test.v internal/runtime/atomic"
- name: Test (amd64, runtime)
# Skip runtime tests with Go 1.19 and Windows, as there is an issue (probably golang/go#51007 and golang/go#57455).
# For Go 1.23, Windows is not supported yet.
if: runner.os != 'Windows' || (!startsWith(matrix.go, '1.19.') && !startsWith(matrix.go, '1.23.'))
if: runner.os != 'Windows' || !startsWith(matrix.go, '1.19.')
run: |
go run test.go -args="-test.run=^Test -test.v -test.short runtime"
5 changes: 5 additions & 0 deletions 1.23_windows/internal/testenv/exec.go.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
//--from
func tryExec() error {
//--to
func tryExec() error {
return fmt.Errorf("can't probe for exec support")
5 changes: 5 additions & 0 deletions 1.23_windows/internal/testenv/testenv.go.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
//--from
func HasGoBuild() bool {
//--to
func HasGoBuild() bool {
return false
19 changes: 19 additions & 0 deletions 1.23_windows/runtime/cgo/gcc_windows_amd64.c.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//--from
static void
threadentry(void *v)
{
//--to
static int getproccount() {
static int proccount = 0;
if (!proccount) {
SYSTEM_INFO info;
GetSystemInfo(&info);
proccount = info.dwNumberOfProcessors;
}
return proccount;
}

static void
threadentry(void *v)
{
SetThreadAffinityMask(GetCurrentThread(), (1<<getproccount())-1);
160 changes: 160 additions & 0 deletions 1.23_windows/runtime/os_windows.go.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
//--from
//go:cgo_import_dynamic runtime._GetConsoleMode GetConsoleMode%2 "kernel32.dll"
//--to
//--from
//go:cgo_import_dynamic runtime._SetConsoleCtrlHandler SetConsoleCtrlHandler%2 "kernel32.dll"
//--to
//--from
//go:cgo_import_dynamic runtime._WriteConsoleW WriteConsoleW%5 "kernel32.dll"
//--to
//go:cgo_import_dynamic runtime._OutputDebugStringW OutputDebugStringW%1 "kernel32.dll"
//--from
_GetConsoleMode,
//--to
//--from
_SetConsoleCtrlHandler,
//--to
//--from
_WriteConsoleW,
//--to
_OutputDebugStringW,
//--from
_timeBeginPeriod,
_timeEndPeriod,
//--to
//--from
m32 := windowsLoadSystemLib(winmmdll[:])
if m32 == 0 {
throw("winmm.dll not found")
}
_timeBeginPeriod = windowsFindfunc(m32, []byte("timeBeginPeriod\000"))
_timeEndPeriod = windowsFindfunc(m32, []byte("timeEndPeriod\000"))
if _timeBeginPeriod == nil || _timeEndPeriod == nil {
throw("timeBegin/EndPeriod not found")
}
//--to
//--from
// We call these all the way here, late in init, so that malloc works
// for the callback functions these generate.
var fn any = ctrlHandler
ctrlHandlerPC := compileCallback(*efaceOf(&fn), true)
stdcall2(_SetConsoleCtrlHandler, ctrlHandlerPC, 1)
//--to
//--from
func osRelax(relax bool) uint32 {
if haveHighResTimer {
// If the high resolution timer is available, the runtime uses the timer
// to sleep for short durations. This means there's no need to adjust
// the global clock frequency.
return 0
}

if relax {
return uint32(stdcall1(_timeEndPeriod, 1))
} else {
return uint32(stdcall1(_timeBeginPeriod, 1))
}
}
//--to
func osRelax(relax bool) uint32 {
if haveHighResTimer {
// If the high resolution timer is available, the runtime uses the timer
// to sleep for short durations. This means there's no need to adjust
// the global clock frequency.
return 0
}

throw("not reached")
return 0
}
//--from
func write1(fd uintptr, buf unsafe.Pointer, n int32) int32 {
const (
_STD_OUTPUT_HANDLE = ^uintptr(10) // -11
_STD_ERROR_HANDLE = ^uintptr(11) // -12
)
var handle uintptr
switch fd {
case 1:
handle = stdcall1(_GetStdHandle, _STD_OUTPUT_HANDLE)
case 2:
handle = stdcall1(_GetStdHandle, _STD_ERROR_HANDLE)
default:
// assume fd is real windows handle.
handle = fd
}
isASCII := true
b := (*[1 << 30]byte)(buf)[:n]
for _, x := range b {
if x >= 0x80 {
isASCII = false
break
}
}

if !isASCII {
var m uint32
isConsole := stdcall2(_GetConsoleMode, handle, uintptr(unsafe.Pointer(&m))) != 0
// If this is a console output, various non-unicode code pages can be in use.
// Use the dedicated WriteConsole call to ensure unicode is printed correctly.
if isConsole {
return int32(writeConsole(handle, buf, n))
}
}
var written uint32
stdcall5(_WriteFile, handle, uintptr(buf), uintptr(n), uintptr(unsafe.Pointer(&written)), 0)
return int32(written)
}
//--to
func write1(fd uintptr, buf unsafe.Pointer, n int32) int32 {
const (
_STD_OUTPUT_HANDLE = ^uintptr(10) // -11
_STD_ERROR_HANDLE = ^uintptr(11) // -12
)
var handle uintptr
switch fd {
case 1:
handle = stdcall1(_GetStdHandle, _STD_OUTPUT_HANDLE)
case 2:
handle = stdcall1(_GetStdHandle, _STD_ERROR_HANDLE)
default:
// assume fd is real windows handle.
handle = fd
}
if fd == 1 || fd == 2 {
// Note that handle is not used anyway.
return int32(writeConsole(handle, buf, n))
}
var written uint32
stdcall5(_WriteFile, handle, uintptr(buf), uintptr(n), uintptr(unsafe.Pointer(&written)), 0)
return int32(written)
}
//--from
func writeConsoleUTF16(handle uintptr, b []uint16) {
l := uint32(len(b))
if l == 0 {
return
}
var written uint32
stdcall5(_WriteConsoleW,
handle,
uintptr(unsafe.Pointer(&b[0])),
uintptr(l),
uintptr(unsafe.Pointer(&written)),
0,
)
return
}
//--to
func writeConsoleUTF16(handle uintptr, b []uint16) {
b = b[:len(b)+1]
b[len(b)-1] = 0
l := uint32(len(b))
if l <= 1 {
return
}
stdcall1(_OutputDebugStringW,
uintptr(unsafe.Pointer(&b[0])),
)
return
}
7 changes: 7 additions & 0 deletions 1.23_windows/runtime/syscall_windows.go.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//--from
func syscall_SyscallN(trap uintptr, args ...uintptr) (r1, r2, err uintptr) {
//--to
func syscall_SyscallN(trap uintptr, args ...uintptr) (r1, r2, err uintptr) {
if trap == 0 {
panic("trap must not be 0 at SyscallN")
}
5 changes: 5 additions & 0 deletions 1.23_windows/runtime/syscall_windows_test.go.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
//--from
func TestNumCPU(t *testing.T) {
//--to
func TestNumCPU(t *testing.T) {
t.Skip("creating a new process with os.Args[0] doesn't work in this environment")

0 comments on commit af4a98a

Please sign in to comment.