2
0
Fork 0
mirror of https://github.com/ii64/sonic.git synced 2026-06-20 16:45:22 +08:00

feat: support for Windows (#228)

* feat: support for Windows

* fix (loader): default loader now has build tag: for linux and darwin
* feat (loader): add memory allocator support for Windows

* feat: add Windows CI

Added Windows CI for GitHub Actions
Go version: 1.15.x, 1.16.x, 1.17.x, 1.18.x

* fix (loader): remove `amd64` build constraint from Windows

* fix: TSAN error on Windows CI

Temporary remove `-race` flag

Link: https://github.com/golang/go/issues/46099

Co-authored-by: Yi Duan <duanyi.aster@bytedance.com>
This commit is contained in:
Ii64人 2022-05-23 11:55:45 +07:00 committed by GitHub
parent 308b76b44f
commit 75b728ba51
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 149 additions and 8 deletions

View file

@ -0,0 +1,26 @@
name: Push Check Go Windows
on: push
jobs:
build:
strategy:
matrix:
go-version: [1.15.x, 1.16.x, 1.17.x, 1.18.x]
os: [windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: ${{ matrix.go-version }}
- name: Unit Test
run: go test -v -gcflags -d=checkptr=0 -covermode atomic -coverprofile coverage.out ./...
env:
GOMAXPROCS: 4
- name: Generic Test
run: go test -v -gcflags -d=checkptr=0 -covermode atomic ./generic_test

View file

@ -1,3 +1,6 @@
//go:build linux || darwin
// +build linux darwin
/*
* Copyright 2021 ByteDance Inc.
*

View file

@ -0,0 +1,112 @@
/*
* Copyright 2021 ByteDance Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package loader
import (
`fmt`
`os`
`reflect`
`syscall`
`unsafe`
)
const (
MEM_COMMIT = 0x00001000
MEM_RESERVE = 0x00002000
)
var (
libKernel32 = syscall.NewLazyDLL("KERNEL32.DLL")
libKernel32_VirtualAlloc = libKernel32.NewProc("VirtualAlloc")
libKernel32_VirtualProtect = libKernel32.NewProc("VirtualProtect")
)
type Loader []byte
type Function unsafe.Pointer
func (self Loader) LoadWithFaker(fn string, fp int, args int, faker interface{}) (f Function) {
p := os.Getpagesize()
n := (((len(self) - 1) / p) + 1) * p
/* register the function */
m := mmap(n)
v := fmt.Sprintf("runtime.__%s_%x", fn, m)
argsptr, localsptr := stackMap(faker)
registerFunction(v, m, uintptr(n), fp, args, uintptr(len(self)), argsptr, localsptr)
/* reference as a slice */
s := *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader {
Data : m,
Cap : n,
Len : len(self),
}))
/* copy the machine code, and make it executable */
copy(s, self)
mprotect(m, n)
return Function(&m)
}
func (self Loader) Load(fn string, fp int, args int) (f Function) {
return self.LoadWithFaker(fn, fp, args, func(){})
}
func mmap(nb int) uintptr {
addr, err := winapi_VirtualAlloc(0, nb, MEM_COMMIT|MEM_RESERVE, syscall.PAGE_READWRITE)
if err != nil {
panic(err)
}
return addr
}
func mprotect(p uintptr, nb int) (oldProtect int) {
err := winapi_VirtualProtect(p, nb, syscall.PAGE_EXECUTE_READ, &oldProtect)
if err != nil {
panic(err)
}
return
}
// winapi_VirtualAlloc allocate memory
// Doc: https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc
func winapi_VirtualAlloc(lpAddr uintptr, dwSize int, flAllocationType int, flProtect int) (uintptr, error) {
r1, _, err := libKernel32_VirtualAlloc.Call(
lpAddr,
uintptr(dwSize),
uintptr(flAllocationType),
uintptr(flProtect),
)
if r1 == 0 {
return 0, err
}
return r1, nil
}
// winapi_VirtualProtect change memory protection
// Doc: https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualprotect
func winapi_VirtualProtect(lpAddr uintptr, dwSize int, flNewProtect int, lpflOldProtect *int) error {
r1, _, err := libKernel32_VirtualProtect.Call(
lpAddr,
uintptr(dwSize),
uintptr(flNewProtect),
uintptr(unsafe.Pointer(lpflOldProtect)),
)
if r1 == 0 {
return err
}
return nil
}

View file

@ -1,4 +1,5 @@
// +build !race
//go:build (linux && !race) || (unix && !race)
// +build linux,!race unix,!race
/*
* Copyright 2021 ByteDance Inc.
@ -23,9 +24,9 @@ import (
`fmt`
`os/exec`
`plugin`
`reflect`
`runtime`
`testing`
`reflect`
_ `github.com/bytedance/sonic`
)
@ -37,8 +38,8 @@ func buildPlugin() {
panic(err)
}
cmd0 := exec.Cmd{
Path: bin0,
Args: []string{"rm", "-f", "plugin/plugin."+runtime.Version()+".so"},
Path: bin0,
Args: []string{"rm", "-f", "plugin/plugin." + runtime.Version() + ".so"},
Stdout: out,
Stderr: out,
}
@ -51,8 +52,8 @@ func buildPlugin() {
panic(err)
}
cmd := exec.Cmd{
Path: bin,
Args: []string{"go", "build", "-buildmode", "plugin", "-o", "plugin/plugin."+runtime.Version()+".so", "plugin/main.go"},
Path: bin,
Args: []string{"go", "build", "-buildmode", "plugin", "-o", "plugin/plugin." + runtime.Version() + ".so", "plugin/main.go"},
Stdout: out,
Stderr: out,
}
@ -61,10 +62,9 @@ func buildPlugin() {
}
}
func TestPlugin(t *testing.T) {
buildPlugin()
p, err := plugin.Open("plugin/plugin."+runtime.Version()+".so")
p, err := plugin.Open("plugin/plugin." + runtime.Version() + ".so")
if err != nil {
t.Fatal(err)
}