fix(deps): update module github.com/shirou/gopsutil/v4 to v4.25.9

Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
This commit is contained in:
renovate[bot]
2025-10-01 03:30:56 +00:00
committed by GitHub
parent 3747e3db3f
commit 3b509022cd
63 changed files with 11415 additions and 6170 deletions

4
go.mod
View File

@@ -57,7 +57,7 @@ require (
github.com/opencontainers/selinux v1.12.0 github.com/opencontainers/selinux v1.12.0
github.com/openshift/imagebuilder v1.2.16-0.20250828154754-e22ebd3ff511 github.com/openshift/imagebuilder v1.2.16-0.20250828154754-e22ebd3ff511
github.com/rootless-containers/rootlesskit/v2 v2.3.5 github.com/rootless-containers/rootlesskit/v2 v2.3.5
github.com/shirou/gopsutil/v4 v4.25.8 github.com/shirou/gopsutil/v4 v4.25.9
github.com/sirupsen/logrus v1.9.3 github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.10.1 github.com/spf13/cobra v1.10.1
github.com/spf13/pflag v1.0.10 github.com/spf13/pflag v1.0.10
@@ -107,7 +107,7 @@ require (
github.com/disiqueira/gotree/v3 v3.0.2 // indirect github.com/disiqueira/gotree/v3 v3.0.2 // indirect
github.com/distribution/reference v0.6.0 // indirect github.com/distribution/reference v0.6.0 // indirect
github.com/docker/docker-credential-helpers v0.9.3 // indirect github.com/docker/docker-credential-helpers v0.9.3 // indirect
github.com/ebitengine/purego v0.8.4 // indirect github.com/ebitengine/purego v0.9.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/fsouza/go-dockerclient v1.12.1 // indirect github.com/fsouza/go-dockerclient v1.12.1 // indirect

8
go.sum
View File

@@ -120,8 +120,8 @@ github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw= github.com/ebitengine/purego v0.9.0 h1:mh0zpKBIXDceC63hpvPuGLiJ8ZAa3DfrFTudmfi8A4k=
github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/ebitengine/purego v0.9.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
@@ -347,8 +347,8 @@ github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c
github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE= github.com/segmentio/ksuid v1.0.4/go.mod h1:/XUiZBD3kVx5SmUOl55voK5yeAbBNNIed+2O73XgrPE=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
github.com/shirou/gopsutil/v4 v4.25.8 h1:NnAsw9lN7587WHxjJA9ryDnqhJpFH6A+wagYWTOH970= github.com/shirou/gopsutil/v4 v4.25.9 h1:JImNpf6gCVhKgZhtaAHJ0serfFGtlfIlSC08eaKdTrU=
github.com/shirou/gopsutil/v4 v4.25.8/go.mod h1:q9QdMmfAOVIw7a+eF86P7ISEU6ka+NLgkUxlopV4RwI= github.com/shirou/gopsutil/v4 v4.25.9/go.mod h1:gxIxoC+7nQRwUl/xNhutXlD8lq+jxTgpIkEf3rADHL8=
github.com/sigstore/fulcio v1.7.1 h1:RcoW20Nz49IGeZyu3y9QYhyyV3ZKQ85T+FXPKkvE+aQ= github.com/sigstore/fulcio v1.7.1 h1:RcoW20Nz49IGeZyu3y9QYhyyV3ZKQ85T+FXPKkvE+aQ=
github.com/sigstore/fulcio v1.7.1/go.mod h1:7lYY+hsd8Dt+IvKQRC+KEhWpCZ/GlmNvwIa5JhypMS8= github.com/sigstore/fulcio v1.7.1/go.mod h1:7lYY+hsd8Dt+IvKQRC+KEhWpCZ/GlmNvwIa5JhypMS8=
github.com/sigstore/protobuf-specs v0.4.1 h1:5SsMqZbdkcO/DNHudaxuCUEjj6x29tS2Xby1BxGU7Zc= github.com/sigstore/protobuf-specs v0.4.1 h1:5SsMqZbdkcO/DNHudaxuCUEjj6x29tS2Xby1BxGU7Zc=

View File

@@ -26,17 +26,31 @@ except for float arguments and return values.
## Supported Platforms ## Supported Platforms
- **FreeBSD**: amd64, arm64 ### Tier 1
- **Linux**: amd64, arm64
- **macOS / iOS**: amd64, arm64
- **Windows**: 386*, amd64, arm*, arm64
`*` These architectures only support SyscallN and NewCallback Tier 1 platforms are the primary targets officially supported by PureGo. When a new version of PureGo is released, any critical bugs found on Tier 1 platforms are treated as release blockers. The release will be postponed until such issues are resolved.
- **Android**: amd64, arm64
- **iOS**: amd64, arm64
- **Linux**: amd64, arm64
- **macOS**: amd64, arm64
- **Windows**: amd64, arm64
### Tier 2
Tier 2 platforms are supported by PureGo on a best-effort basis. Critical bugs on Tier 2 platforms do not block new PureGo releases. However, fixes contributed by external contributors are very welcome and encouraged.
- **Android**: 386, arm
- **FreeBSD**: amd64, arm64
- **Linux**: 386, arm, loong64
- **Windows**: 386*, arm*
`*` These architectures only support `SyscallN` and `NewCallback`
## Example ## Example
The example below only showcases purego use for macOS and Linux. The other platforms require special handling which can The example below only showcases purego use for macOS and Linux. The other platforms require special handling which can
be seen in the complete example at [examples/libc](https://github.com/ebitengine/purego/tree/main/examples/libc) which supports Windows and FreeBSD. be seen in the complete example at [examples/libc](https://github.com/ebitengine/purego/tree/main/examples/libc) which supports FreeBSD and Windows.
```go ```go
package main package main
@@ -84,6 +98,7 @@ License that can be found [in the Go Source](https://github.com/golang/go/blob/m
This is a list of the copied files: This is a list of the copied files:
* `abi_*.h` from package `runtime/cgo` * `abi_*.h` from package `runtime/cgo`
* `wincallback.go` from package `runtime`
* `zcallback_darwin_*.s` from package `runtime` * `zcallback_darwin_*.s` from package `runtime`
* `internal/fakecgo/abi_*.h` from package `runtime/cgo` * `internal/fakecgo/abi_*.h` from package `runtime/cgo`
* `internal/fakecgo/asm_GOARCH.s` from package `runtime/cgo` * `internal/fakecgo/asm_GOARCH.s` from package `runtime/cgo`
@@ -92,6 +107,7 @@ This is a list of the copied files:
* `internal/fakecgo/iscgo.go` from package `runtime/cgo` * `internal/fakecgo/iscgo.go` from package `runtime/cgo`
* `internal/fakecgo/setenv.go` from package `runtime/cgo` * `internal/fakecgo/setenv.go` from package `runtime/cgo`
* `internal/fakecgo/freebsd.go` from package `runtime/cgo` * `internal/fakecgo/freebsd.go` from package `runtime/cgo`
* `internal/fakecgo/netbsd.go` from package `runtime/cgo`
The files `abi_*.h` and `internal/fakecgo/abi_*.h` are the same because Bazel does not support cross-package use of The files `abi_*.h` and `internal/fakecgo/abi_*.h` are the same because Bazel does not support cross-package use of
`#include` so we need each one once per package. (cf. [issue](https://github.com/bazelbuild/rules_go/issues/3636)) `#include` so we need each one once per package. (cf. [issue](https://github.com/bazelbuild/rules_go/issues/3636))

60
vendor/github.com/ebitengine/purego/abi_loong64.h generated vendored Normal file
View File

@@ -0,0 +1,60 @@
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Macros for transitioning from the host ABI to Go ABI0.
//
// These macros save and restore the callee-saved registers
// from the stack, but they don't adjust stack pointer, so
// the user should prepare stack space in advance.
// SAVE_R22_TO_R31(offset) saves R22 ~ R31 to the stack space
// of ((offset)+0*8)(R3) ~ ((offset)+9*8)(R3).
//
// SAVE_F24_TO_F31(offset) saves F24 ~ F31 to the stack space
// of ((offset)+0*8)(R3) ~ ((offset)+7*8)(R3).
//
// Note: g is R22
#define SAVE_R22_TO_R31(offset) \
MOVV g, ((offset)+(0*8))(R3) \
MOVV R23, ((offset)+(1*8))(R3) \
MOVV R24, ((offset)+(2*8))(R3) \
MOVV R25, ((offset)+(3*8))(R3) \
MOVV R26, ((offset)+(4*8))(R3) \
MOVV R27, ((offset)+(5*8))(R3) \
MOVV R28, ((offset)+(6*8))(R3) \
MOVV R29, ((offset)+(7*8))(R3) \
MOVV R30, ((offset)+(8*8))(R3) \
MOVV R31, ((offset)+(9*8))(R3)
#define SAVE_F24_TO_F31(offset) \
MOVD F24, ((offset)+(0*8))(R3) \
MOVD F25, ((offset)+(1*8))(R3) \
MOVD F26, ((offset)+(2*8))(R3) \
MOVD F27, ((offset)+(3*8))(R3) \
MOVD F28, ((offset)+(4*8))(R3) \
MOVD F29, ((offset)+(5*8))(R3) \
MOVD F30, ((offset)+(6*8))(R3) \
MOVD F31, ((offset)+(7*8))(R3)
#define RESTORE_R22_TO_R31(offset) \
MOVV ((offset)+(0*8))(R3), g \
MOVV ((offset)+(1*8))(R3), R23 \
MOVV ((offset)+(2*8))(R3), R24 \
MOVV ((offset)+(3*8))(R3), R25 \
MOVV ((offset)+(4*8))(R3), R26 \
MOVV ((offset)+(5*8))(R3), R27 \
MOVV ((offset)+(6*8))(R3), R28 \
MOVV ((offset)+(7*8))(R3), R29 \
MOVV ((offset)+(8*8))(R3), R30 \
MOVV ((offset)+(9*8))(R3), R31
#define RESTORE_F24_TO_F31(offset) \
MOVD ((offset)+(0*8))(R3), F24 \
MOVD ((offset)+(1*8))(R3), F25 \
MOVD ((offset)+(2*8))(R3), F26 \
MOVD ((offset)+(3*8))(R3), F27 \
MOVD ((offset)+(4*8))(R3), F28 \
MOVD ((offset)+(5*8))(R3), F29 \
MOVD ((offset)+(6*8))(R3), F30 \
MOVD ((offset)+(7*8))(R3), F31

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build cgo && (darwin || freebsd || linux) //go:build cgo && (darwin || freebsd || linux || netbsd)
package purego package purego

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 The Ebitengine Authors // SPDX-FileCopyrightText: 2023 The Ebitengine Authors
//go:build darwin || freebsd || linux //go:build darwin || freebsd || linux || netbsd
package purego package purego

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build (darwin || freebsd || linux) && !android && !faketime //go:build (darwin || freebsd || linux || netbsd) && !android && !faketime
package purego package purego

15
vendor/github.com/ebitengine/purego/dlfcn_netbsd.go generated vendored Normal file
View File

@@ -0,0 +1,15 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
package purego
// Source for constants: https://github.com/NetBSD/src/blob/trunk/include/dlfcn.h
const (
intSize = 32 << (^uint(0) >> 63) // 32 or 64
RTLD_DEFAULT = 1<<intSize - 2 // Pseudo-handle for dlsym so search for any loaded symbol
RTLD_LAZY = 0x00000001 // Relocations are performed at an implementation-dependent time.
RTLD_NOW = 0x00000002 // Relocations are performed when the object is loaded.
RTLD_LOCAL = 0x00000000 // All symbols are not made available for relocation processing by other modules.
RTLD_GLOBAL = 0x00000100 // All symbols are available for relocation processing of other modules.
)

View File

@@ -0,0 +1,9 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
package purego
//go:cgo_import_dynamic purego_dlopen dlopen "libc.so"
//go:cgo_import_dynamic purego_dlsym dlsym "libc.so"
//go:cgo_import_dynamic purego_dlerror dlerror "libc.so"
//go:cgo_import_dynamic purego_dlclose dlclose "libc.so"

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build darwin || !cgo && (freebsd || linux) && !faketime //go:build darwin || !cgo && (freebsd || linux || netbsd) && !faketime
#include "textflag.h" #include "textflag.h"

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build darwin || freebsd || linux || windows //go:build darwin || freebsd || linux || netbsd || windows
package purego package purego
@@ -10,14 +10,20 @@ import (
"math" "math"
"reflect" "reflect"
"runtime" "runtime"
"strconv"
"sync"
"unsafe" "unsafe"
"github.com/ebitengine/purego/internal/strings" "github.com/ebitengine/purego/internal/strings"
) )
var thePool = sync.Pool{New: func() any {
return new(syscall15Args)
}}
// RegisterLibFunc is a wrapper around RegisterFunc that uses the C function returned from Dlsym(handle, name). // RegisterLibFunc is a wrapper around RegisterFunc that uses the C function returned from Dlsym(handle, name).
// It panics if it can't find the name symbol. // It panics if it can't find the name symbol.
func RegisterLibFunc(fptr interface{}, handle uintptr, name string) { func RegisterLibFunc(fptr any, handle uintptr, name string) {
sym, err := loadSymbol(handle, name) sym, err := loadSymbol(handle, name)
if err != nil { if err != nil {
panic(err) panic(err)
@@ -60,7 +66,7 @@ func RegisterLibFunc(fptr interface{}, handle uintptr, name string) {
// //
// There is a special case when the last argument of fptr is a variadic interface (or []interface} // There is a special case when the last argument of fptr is a variadic interface (or []interface}
// it will be expanded into a call to the C function as if it had the arguments in that slice. // it will be expanded into a call to the C function as if it had the arguments in that slice.
// This means that using arg ...interface{} is like a cast to the function with the arguments inside arg. // This means that using arg ...any is like a cast to the function with the arguments inside arg.
// This is not the same as C variadic. // This is not the same as C variadic.
// //
// # Memory // # Memory
@@ -105,7 +111,7 @@ func RegisterLibFunc(fptr interface{}, handle uintptr, name string) {
// defer free(mustFree) // defer free(mustFree)
// //
// [Cgo rules]: https://pkg.go.dev/cmd/cgo#hdr-Go_references_to_C // [Cgo rules]: https://pkg.go.dev/cmd/cgo#hdr-Go_references_to_C
func RegisterFunc(fptr interface{}, cfn uintptr) { func RegisterFunc(fptr any, cfn uintptr) {
fn := reflect.ValueOf(fptr).Elem() fn := reflect.ValueOf(fptr).Elem()
ty := fn.Type() ty := fn.Type()
if ty.Kind() != reflect.Func { if ty.Kind() != reflect.Func {
@@ -118,7 +124,7 @@ func RegisterFunc(fptr interface{}, cfn uintptr) {
panic("purego: cfn is nil") panic("purego: cfn is nil")
} }
if ty.NumOut() == 1 && (ty.Out(0).Kind() == reflect.Float32 || ty.Out(0).Kind() == reflect.Float64) && if ty.NumOut() == 1 && (ty.Out(0).Kind() == reflect.Float32 || ty.Out(0).Kind() == reflect.Float64) &&
runtime.GOARCH != "arm64" && runtime.GOARCH != "amd64" { runtime.GOARCH != "arm64" && runtime.GOARCH != "amd64" && runtime.GOARCH != "loong64" {
panic("purego: float returns are not supported") panic("purego: float returns are not supported")
} }
{ {
@@ -156,7 +162,7 @@ func RegisterFunc(fptr interface{}, cfn uintptr) {
if is32bit { if is32bit {
panic("purego: floats only supported on 64bit platforms") panic("purego: floats only supported on 64bit platforms")
} }
if floats < numOfFloats { if floats < numOfFloatRegisters {
floats++ floats++
} else { } else {
stack++ stack++
@@ -200,21 +206,8 @@ func RegisterFunc(fptr interface{}, cfn uintptr) {
} }
} }
v := reflect.MakeFunc(ty, func(args []reflect.Value) (results []reflect.Value) { v := reflect.MakeFunc(ty, func(args []reflect.Value) (results []reflect.Value) {
if len(args) > 0 {
if variadic, ok := args[len(args)-1].Interface().([]interface{}); ok {
// subtract one from args bc the last argument in args is []interface{}
// which we are currently expanding
tmp := make([]reflect.Value, len(args)-1+len(variadic))
n := copy(tmp, args[:len(args)-1])
for i, v := range variadic {
tmp[n+i] = reflect.ValueOf(v)
}
args = tmp
}
}
var sysargs [maxArgs]uintptr var sysargs [maxArgs]uintptr
stack := sysargs[numOfIntegerRegisters():] var floats [numOfFloatRegisters]uintptr
var floats [numOfFloats]uintptr
var numInts int var numInts int
var numFloats int var numFloats int
var numStack int var numStack int
@@ -222,7 +215,7 @@ func RegisterFunc(fptr interface{}, cfn uintptr) {
if runtime.GOARCH == "arm64" || runtime.GOOS != "windows" { if runtime.GOARCH == "arm64" || runtime.GOOS != "windows" {
// Windows arm64 uses the same calling convention as macOS and Linux // Windows arm64 uses the same calling convention as macOS and Linux
addStack = func(x uintptr) { addStack = func(x uintptr) {
stack[numStack] = x sysargs[numOfIntegerRegisters()+numStack] = x
numStack++ numStack++
} }
addInt = func(x uintptr) { addInt = func(x uintptr) {
@@ -255,15 +248,16 @@ func RegisterFunc(fptr interface{}, cfn uintptr) {
addFloat = addStack addFloat = addStack
} }
var keepAlive []interface{} var keepAlive []any
defer func() { defer func() {
runtime.KeepAlive(keepAlive) runtime.KeepAlive(keepAlive)
runtime.KeepAlive(args) runtime.KeepAlive(args)
}() }()
var syscall syscall15Args
var arm64_r8 uintptr
if ty.NumOut() == 1 && ty.Out(0).Kind() == reflect.Struct { if ty.NumOut() == 1 && ty.Out(0).Kind() == reflect.Struct {
outType := ty.Out(0) outType := ty.Out(0)
if runtime.GOARCH == "amd64" && outType.Size() > maxRegAllocStructSize { if (runtime.GOARCH == "amd64" || runtime.GOARCH == "loong64") && outType.Size() > maxRegAllocStructSize {
val := reflect.New(outType) val := reflect.New(outType)
keepAlive = append(keepAlive, val) keepAlive = append(keepAlive, val)
addInt(val.Pointer()) addInt(val.Pointer())
@@ -272,53 +266,73 @@ func RegisterFunc(fptr interface{}, cfn uintptr) {
if !isAllFloats || numFields > 4 { if !isAllFloats || numFields > 4 {
val := reflect.New(outType) val := reflect.New(outType)
keepAlive = append(keepAlive, val) keepAlive = append(keepAlive, val)
syscall.arm64_r8 = val.Pointer() arm64_r8 = val.Pointer()
} }
} }
} }
for _, v := range args { for i, v := range args {
switch v.Kind() { if variadic, ok := args[i].Interface().([]any); ok {
case reflect.String: if i != len(args)-1 {
ptr := strings.CString(v.String()) panic("purego: can only expand last parameter")
keepAlive = append(keepAlive, ptr)
addInt(uintptr(unsafe.Pointer(ptr)))
case reflect.Uintptr, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
addInt(uintptr(v.Uint()))
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
addInt(uintptr(v.Int()))
case reflect.Ptr, reflect.UnsafePointer, reflect.Slice:
// There is no need to keepAlive this pointer separately because it is kept alive in the args variable
addInt(v.Pointer())
case reflect.Func:
addInt(NewCallback(v.Interface()))
case reflect.Bool:
if v.Bool() {
addInt(1)
} else {
addInt(0)
} }
case reflect.Float32: for _, x := range variadic {
addFloat(uintptr(math.Float32bits(float32(v.Float())))) keepAlive = addValue(reflect.ValueOf(x), keepAlive, addInt, addFloat, addStack, &numInts, &numFloats, &numStack)
case reflect.Float64: }
addFloat(uintptr(math.Float64bits(v.Float()))) continue
case reflect.Struct:
keepAlive = addStruct(v, &numInts, &numFloats, &numStack, addInt, addFloat, addStack, keepAlive)
default:
panic("purego: unsupported kind: " + v.Kind().String())
} }
if runtime.GOARCH == "arm64" && runtime.GOOS == "darwin" &&
(numInts >= numOfIntegerRegisters() || numFloats >= numOfFloatRegisters) && v.Kind() != reflect.Struct { // hit the stack
fields := make([]reflect.StructField, len(args[i:]))
for j, val := range args[i:] {
if val.Kind() == reflect.String {
ptr := strings.CString(v.String())
keepAlive = append(keepAlive, ptr)
val = reflect.ValueOf(ptr)
args[i+j] = val
}
fields[j] = reflect.StructField{
Name: "X" + strconv.Itoa(j),
Type: val.Type(),
}
}
structType := reflect.StructOf(fields)
structInstance := reflect.New(structType).Elem()
for j, val := range args[i:] {
structInstance.Field(j).Set(val)
}
placeRegisters(structInstance, addFloat, addInt)
break
}
keepAlive = addValue(v, keepAlive, addInt, addFloat, addStack, &numInts, &numFloats, &numStack)
} }
if runtime.GOARCH == "arm64" || runtime.GOOS != "windows" {
// Use the normal arm64 calling convention even on Windows syscall := thePool.Get().(*syscall15Args)
syscall = syscall15Args{ defer thePool.Put(syscall)
if runtime.GOARCH == "loong64" {
*syscall = syscall15Args{
cfn, cfn,
sysargs[0], sysargs[1], sysargs[2], sysargs[3], sysargs[4], sysargs[5], sysargs[0], sysargs[1], sysargs[2], sysargs[3], sysargs[4], sysargs[5],
sysargs[6], sysargs[7], sysargs[8], sysargs[9], sysargs[10], sysargs[11], sysargs[6], sysargs[7], sysargs[8], sysargs[9], sysargs[10], sysargs[11],
sysargs[12], sysargs[13], sysargs[14], sysargs[12], sysargs[13], sysargs[14],
floats[0], floats[1], floats[2], floats[3], floats[4], floats[5], floats[6], floats[7], floats[0], floats[1], floats[2], floats[3], floats[4], floats[5], floats[6], floats[7],
syscall.arm64_r8, 0,
} }
runtime_cgocall(syscall15XABI0, unsafe.Pointer(&syscall)) runtime_cgocall(syscall15XABI0, unsafe.Pointer(syscall))
} else if runtime.GOARCH == "arm64" || runtime.GOOS != "windows" {
// Use the normal arm64 calling convention even on Windows
*syscall = syscall15Args{
cfn,
sysargs[0], sysargs[1], sysargs[2], sysargs[3], sysargs[4], sysargs[5],
sysargs[6], sysargs[7], sysargs[8], sysargs[9], sysargs[10], sysargs[11],
sysargs[12], sysargs[13], sysargs[14],
floats[0], floats[1], floats[2], floats[3], floats[4], floats[5], floats[6], floats[7],
arm64_r8,
}
runtime_cgocall(syscall15XABI0, unsafe.Pointer(syscall))
} else { } else {
*syscall = syscall15Args{}
// This is a fallback for Windows amd64, 386, and arm. Note this may not support floats // This is a fallback for Windows amd64, 386, and arm. Note this may not support floats
syscall.a1, syscall.a2, _ = syscall_syscall15X(cfn, sysargs[0], sysargs[1], sysargs[2], sysargs[3], sysargs[4], syscall.a1, syscall.a2, _ = syscall_syscall15X(cfn, sysargs[0], sysargs[1], sysargs[2], sysargs[3], sysargs[4],
sysargs[5], sysargs[6], sysargs[7], sysargs[8], sysargs[9], sysargs[10], sysargs[11], sysargs[5], sysargs[6], sysargs[7], sysargs[8], sysargs[9], sysargs[10], sysargs[11],
@@ -357,15 +371,54 @@ func RegisterFunc(fptr interface{}, cfn uintptr) {
// On 32bit platforms syscall.r2 is the upper part of a 64bit return. // On 32bit platforms syscall.r2 is the upper part of a 64bit return.
v.SetFloat(math.Float64frombits(uint64(syscall.f1))) v.SetFloat(math.Float64frombits(uint64(syscall.f1)))
case reflect.Struct: case reflect.Struct:
v = getStruct(outType, syscall) v = getStruct(outType, *syscall)
default: default:
panic("purego: unsupported return kind: " + outType.Kind().String()) panic("purego: unsupported return kind: " + outType.Kind().String())
} }
return []reflect.Value{v} if len(args) > 0 {
// reuse args slice instead of allocating one when possible
args[0] = v
return args[:1]
} else {
return []reflect.Value{v}
}
}) })
fn.Set(v) fn.Set(v)
} }
func addValue(v reflect.Value, keepAlive []any, addInt func(x uintptr), addFloat func(x uintptr), addStack func(x uintptr), numInts *int, numFloats *int, numStack *int) []any {
switch v.Kind() {
case reflect.String:
ptr := strings.CString(v.String())
keepAlive = append(keepAlive, ptr)
addInt(uintptr(unsafe.Pointer(ptr)))
case reflect.Uintptr, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
addInt(uintptr(v.Uint()))
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
addInt(uintptr(v.Int()))
case reflect.Ptr, reflect.UnsafePointer, reflect.Slice:
// There is no need to keepAlive this pointer separately because it is kept alive in the args variable
addInt(v.Pointer())
case reflect.Func:
addInt(NewCallback(v.Interface()))
case reflect.Bool:
if v.Bool() {
addInt(1)
} else {
addInt(0)
}
case reflect.Float32:
addFloat(uintptr(math.Float32bits(float32(v.Float()))))
case reflect.Float64:
addFloat(uintptr(math.Float64bits(v.Float())))
case reflect.Struct:
keepAlive = addStruct(v, numInts, numFloats, numStack, addInt, addFloat, addStack, keepAlive)
default:
panic("purego: unsupported kind: " + v.Kind().String())
}
return keepAlive
}
// maxRegAllocStructSize is the biggest a struct can be while still fitting in registers. // maxRegAllocStructSize is the biggest a struct can be while still fitting in registers.
// if it is bigger than this than enough space must be allocated on the heap and then passed into // if it is bigger than this than enough space must be allocated on the heap and then passed into
// the function as the first parameter on amd64 or in R8 on arm64. // the function as the first parameter on amd64 or in R8 on arm64.
@@ -424,7 +477,7 @@ func roundUpTo8(val uintptr) uintptr {
func numOfIntegerRegisters() int { func numOfIntegerRegisters() int {
switch runtime.GOARCH { switch runtime.GOARCH {
case "arm64": case "arm64", "loong64":
return 8 return 8
case "amd64": case "amd64":
return 6 return 6

6
vendor/github.com/ebitengine/purego/gen.go generated vendored Normal file
View File

@@ -0,0 +1,6 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
package purego
//go:generate go run wincallback.go

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build darwin || freebsd || linux || windows //go:build darwin || freebsd || linux || netbsd || windows
package purego package purego

View File

@@ -1,12 +1,12 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2024 The Ebitengine Authors // SPDX-FileCopyrightText: 2024 The Ebitengine Authors
//go:build freebsd || linux //go:build freebsd || linux || netbsd
package cgo package cgo
/* /*
#cgo LDFLAGS: -ldl #cgo !netbsd LDFLAGS: -ldl
#include <dlfcn.h> #include <dlfcn.h>
#include <stdlib.h> #include <stdlib.h>

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build freebsd || (linux && !(arm64 || amd64)) //go:build freebsd || (linux && !(arm64 || amd64 || loong64)) || netbsd
package cgo package cgo
@@ -9,7 +9,7 @@ package cgo
// because Cgo and assembly files can't be in the same package. // because Cgo and assembly files can't be in the same package.
/* /*
#cgo LDFLAGS: -ldl #cgo !netbsd LDFLAGS: -ldl
#include <stdint.h> #include <stdint.h>
#include <dlfcn.h> #include <dlfcn.h>

View File

@@ -0,0 +1,60 @@
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Macros for transitioning from the host ABI to Go ABI0.
//
// These macros save and restore the callee-saved registers
// from the stack, but they don't adjust stack pointer, so
// the user should prepare stack space in advance.
// SAVE_R22_TO_R31(offset) saves R22 ~ R31 to the stack space
// of ((offset)+0*8)(R3) ~ ((offset)+9*8)(R3).
//
// SAVE_F24_TO_F31(offset) saves F24 ~ F31 to the stack space
// of ((offset)+0*8)(R3) ~ ((offset)+7*8)(R3).
//
// Note: g is R22
#define SAVE_R22_TO_R31(offset) \
MOVV g, ((offset)+(0*8))(R3) \
MOVV R23, ((offset)+(1*8))(R3) \
MOVV R24, ((offset)+(2*8))(R3) \
MOVV R25, ((offset)+(3*8))(R3) \
MOVV R26, ((offset)+(4*8))(R3) \
MOVV R27, ((offset)+(5*8))(R3) \
MOVV R28, ((offset)+(6*8))(R3) \
MOVV R29, ((offset)+(7*8))(R3) \
MOVV R30, ((offset)+(8*8))(R3) \
MOVV R31, ((offset)+(9*8))(R3)
#define SAVE_F24_TO_F31(offset) \
MOVD F24, ((offset)+(0*8))(R3) \
MOVD F25, ((offset)+(1*8))(R3) \
MOVD F26, ((offset)+(2*8))(R3) \
MOVD F27, ((offset)+(3*8))(R3) \
MOVD F28, ((offset)+(4*8))(R3) \
MOVD F29, ((offset)+(5*8))(R3) \
MOVD F30, ((offset)+(6*8))(R3) \
MOVD F31, ((offset)+(7*8))(R3)
#define RESTORE_R22_TO_R31(offset) \
MOVV ((offset)+(0*8))(R3), g \
MOVV ((offset)+(1*8))(R3), R23 \
MOVV ((offset)+(2*8))(R3), R24 \
MOVV ((offset)+(3*8))(R3), R25 \
MOVV ((offset)+(4*8))(R3), R26 \
MOVV ((offset)+(5*8))(R3), R27 \
MOVV ((offset)+(6*8))(R3), R28 \
MOVV ((offset)+(7*8))(R3), R29 \
MOVV ((offset)+(8*8))(R3), R30 \
MOVV ((offset)+(9*8))(R3), R31
#define RESTORE_F24_TO_F31(offset) \
MOVD ((offset)+(0*8))(R3), F24 \
MOVD ((offset)+(1*8))(R3), F25 \
MOVD ((offset)+(2*8))(R3), F26 \
MOVD ((offset)+(3*8))(R3), F27 \
MOVD ((offset)+(4*8))(R3), F28 \
MOVD ((offset)+(5*8))(R3), F29 \
MOVD ((offset)+(6*8))(R3), F30 \
MOVD ((offset)+(7*8))(R3), F31

View File

@@ -0,0 +1,40 @@
// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "textflag.h"
#include "abi_loong64.h"
// Called by C code generated by cmd/cgo.
// func crosscall2(fn, a unsafe.Pointer, n int32, ctxt uintptr)
// Saves C callee-saved registers and calls cgocallback with three arguments.
// fn is the PC of a func(a unsafe.Pointer) function.
TEXT crosscall2(SB),NOSPLIT|NOFRAME,$0
/*
* We still need to save all callee save register as before, and then
* push 3 args for fn (R4, R5, R7), skipping R6.
* Also note that at procedure entry in gc world, 8(R29) will be the
* first arg.
*/
ADDV $(-23*8), R3
MOVV R4, (1*8)(R3) // fn unsafe.Pointer
MOVV R5, (2*8)(R3) // a unsafe.Pointer
MOVV R7, (3*8)(R3) // ctxt uintptr
SAVE_R22_TO_R31((4*8))
SAVE_F24_TO_F31((14*8))
MOVV R1, (22*8)(R3)
// Initialize Go ABI environment
JAL runtime·load_g(SB)
JAL runtime·cgocallback(SB)
RESTORE_R22_TO_R31((4*8))
RESTORE_F24_TO_F31((14*8))
MOVV (22*8)(R3), R1
ADDV $(23*8), R3
RET

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !cgo && (darwin || freebsd || linux) //go:build !cgo && (darwin || freebsd || linux || netbsd)
package fakecgo package fakecgo

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build !cgo && (darwin || freebsd || linux) //go:build !cgo && (darwin || freebsd || linux || netbsd)
// Package fakecgo implements the Cgo runtime (runtime/cgo) entirely in Go. // Package fakecgo implements the Cgo runtime (runtime/cgo) entirely in Go.
// This allows code that calls into C to function properly when CGO_ENABLED=0. // This allows code that calls into C to function properly when CGO_ENABLED=0.

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build !cgo && (darwin || freebsd || linux) //go:build !cgo && (darwin || freebsd || linux || netbsd)
package fakecgo package fakecgo

View File

@@ -0,0 +1,92 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !cgo
package fakecgo
import "unsafe"
//go:nosplit
func _cgo_sys_thread_start(ts *ThreadStart) {
var attr pthread_attr_t
var ign, oset sigset_t
var p pthread_t
var size size_t
var err int
sigfillset(&ign)
pthread_sigmask(SIG_SETMASK, &ign, &oset)
pthread_attr_init(&attr)
pthread_attr_getstacksize(&attr, &size)
// Leave stacklo=0 and set stackhi=size; mstart will do the rest.
ts.g.stackhi = uintptr(size)
err = _cgo_try_pthread_create(&p, &attr, unsafe.Pointer(threadentry_trampolineABI0), ts)
pthread_sigmask(SIG_SETMASK, &oset, nil)
if err != 0 {
print("fakecgo: pthread_create failed: ")
println(err)
abort()
}
}
// threadentry_trampolineABI0 maps the C ABI to Go ABI then calls the Go function
//
//go:linkname x_threadentry_trampoline threadentry_trampoline
var x_threadentry_trampoline byte
var threadentry_trampolineABI0 = &x_threadentry_trampoline
//go:nosplit
func threadentry(v unsafe.Pointer) unsafe.Pointer {
ts := *(*ThreadStart)(v)
free(v)
setg_trampoline(setg_func, uintptr(unsafe.Pointer(ts.g)))
// faking funcs in go is a bit a... involved - but the following works :)
fn := uintptr(unsafe.Pointer(&ts.fn))
(*(*func())(unsafe.Pointer(&fn)))()
return nil
}
// here we will store a pointer to the provided setg func
var setg_func uintptr
//go:nosplit
func x_cgo_init(g *G, setg uintptr) {
var size size_t
var attr *pthread_attr_t
/* The memory sanitizer distributed with versions of clang
before 3.8 has a bug: if you call mmap before malloc, mmap
may return an address that is later overwritten by the msan
library. Avoid this problem by forcing a call to malloc
here, before we ever call malloc.
This is only required for the memory sanitizer, so it's
unfortunate that we always run it. It should be possible
to remove this when we no longer care about versions of
clang before 3.8. The test for this is
misc/cgo/testsanitizers.
GCC works hard to eliminate a seemingly unnecessary call to
malloc, so we actually use the memory we allocate. */
setg_func = setg
attr = (*pthread_attr_t)(malloc(unsafe.Sizeof(*attr)))
if attr == nil {
println("fakecgo: malloc failed")
abort()
}
pthread_attr_init(attr)
pthread_attr_getstacksize(attr, &size)
g.stacklo = uintptr(unsafe.Pointer(&size)) - uintptr(size) + 4096
pthread_attr_destroy(attr)
free(unsafe.Pointer(attr))
}

View File

@@ -0,0 +1,106 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !cgo && (amd64 || arm64)
package fakecgo
import "unsafe"
//go:nosplit
func _cgo_sys_thread_start(ts *ThreadStart) {
var attr pthread_attr_t
var ign, oset sigset_t
var p pthread_t
var size size_t
var err int
// fprintf(stderr, "runtime/cgo: _cgo_sys_thread_start: fn=%p, g=%p\n", ts->fn, ts->g); // debug
sigfillset(&ign)
pthread_sigmask(SIG_SETMASK, &ign, &oset)
pthread_attr_init(&attr)
pthread_attr_getstacksize(&attr, &size)
// Leave stacklo=0 and set stackhi=size; mstart will do the rest.
ts.g.stackhi = uintptr(size)
err = _cgo_try_pthread_create(&p, &attr, unsafe.Pointer(threadentry_trampolineABI0), ts)
pthread_sigmask(SIG_SETMASK, &oset, nil)
if err != 0 {
print("fakecgo: pthread_create failed: ")
println(err)
abort()
}
}
// threadentry_trampolineABI0 maps the C ABI to Go ABI then calls the Go function
//
//go:linkname x_threadentry_trampoline threadentry_trampoline
var x_threadentry_trampoline byte
var threadentry_trampolineABI0 = &x_threadentry_trampoline
//go:nosplit
func threadentry(v unsafe.Pointer) unsafe.Pointer {
var ss stack_t
ts := *(*ThreadStart)(v)
free(v)
// On NetBSD, a new thread inherits the signal stack of the
// creating thread. That confuses minit, so we remove that
// signal stack here before calling the regular mstart. It's
// a bit baroque to remove a signal stack here only to add one
// in minit, but it's a simple change that keeps NetBSD
// working like other OS's. At this point all signals are
// blocked, so there is no race.
ss.ss_flags = SS_DISABLE
sigaltstack(&ss, nil)
setg_trampoline(setg_func, uintptr(unsafe.Pointer(ts.g)))
// faking funcs in go is a bit a... involved - but the following works :)
fn := uintptr(unsafe.Pointer(&ts.fn))
(*(*func())(unsafe.Pointer(&fn)))()
return nil
}
// here we will store a pointer to the provided setg func
var setg_func uintptr
//go:nosplit
func x_cgo_init(g *G, setg uintptr) {
var size size_t
var attr *pthread_attr_t
/* The memory sanitizer distributed with versions of clang
before 3.8 has a bug: if you call mmap before malloc, mmap
may return an address that is later overwritten by the msan
library. Avoid this problem by forcing a call to malloc
here, before we ever call malloc.
This is only required for the memory sanitizer, so it's
unfortunate that we always run it. It should be possible
to remove this when we no longer care about versions of
clang before 3.8. The test for this is
misc/cgo/testsanitizers.
GCC works hard to eliminate a seemingly unnecessary call to
malloc, so we actually use the memory we allocate. */
setg_func = setg
attr = (*pthread_attr_t)(malloc(unsafe.Sizeof(*attr)))
if attr == nil {
println("fakecgo: malloc failed")
abort()
}
pthread_attr_init(attr)
pthread_attr_getstacksize(attr, &size)
// runtime/cgo uses __builtin_frame_address(0) instead of `uintptr(unsafe.Pointer(&size))`
// but this should be OK since we are taking the address of the first variable in this function.
g.stacklo = uintptr(unsafe.Pointer(&size)) - uintptr(size) + 4096
pthread_attr_destroy(attr)
free(unsafe.Pointer(attr))
}

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build !cgo && (darwin || freebsd || linux) //go:build !cgo && (darwin || freebsd || linux || netbsd)
package fakecgo package fakecgo

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build !cgo && (darwin || freebsd || linux) //go:build !cgo && (darwin || freebsd || linux || netbsd)
package fakecgo package fakecgo

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !cgo && (darwin || freebsd || linux) //go:build !cgo && (darwin || freebsd || linux || netbsd)
// The runtime package contains an uninitialized definition // The runtime package contains an uninitialized definition
// for runtime·iscgo. Override it to tell the runtime we're here. // for runtime·iscgo. Override it to tell the runtime we're here.

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build !cgo && (darwin || freebsd || linux) //go:build !cgo && (darwin || freebsd || linux || netbsd)
package fakecgo package fakecgo

View File

@@ -20,3 +20,7 @@ var (
PTHREAD_COND_INITIALIZER = pthread_cond_t{sig: 0x3CB0B1BB} PTHREAD_COND_INITIALIZER = pthread_cond_t{sig: 0x3CB0B1BB}
PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t{sig: 0x32AAABA7} PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t{sig: 0x32AAABA7}
) )
type stack_t struct {
/* not implemented */
}

View File

@@ -14,3 +14,7 @@ var (
PTHREAD_COND_INITIALIZER = pthread_cond_t(0) PTHREAD_COND_INITIALIZER = pthread_cond_t(0)
PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t(0) PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t(0)
) )
type stack_t struct {
/* not implemented */
}

View File

@@ -14,3 +14,7 @@ var (
PTHREAD_COND_INITIALIZER = pthread_cond_t{} PTHREAD_COND_INITIALIZER = pthread_cond_t{}
PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t{} PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t{}
) )
type stack_t struct {
/* not implemented */
}

View File

@@ -0,0 +1,26 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
//go:build !cgo
package fakecgo
type (
pthread_cond_t uintptr
pthread_mutex_t uintptr
)
var (
PTHREAD_COND_INITIALIZER = pthread_cond_t(0)
PTHREAD_MUTEX_INITIALIZER = pthread_mutex_t(0)
)
// Source: https://github.com/NetBSD/src/blob/613e27c65223fd2283b6ed679da1197e12f50e27/sys/compat/linux/arch/m68k/linux_signal.h#L133
type stack_t struct {
ss_sp uintptr
ss_flags int32
ss_size uintptr
}
// Source: https://github.com/NetBSD/src/blob/613e27c65223fd2283b6ed679da1197e12f50e27/sys/sys/signal.h#L261
const SS_DISABLE = 0x004

View File

@@ -0,0 +1,23 @@
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build netbsd
package fakecgo
import _ "unsafe" // for go:linkname
// Supply environ and __progname, because we don't
// link against the standard NetBSD crt0.o and the
// libc dynamic library needs them.
//go:linkname _environ environ
//go:linkname _progname __progname
//go:linkname ___ps_strings __ps_strings
var (
_environ uintptr
_progname uintptr
___ps_strings uintptr
)

View File

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//go:build !cgo && (darwin || freebsd || linux) //go:build !cgo && (darwin || freebsd || linux || netbsd)
package fakecgo package fakecgo

View File

@@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build !cgo && (darwin || freebsd || linux) //go:build !cgo && (darwin || freebsd || linux || netbsd)
package fakecgo package fakecgo
@@ -62,6 +62,12 @@ func abort() {
call5(abortABI0, 0, 0, 0, 0, 0) call5(abortABI0, 0, 0, 0, 0, 0)
} }
//go:nosplit
//go:norace
func sigaltstack(ss *stack_t, old_ss *stack_t) int32 {
return int32(call5(sigaltstackABI0, uintptr(unsafe.Pointer(ss)), uintptr(unsafe.Pointer(old_ss)), 0, 0, 0))
}
//go:nosplit //go:nosplit
//go:norace //go:norace
func pthread_attr_init(attr *pthread_attr_t) int32 { func pthread_attr_init(attr *pthread_attr_t) int32 {
@@ -168,6 +174,10 @@ var nanosleepABI0 = uintptr(unsafe.Pointer(&_nanosleep))
var _abort uint8 var _abort uint8
var abortABI0 = uintptr(unsafe.Pointer(&_abort)) var abortABI0 = uintptr(unsafe.Pointer(&_abort))
//go:linkname _sigaltstack _sigaltstack
var _sigaltstack uint8
var sigaltstackABI0 = uintptr(unsafe.Pointer(&_sigaltstack))
//go:linkname _pthread_attr_init _pthread_attr_init //go:linkname _pthread_attr_init _pthread_attr_init
var _pthread_attr_init uint8 var _pthread_attr_init uint8
var pthread_attr_initABI0 = uintptr(unsafe.Pointer(&_pthread_attr_init)) var pthread_attr_initABI0 = uintptr(unsafe.Pointer(&_pthread_attr_init))

View File

@@ -14,6 +14,7 @@ package fakecgo
//go:cgo_import_dynamic purego_sigfillset sigfillset "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic purego_sigfillset sigfillset "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic purego_nanosleep nanosleep "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic purego_nanosleep nanosleep "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic purego_abort abort "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic purego_abort abort "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic purego_sigaltstack sigaltstack "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic purego_pthread_attr_init pthread_attr_init "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic purego_pthread_attr_init pthread_attr_init "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic purego_pthread_create pthread_create "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic purego_pthread_create pthread_create "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic purego_pthread_detach pthread_detach "/usr/lib/libSystem.B.dylib" //go:cgo_import_dynamic purego_pthread_detach pthread_detach "/usr/lib/libSystem.B.dylib"

View File

@@ -14,6 +14,7 @@ package fakecgo
//go:cgo_import_dynamic purego_sigfillset sigfillset "libc.so.7" //go:cgo_import_dynamic purego_sigfillset sigfillset "libc.so.7"
//go:cgo_import_dynamic purego_nanosleep nanosleep "libc.so.7" //go:cgo_import_dynamic purego_nanosleep nanosleep "libc.so.7"
//go:cgo_import_dynamic purego_abort abort "libc.so.7" //go:cgo_import_dynamic purego_abort abort "libc.so.7"
//go:cgo_import_dynamic purego_sigaltstack sigaltstack "libc.so.7"
//go:cgo_import_dynamic purego_pthread_attr_init pthread_attr_init "libpthread.so" //go:cgo_import_dynamic purego_pthread_attr_init pthread_attr_init "libpthread.so"
//go:cgo_import_dynamic purego_pthread_create pthread_create "libpthread.so" //go:cgo_import_dynamic purego_pthread_create pthread_create "libpthread.so"
//go:cgo_import_dynamic purego_pthread_detach pthread_detach "libpthread.so" //go:cgo_import_dynamic purego_pthread_detach pthread_detach "libpthread.so"

View File

@@ -14,6 +14,7 @@ package fakecgo
//go:cgo_import_dynamic purego_sigfillset sigfillset "libc.so.6" //go:cgo_import_dynamic purego_sigfillset sigfillset "libc.so.6"
//go:cgo_import_dynamic purego_nanosleep nanosleep "libc.so.6" //go:cgo_import_dynamic purego_nanosleep nanosleep "libc.so.6"
//go:cgo_import_dynamic purego_abort abort "libc.so.6" //go:cgo_import_dynamic purego_abort abort "libc.so.6"
//go:cgo_import_dynamic purego_sigaltstack sigaltstack "libc.so.6"
//go:cgo_import_dynamic purego_pthread_attr_init pthread_attr_init "libpthread.so.0" //go:cgo_import_dynamic purego_pthread_attr_init pthread_attr_init "libpthread.so.0"
//go:cgo_import_dynamic purego_pthread_create pthread_create "libpthread.so.0" //go:cgo_import_dynamic purego_pthread_create pthread_create "libpthread.so.0"
//go:cgo_import_dynamic purego_pthread_detach pthread_detach "libpthread.so.0" //go:cgo_import_dynamic purego_pthread_detach pthread_detach "libpthread.so.0"

View File

@@ -0,0 +1,30 @@
// Code generated by 'go generate' with gen.go. DO NOT EDIT.
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build !cgo
package fakecgo
//go:cgo_import_dynamic purego_malloc malloc "libc.so"
//go:cgo_import_dynamic purego_free free "libc.so"
//go:cgo_import_dynamic purego_setenv setenv "libc.so"
//go:cgo_import_dynamic purego_unsetenv unsetenv "libc.so"
//go:cgo_import_dynamic purego_sigfillset sigfillset "libc.so"
//go:cgo_import_dynamic purego_nanosleep nanosleep "libc.so"
//go:cgo_import_dynamic purego_abort abort "libc.so"
//go:cgo_import_dynamic purego_sigaltstack sigaltstack "libc.so"
//go:cgo_import_dynamic purego_pthread_attr_init pthread_attr_init "libpthread.so"
//go:cgo_import_dynamic purego_pthread_create pthread_create "libpthread.so"
//go:cgo_import_dynamic purego_pthread_detach pthread_detach "libpthread.so"
//go:cgo_import_dynamic purego_pthread_sigmask pthread_sigmask "libpthread.so"
//go:cgo_import_dynamic purego_pthread_self pthread_self "libpthread.so"
//go:cgo_import_dynamic purego_pthread_get_stacksize_np pthread_get_stacksize_np "libpthread.so"
//go:cgo_import_dynamic purego_pthread_attr_getstacksize pthread_attr_getstacksize "libpthread.so"
//go:cgo_import_dynamic purego_pthread_attr_setstacksize pthread_attr_setstacksize "libpthread.so"
//go:cgo_import_dynamic purego_pthread_attr_destroy pthread_attr_destroy "libpthread.so"
//go:cgo_import_dynamic purego_pthread_mutex_lock pthread_mutex_lock "libpthread.so"
//go:cgo_import_dynamic purego_pthread_mutex_unlock pthread_mutex_unlock "libpthread.so"
//go:cgo_import_dynamic purego_pthread_cond_broadcast pthread_cond_broadcast "libpthread.so"
//go:cgo_import_dynamic purego_pthread_setspecific pthread_setspecific "libpthread.so"

View File

@@ -0,0 +1,71 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
//go:build !cgo && linux
#include "textflag.h"
#include "go_asm.h"
// these trampolines map the gcc ABI to Go ABI and then calls into the Go equivalent functions.
TEXT x_cgo_init_trampoline(SB), NOSPLIT, $16
MOVV R4, 8(R3)
MOVV R5, 16(R3)
MOVV ·x_cgo_init_call(SB), R6
MOVV (R6), R7
CALL (R7)
RET
TEXT x_cgo_thread_start_trampoline(SB), NOSPLIT, $8
MOVV R4, 8(R3)
MOVV ·x_cgo_thread_start_call(SB), R5
MOVV (R5), R6
CALL (R6)
RET
TEXT x_cgo_setenv_trampoline(SB), NOSPLIT, $8
MOVV R4, 8(R3)
MOVV ·x_cgo_setenv_call(SB), R5
MOVV (R5), R6
CALL (R6)
RET
TEXT x_cgo_unsetenv_trampoline(SB), NOSPLIT, $8
MOVV R4, 8(R3)
MOVV ·x_cgo_unsetenv_call(SB), R5
MOVV (R5), R6
CALL (R6)
RET
TEXT x_cgo_notify_runtime_init_done_trampoline(SB), NOSPLIT, $0
CALL ·x_cgo_notify_runtime_init_done(SB)
RET
TEXT x_cgo_bindm_trampoline(SB), NOSPLIT, $0
CALL ·x_cgo_bindm(SB)
RET
// func setg_trampoline(setg uintptr, g uintptr)
TEXT ·setg_trampoline(SB), NOSPLIT, $0
MOVV G+8(FP), R4
MOVV setg+0(FP), R5
CALL (R5)
RET
TEXT threadentry_trampoline(SB), NOSPLIT, $16
MOVV R4, 8(R3)
MOVV ·threadentry_call(SB), R5
MOVV (R5), R6
CALL (R6)
RET
TEXT ·call5(SB), NOSPLIT, $0-0
MOVV fn+0(FP), R9
MOVV a1+8(FP), R4
MOVV a2+16(FP), R5
MOVV a3+24(FP), R6
MOVV a4+32(FP), R7
MOVV a5+40(FP), R8
CALL (R9)
MOVV R4, ret+48(FP)
RET

View File

@@ -3,7 +3,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build !cgo && (darwin || freebsd || linux) //go:build !cgo && (darwin || freebsd || linux || netbsd)
#include "textflag.h" #include "textflag.h"
@@ -37,6 +37,10 @@ TEXT _abort(SB), NOSPLIT|NOFRAME, $0-0
JMP purego_abort(SB) JMP purego_abort(SB)
RET RET
TEXT _sigaltstack(SB), NOSPLIT|NOFRAME, $0-0
JMP purego_sigaltstack(SB)
RET
TEXT _pthread_attr_init(SB), NOSPLIT|NOFRAME, $0-0 TEXT _pthread_attr_init(SB), NOSPLIT|NOFRAME, $0-0
JMP purego_pthread_attr_init(SB) JMP purego_pthread_attr_init(SB)
RET RET

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build !cgo && (darwin || freebsd || linux) //go:build !cgo && (darwin || freebsd || linux || netbsd)
package purego package purego

View File

@@ -85,7 +85,7 @@ const (
_MEMORY = 0b1111 _MEMORY = 0b1111
) )
func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFloat, addStack func(uintptr), keepAlive []interface{}) []interface{} { func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFloat, addStack func(uintptr), keepAlive []any) []any {
if v.Type().Size() == 0 { if v.Type().Size() == 0 {
return keepAlive return keepAlive
} }
@@ -120,7 +120,7 @@ func postMerger(t reflect.Type) (passInMemory bool) {
if t.Size() <= 2*8 { if t.Size() <= 2*8 {
return false return false
} }
return true // Go does not have an SSE/SEEUP type so this is always true return true // Go does not have an SSE/SSEUP type so this is always true
} }
func tryPlaceRegister(v reflect.Value, addFloat func(uintptr), addInt func(uintptr)) (ok bool) { func tryPlaceRegister(v reflect.Value, addFloat func(uintptr), addInt func(uintptr)) (ok bool) {
@@ -200,7 +200,7 @@ func tryPlaceRegister(v reflect.Value, addFloat func(uintptr), addInt func(uintp
val |= f.Uint() << shift val |= f.Uint() << shift
shift += 32 shift += 32
class |= _INTEGER class |= _INTEGER
case reflect.Uint64, reflect.Uint: case reflect.Uint64, reflect.Uint, reflect.Uintptr:
val = f.Uint() val = f.Uint()
shift = 64 shift = 64
class = _INTEGER class = _INTEGER
@@ -245,7 +245,7 @@ func placeStack(v reflect.Value, addStack func(uintptr)) {
addStack(f.Pointer()) addStack(f.Pointer())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
addStack(uintptr(f.Int())) addStack(uintptr(f.Int()))
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
addStack(uintptr(f.Uint())) addStack(uintptr(f.Uint()))
case reflect.Float32: case reflect.Float32:
addStack(uintptr(math.Float32bits(float32(f.Float())))) addStack(uintptr(math.Float32bits(float32(f.Float()))))
@@ -258,3 +258,7 @@ func placeStack(v reflect.Value, addStack func(uintptr)) {
} }
} }
} }
func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr)) {
panic("purego: not needed on amd64")
}

View File

@@ -65,7 +65,7 @@ const (
_INT = 0b11 _INT = 0b11
) )
func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFloat, addStack func(uintptr), keepAlive []interface{}) []interface{} { func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFloat, addStack func(uintptr), keepAlive []any) []any {
if v.Type().Size() == 0 { if v.Type().Size() == 0 {
return keepAlive return keepAlive
} }
@@ -73,8 +73,8 @@ func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFl
if hva, hfa, size := isHVA(v.Type()), isHFA(v.Type()), v.Type().Size(); hva || hfa || size <= 16 { if hva, hfa, size := isHVA(v.Type()), isHFA(v.Type()), v.Type().Size(); hva || hfa || size <= 16 {
// if this doesn't fit entirely in registers then // if this doesn't fit entirely in registers then
// each element goes onto the stack // each element goes onto the stack
if hfa && *numFloats+v.NumField() > numOfFloats { if hfa && *numFloats+v.NumField() > numOfFloatRegisters {
*numFloats = numOfFloats *numFloats = numOfFloatRegisters
} else if hva && *numInts+v.NumField() > numOfIntegerRegisters() { } else if hva && *numInts+v.NumField() > numOfIntegerRegisters() {
*numInts = numOfIntegerRegisters() *numInts = numOfIntegerRegisters()
} }
@@ -107,6 +107,8 @@ func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr
} else { } else {
f = v.Index(k) f = v.Index(k)
} }
align := byte(f.Type().Align()*8 - 1)
shift = (shift + align) &^ align
if shift >= 64 { if shift >= 64 {
shift = 0 shift = 0
flushed = true flushed = true
@@ -137,10 +139,11 @@ func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr
val |= f.Uint() << shift val |= f.Uint() << shift
shift += 32 shift += 32
class |= _INT class |= _INT
case reflect.Uint64: case reflect.Uint64, reflect.Uint, reflect.Uintptr:
addInt(uintptr(f.Uint())) addInt(uintptr(f.Uint()))
shift = 0 shift = 0
flushed = true flushed = true
class = _NO_CLASS
case reflect.Int8: case reflect.Int8:
val |= uint64(f.Int()&0xFF) << shift val |= uint64(f.Int()&0xFF) << shift
shift += 8 shift += 8
@@ -153,10 +156,11 @@ func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr
val |= uint64(f.Int()&0xFFFF_FFFF) << shift val |= uint64(f.Int()&0xFFFF_FFFF) << shift
shift += 32 shift += 32
class |= _INT class |= _INT
case reflect.Int64: case reflect.Int64, reflect.Int:
addInt(uintptr(f.Int())) addInt(uintptr(f.Int()))
shift = 0 shift = 0
flushed = true flushed = true
class = _NO_CLASS
case reflect.Float32: case reflect.Float32:
if class == _FLOAT { if class == _FLOAT {
addFloat(uintptr(val)) addFloat(uintptr(val))
@@ -170,6 +174,12 @@ func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr
addFloat(uintptr(math.Float64bits(float64(f.Float())))) addFloat(uintptr(math.Float64bits(float64(f.Float()))))
shift = 0 shift = 0
flushed = true flushed = true
class = _NO_CLASS
case reflect.Ptr:
addInt(f.Pointer())
shift = 0
flushed = true
class = _NO_CLASS
case reflect.Array: case reflect.Array:
place(f) place(f)
default: default:
@@ -187,7 +197,7 @@ func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr
} }
} }
func placeStack(v reflect.Value, keepAlive []interface{}, addInt func(uintptr)) []interface{} { func placeStack(v reflect.Value, keepAlive []any, addInt func(uintptr)) []any {
// Struct is too big to be placed in registers. // Struct is too big to be placed in registers.
// Copy to heap and place the pointer in register // Copy to heap and place the pointer in register
ptrStruct := reflect.New(v.Type()) ptrStruct := reflect.New(v.Type())

190
vendor/github.com/ebitengine/purego/struct_loong64.go generated vendored Normal file
View File

@@ -0,0 +1,190 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
package purego
import (
"math"
"reflect"
"unsafe"
)
func getStruct(outType reflect.Type, syscall syscall15Args) (v reflect.Value) {
outSize := outType.Size()
switch {
case outSize == 0:
return reflect.New(outType).Elem()
case outSize <= 8:
r1 := syscall.a1
if isAllFloats, numFields := isAllSameFloat(outType); isAllFloats {
r1 = syscall.f1
if numFields == 2 {
r1 = syscall.f2<<32 | syscall.f1
}
}
return reflect.NewAt(outType, unsafe.Pointer(&struct{ a uintptr }{r1})).Elem()
case outSize <= 16:
r1, r2 := syscall.a1, syscall.a2
if isAllFloats, numFields := isAllSameFloat(outType); isAllFloats {
switch numFields {
case 4:
r1 = syscall.f2<<32 | syscall.f1
r2 = syscall.f4<<32 | syscall.f3
case 3:
r1 = syscall.f2<<32 | syscall.f1
r2 = syscall.f3
case 2:
r1 = syscall.f1
r2 = syscall.f2
default:
panic("unreachable")
}
}
return reflect.NewAt(outType, unsafe.Pointer(&struct{ a, b uintptr }{r1, r2})).Elem()
default:
// create struct from the Go pointer created above
// weird pointer dereference to circumvent go vet
return reflect.NewAt(outType, *(*unsafe.Pointer)(unsafe.Pointer(&syscall.a1))).Elem()
}
}
const (
_NO_CLASS = 0b00
_FLOAT = 0b01
_INT = 0b11
)
func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFloat, addStack func(uintptr), keepAlive []any) []any {
if v.Type().Size() == 0 {
return keepAlive
}
if size := v.Type().Size(); size <= 16 {
placeRegisters(v, addFloat, addInt)
} else {
keepAlive = placeStack(v, keepAlive, addInt)
}
return keepAlive // the struct was allocated so don't panic
}
func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr)) {
var val uint64
var shift byte
var flushed bool
class := _NO_CLASS
var place func(v reflect.Value)
place = func(v reflect.Value) {
var numFields int
if v.Kind() == reflect.Struct {
numFields = v.Type().NumField()
} else {
numFields = v.Type().Len()
}
for k := 0; k < numFields; k++ {
flushed = false
var f reflect.Value
if v.Kind() == reflect.Struct {
f = v.Field(k)
} else {
f = v.Index(k)
}
align := byte(f.Type().Align()*8 - 1)
shift = (shift + align) &^ align
if shift >= 64 {
shift = 0
flushed = true
if class == _FLOAT {
addFloat(uintptr(val))
} else {
addInt(uintptr(val))
}
}
switch f.Type().Kind() {
case reflect.Struct:
place(f)
case reflect.Bool:
if f.Bool() {
val |= 1
}
shift += 8
class |= _INT
case reflect.Uint8:
val |= f.Uint() << shift
shift += 8
class |= _INT
case reflect.Uint16:
val |= f.Uint() << shift
shift += 16
class |= _INT
case reflect.Uint32:
val |= f.Uint() << shift
shift += 32
class |= _INT
case reflect.Uint64, reflect.Uint, reflect.Uintptr:
addInt(uintptr(f.Uint()))
shift = 0
flushed = true
class = _NO_CLASS
case reflect.Int8:
val |= uint64(f.Int()&0xFF) << shift
shift += 8
class |= _INT
case reflect.Int16:
val |= uint64(f.Int()&0xFFFF) << shift
shift += 16
class |= _INT
case reflect.Int32:
val |= uint64(f.Int()&0xFFFF_FFFF) << shift
shift += 32
class |= _INT
case reflect.Int64, reflect.Int:
addInt(uintptr(f.Int()))
shift = 0
flushed = true
class = _NO_CLASS
case reflect.Float32:
if class == _FLOAT {
addFloat(uintptr(val))
val = 0
shift = 0
}
val |= uint64(math.Float32bits(float32(f.Float()))) << shift
shift += 32
class |= _FLOAT
case reflect.Float64:
addFloat(uintptr(math.Float64bits(float64(f.Float()))))
shift = 0
flushed = true
class = _NO_CLASS
case reflect.Ptr:
addInt(f.Pointer())
shift = 0
flushed = true
class = _NO_CLASS
case reflect.Array:
place(f)
default:
panic("purego: unsupported kind " + f.Kind().String())
}
}
}
place(v)
if !flushed {
if class == _FLOAT {
addFloat(uintptr(val))
} else {
addInt(uintptr(val))
}
}
}
func placeStack(v reflect.Value, keepAlive []any, addInt func(uintptr)) []any {
// Struct is too big to be placed in registers.
// Copy to heap and place the pointer in register
ptrStruct := reflect.New(v.Type())
ptrStruct.Elem().Set(v)
ptr := ptrStruct.Elem().Addr().UnsafePointer()
keepAlive = append(keepAlive, ptr)
addInt(uintptr(ptr))
return keepAlive
}

View File

@@ -1,16 +1,20 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2024 The Ebitengine Authors // SPDX-FileCopyrightText: 2024 The Ebitengine Authors
//go:build !amd64 && !arm64 //go:build !amd64 && !arm64 && !loong64
package purego package purego
import "reflect" import "reflect"
func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFloat, addStack func(uintptr), keepAlive []interface{}) []interface{} { func addStruct(v reflect.Value, numInts, numFloats, numStack *int, addInt, addFloat, addStack func(uintptr), keepAlive []any) []any {
panic("purego: struct arguments are not supported") panic("purego: struct arguments are not supported")
} }
func getStruct(outType reflect.Type, syscall syscall15Args) (v reflect.Value) { func getStruct(outType reflect.Type, syscall syscall15Args) (v reflect.Value) {
panic("purego: struct returns are not supported") panic("purego: struct returns are not supported")
} }
func placeRegisters(v reflect.Value, addFloat func(uintptr), addInt func(uintptr)) {
panic("purego: not needed on other platforms")
}

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build darwin || freebsd || linux //go:build darwin || freebsd || linux || netbsd
#include "textflag.h" #include "textflag.h"
#include "abi_amd64.h" #include "abi_amd64.h"

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build darwin || freebsd || linux || windows //go:build darwin || freebsd || linux || netbsd || windows
#include "textflag.h" #include "textflag.h"
#include "go_asm.h" #include "go_asm.h"

96
vendor/github.com/ebitengine/purego/sys_loong64.s generated vendored Normal file
View File

@@ -0,0 +1,96 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
//go:build linux
#include "textflag.h"
#include "go_asm.h"
#include "funcdata.h"
#define STACK_SIZE 64
#define PTR_ADDRESS (STACK_SIZE - 8)
// syscall15X calls a function in libc on behalf of the syscall package.
// syscall15X takes a pointer to a struct like:
// struct {
// fn uintptr
// a1 uintptr
// a2 uintptr
// a3 uintptr
// a4 uintptr
// a5 uintptr
// a6 uintptr
// a7 uintptr
// a8 uintptr
// a9 uintptr
// a10 uintptr
// a11 uintptr
// a12 uintptr
// a13 uintptr
// a14 uintptr
// a15 uintptr
// r1 uintptr
// r2 uintptr
// err uintptr
// }
// syscall15X must be called on the g0 stack with the
// C calling convention (use libcCall).
GLOBL ·syscall15XABI0(SB), NOPTR|RODATA, $8
DATA ·syscall15XABI0(SB)/8, $syscall15X(SB)
TEXT syscall15X(SB), NOSPLIT, $0
// push structure pointer
SUBV $STACK_SIZE, R3
MOVV R4, PTR_ADDRESS(R3)
MOVV R4, R13
MOVD syscall15Args_f1(R13), F0 // f1
MOVD syscall15Args_f2(R13), F1 // f2
MOVD syscall15Args_f3(R13), F2 // f3
MOVD syscall15Args_f4(R13), F3 // f4
MOVD syscall15Args_f5(R13), F4 // f5
MOVD syscall15Args_f6(R13), F5 // f6
MOVD syscall15Args_f7(R13), F6 // f7
MOVD syscall15Args_f8(R13), F7 // f8
MOVV syscall15Args_a1(R13), R4 // a1
MOVV syscall15Args_a2(R13), R5 // a2
MOVV syscall15Args_a3(R13), R6 // a3
MOVV syscall15Args_a4(R13), R7 // a4
MOVV syscall15Args_a5(R13), R8 // a5
MOVV syscall15Args_a6(R13), R9 // a6
MOVV syscall15Args_a7(R13), R10 // a7
MOVV syscall15Args_a8(R13), R11 // a8
// push a9-a15 onto stack
MOVV syscall15Args_a9(R13), R12
MOVV R12, 0(R3)
MOVV syscall15Args_a10(R13), R12
MOVV R12, 8(R3)
MOVV syscall15Args_a11(R13), R12
MOVV R12, 16(R3)
MOVV syscall15Args_a12(R13), R12
MOVV R12, 24(R3)
MOVV syscall15Args_a13(R13), R12
MOVV R12, 32(R3)
MOVV syscall15Args_a14(R13), R12
MOVV R12, 40(R3)
MOVV syscall15Args_a15(R13), R12
MOVV R12, 48(R3)
MOVV syscall15Args_fn(R13), R12
JAL (R12)
// pop structure pointer
MOVV PTR_ADDRESS(R3), R13
ADDV $STACK_SIZE, R3
// save R4, R5
MOVV R4, syscall15Args_a1(R13)
MOVV R5, syscall15Args_a2(R13)
// save f0-f3
MOVD F0, syscall15Args_f1(R13)
MOVD F1, syscall15Args_f2(R13)
MOVD F2, syscall15Args_f3(R13)
MOVD F3, syscall15Args_f4(R13)
RET

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2023 The Ebitengine Authors // SPDX-FileCopyrightText: 2023 The Ebitengine Authors
//go:build darwin || freebsd || linux //go:build darwin || freebsd || linux || netbsd
#include "textflag.h" #include "textflag.h"
#include "go_asm.h" #include "go_asm.h"

75
vendor/github.com/ebitengine/purego/sys_unix_loong64.s generated vendored Normal file
View File

@@ -0,0 +1,75 @@
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2025 The Ebitengine Authors
//go:build linux
#include "textflag.h"
#include "go_asm.h"
#include "funcdata.h"
#include "abi_loong64.h"
TEXT callbackasm1(SB), NOSPLIT|NOFRAME, $0
NO_LOCAL_POINTERS
SUBV $(16*8), R3, R14
MOVD F0, 0(R14)
MOVD F1, 8(R14)
MOVD F2, 16(R14)
MOVD F3, 24(R14)
MOVD F4, 32(R14)
MOVD F5, 40(R14)
MOVD F6, 48(R14)
MOVD F7, 56(R14)
MOVV R4, 64(R14)
MOVV R5, 72(R14)
MOVV R6, 80(R14)
MOVV R7, 88(R14)
MOVV R8, 96(R14)
MOVV R9, 104(R14)
MOVV R10, 112(R14)
MOVV R11, 120(R14)
// Adjust SP by frame size.
SUBV $(22*8), R3
// It is important to save R30 because the go assembler
// uses it for move instructions for a variable.
// This line:
// MOVV ·callbackWrap_call(SB), R4
// Creates the instructions:
// PCALAU12I off1(PC), R30
// MOVV off2(R30), R4
// R30 is a callee saved register so we are responsible
// for ensuring its value doesn't change. So save it and
// restore it at the end of this function.
// R1 is the link register. crosscall2 doesn't save it
// so it's saved here.
MOVV R1, 0(R3)
MOVV R30, 8(R3)
// Create a struct callbackArgs on our stack.
MOVV $(callbackArgs__size)(R3), R13
MOVV R12, callbackArgs_index(R13) // callback index
MOVV R14, callbackArgs_args(R13) // address of args vector
MOVV $0, callbackArgs_result(R13) // result
// Move parameters into registers
// Get the ABIInternal function pointer
// without <ABIInternal> by using a closure.
MOVV ·callbackWrap_call(SB), R4
MOVV (R4), R4 // fn unsafe.Pointer
MOVV R13, R5 // frame (&callbackArgs{...})
MOVV $0, R7 // ctxt uintptr
JAL crosscall2(SB)
// Get callback result.
MOVV $(callbackArgs__size)(R3), R13
MOVV callbackArgs_result(R13), R4
// Restore LR and R30
MOVV 0(R3), R1
MOVV 8(R3), R30
ADDV $(22*8), R3
RET

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build darwin || freebsd || linux || windows //go:build darwin || freebsd || linux || netbsd || windows
package purego package purego
@@ -13,8 +13,8 @@ package purego
type CDecl struct{} type CDecl struct{}
const ( const (
maxArgs = 15 maxArgs = 15
numOfFloats = 8 // arm64 and amd64 both have 8 float registers numOfFloatRegisters = 8 // arm64 and amd64 both have 8 float registers
) )
type syscall15Args struct { type syscall15Args struct {
@@ -27,6 +27,9 @@ type syscall15Args struct {
// There is an internal maximum number of arguments that SyscallN can take. It panics // There is an internal maximum number of arguments that SyscallN can take. It panics
// when the maximum is exceeded. It returns the result and the libc error code if there is one. // when the maximum is exceeded. It returns the result and the libc error code if there is one.
// //
// In order to call this function properly make sure to follow all the rules specified in [unsafe.Pointer]
// especially point 4.
//
// NOTE: SyscallN does not properly call functions that have both integer and float parameters. // NOTE: SyscallN does not properly call functions that have both integer and float parameters.
// See discussion comment https://github.com/ebiten/purego/pull/1#issuecomment-1128057607 // See discussion comment https://github.com/ebiten/purego/pull/1#issuecomment-1128057607
// for an explanation of why that is. // for an explanation of why that is.

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build cgo && !(amd64 || arm64) //go:build cgo && !(amd64 || arm64 || loong64)
package purego package purego
@@ -16,6 +16,6 @@ func syscall_syscall15X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a
return cgo.Syscall15X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) return cgo.Syscall15X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15)
} }
func NewCallback(_ interface{}) uintptr { func NewCallback(_ any) uintptr {
panic("purego: NewCallback on Linux is only supported on amd64/arm64") panic("purego: NewCallback on Linux is only supported on amd64/arm64/loong64")
} }

View File

@@ -1,7 +1,7 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2022 The Ebitengine Authors // SPDX-FileCopyrightText: 2022 The Ebitengine Authors
//go:build darwin || freebsd || (linux && (amd64 || arm64)) //go:build darwin || freebsd || (linux && (amd64 || arm64 || loong64)) || netbsd
package purego package purego
@@ -14,14 +14,17 @@ import (
var syscall15XABI0 uintptr var syscall15XABI0 uintptr
//go:nosplit
func syscall_syscall15X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2, err uintptr) { func syscall_syscall15X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2, err uintptr) {
args := syscall15Args{ args := thePool.Get().(*syscall15Args)
defer thePool.Put(args)
*args = syscall15Args{
fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15,
a1, a2, a3, a4, a5, a6, a7, a8, a1, a2, a3, a4, a5, a6, a7, a8,
0, 0,
} }
runtime_cgocall(syscall15XABI0, unsafe.Pointer(&args))
runtime_cgocall(syscall15XABI0, unsafe.Pointer(args))
return args.a1, args.a2, 0 return args.a1, args.a2, 0
} }
@@ -31,7 +34,7 @@ func syscall_syscall15X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a
// of uintptr. Only a limited number of callbacks may be created in a single Go process, and any memory allocated // of uintptr. Only a limited number of callbacks may be created in a single Go process, and any memory allocated
// for these callbacks is never released. At least 2000 callbacks can always be created. Although this function // for these callbacks is never released. At least 2000 callbacks can always be created. Although this function
// provides similar functionality to windows.NewCallback it is distinct. // provides similar functionality to windows.NewCallback it is distinct.
func NewCallback(fn interface{}) uintptr { func NewCallback(fn any) uintptr {
ty := reflect.TypeOf(fn) ty := reflect.TypeOf(fn)
for i := 0; i < ty.NumIn(); i++ { for i := 0; i < ty.NumIn(); i++ {
in := ty.In(i) in := ty.In(i)
@@ -71,7 +74,7 @@ type callbackArgs struct {
result uintptr result uintptr
} }
func compileCallback(fn interface{}) uintptr { func compileCallback(fn any) uintptr {
val := reflect.ValueOf(fn) val := reflect.ValueOf(fn)
if val.Kind() != reflect.Func { if val.Kind() != reflect.Func {
panic("purego: the type must be a function but was not") panic("purego: the type must be a function but was not")
@@ -146,12 +149,12 @@ func callbackWrap(a *callbackArgs) {
var intsN int // intsN represents the number of integer arguments processed var intsN int // intsN represents the number of integer arguments processed
// stack points to the index into frame of the current stack element. // stack points to the index into frame of the current stack element.
// The stack begins after the float and integer registers. // The stack begins after the float and integer registers.
stack := numOfIntegerRegisters() + numOfFloats stack := numOfIntegerRegisters() + numOfFloatRegisters
for i := range args { for i := range args {
var pos int var pos int
switch fnType.In(i).Kind() { switch fnType.In(i).Kind() {
case reflect.Float32, reflect.Float64: case reflect.Float32, reflect.Float64:
if floatsN >= numOfFloats { if floatsN >= numOfFloatRegisters {
pos = stack pos = stack
stack++ stack++
} else { } else {
@@ -169,7 +172,7 @@ func callbackWrap(a *callbackArgs) {
stack++ stack++
} else { } else {
// the integers begin after the floats in frame // the integers begin after the floats in frame
pos = intsN + numOfFloats pos = intsN + numOfFloatRegisters
} }
intsN++ intsN++
} }
@@ -214,7 +217,7 @@ func callbackasmAddr(i int) uintptr {
panic("purego: unsupported architecture") panic("purego: unsupported architecture")
case "386", "amd64": case "386", "amd64":
entrySize = 5 entrySize = 5
case "arm", "arm64": case "arm", "arm64", "loong64":
// On ARM and ARM64, each entry is a MOV instruction // On ARM and ARM64, each entry is a MOV instruction
// followed by a branch instruction // followed by a branch instruction
entrySize = 8 entrySize = 8

View File

@@ -22,7 +22,7 @@ func syscall_syscall15X(fn, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a
// allocated for these callbacks is never released. Between NewCallback and NewCallbackCDecl, at least 1024 // allocated for these callbacks is never released. Between NewCallback and NewCallbackCDecl, at least 1024
// callbacks can always be created. Although this function is similiar to the darwin version it may act // callbacks can always be created. Although this function is similiar to the darwin version it may act
// differently. // differently.
func NewCallback(fn interface{}) uintptr { func NewCallback(fn any) uintptr {
isCDecl := false isCDecl := false
ty := reflect.TypeOf(fn) ty := reflect.TypeOf(fn)
for i := 0; i < ty.NumIn(); i++ { for i := 0; i < ty.NumIn(); i++ {

View File

File diff suppressed because it is too large Load Diff

View File

File diff suppressed because it is too large Load Diff

4014
vendor/github.com/ebitengine/purego/zcallback_loong64.s generated vendored Normal file
View File

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,9 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"math/bits"
"strconv" "strconv"
"syscall"
"unsafe" "unsafe"
"github.com/yusufpapurcu/wmi" "github.com/yusufpapurcu/wmi"
@@ -19,6 +21,8 @@ import (
var ( var (
procGetNativeSystemInfo = common.Modkernel32.NewProc("GetNativeSystemInfo") procGetNativeSystemInfo = common.Modkernel32.NewProc("GetNativeSystemInfo")
procGetLogicalProcessorInformationEx = common.Modkernel32.NewProc("GetLogicalProcessorInformationEx") procGetLogicalProcessorInformationEx = common.Modkernel32.NewProc("GetLogicalProcessorInformationEx")
procGetSystemFirmwareTable = common.Modkernel32.NewProc("GetSystemFirmwareTable")
procCallNtPowerInformation = common.ModPowrProf.NewProc("CallNtPowerInformation")
) )
type win32_Processor struct { //nolint:revive //FIXME type win32_Processor struct { //nolint:revive //FIXME
@@ -46,6 +50,16 @@ type win32_SystemProcessorPerformanceInformation struct { //nolint:revive //FIXM
InterruptCount uint64 // ULONG needs to be uint64 InterruptCount uint64 // ULONG needs to be uint64
} }
// https://learn.microsoft.com/en-us/windows/win32/power/processor-power-information-str
type processorPowerInformation struct {
number uint32 // http://download.microsoft.com/download/a/d/f/adf1347d-08dc-41a4-9084-623b1194d4b2/MoreThan64proc.docx
maxMhz uint32
currentMhz uint32
mhzLimit uint32
maxIdleState uint32
currentIdleState uint32
}
const ( const (
ClocksPerSec = 10000000.0 ClocksPerSec = 10000000.0
@@ -55,6 +69,28 @@ const (
// size of systemProcessorPerformanceInfoSize in memory // size of systemProcessorPerformanceInfoSize in memory
win32_SystemProcessorPerformanceInfoSize = uint32(unsafe.Sizeof(win32_SystemProcessorPerformanceInformation{})) //nolint:revive //FIXME win32_SystemProcessorPerformanceInfoSize = uint32(unsafe.Sizeof(win32_SystemProcessorPerformanceInformation{})) //nolint:revive //FIXME
firmwareTableProviderSignatureRSMB = 0x52534d42 // "RSMB" https://gitlab.winehq.org/dreamer/wine/-/blame/wine-7.0-rc6/dlls/ntdll/unix/system.c#L230
smBiosHeaderSize = 8 // SMBIOS header size
smbiosEndOfTable = 127 // Minimum length for processor structure
smbiosTypeProcessor = 4 // SMBIOS Type 4: Processor Information
smbiosProcessorMinLength = 0x18 // Minimum length for processor structure
)
type relationship uint32
// https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getlogicalprocessorinformationex
const (
relationProcessorCore = relationship(0)
relationProcessorPackage = relationship(3)
)
const (
kAffinitySize = unsafe.Sizeof(int(0))
// https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/interrupt-affinity-and-priority
maxLogicalProcessorsPerGroup = uint32(unsafe.Sizeof(kAffinitySize * 8))
// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ne-wdm-power_information_level
processorInformation = 11
) )
// Times returns times stat per cpu and combined for all CPUs // Times returns times stat per cpu and combined for all CPUs
@@ -101,6 +137,46 @@ func Info() ([]InfoStat, error) {
return InfoWithContext(context.Background()) return InfoWithContext(context.Background())
} }
// this function iterates over each set bit in the package affinity mask, each bit represent a logical processor in a group (assuming you are iteriang over a package mask)
// the function is used also to compute the global logical processor number
// https://learn.microsoft.com/en-us/windows/win32/procthread/processor-groups
// see https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-group_affinity
// and https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-processor_relationship
// and https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-system_logical_processor_information_ex
func forEachSetBit64(mask uint64, fn func(bit int)) {
m := mask
for m != 0 {
b := bits.TrailingZeros64(m)
fn(b)
m &= m - 1
}
}
func getProcessorPowerInformation(ctx context.Context) ([]processorPowerInformation, error) {
numLP, countErr := CountsWithContext(ctx, true)
if countErr != nil {
return nil, fmt.Errorf("failed to get logical processor count: %w", countErr)
}
if numLP <= 0 {
return nil, fmt.Errorf("invalid logical processor count: %d", numLP)
}
ppiSize := uintptr(numLP) * unsafe.Sizeof(processorPowerInformation{})
buf := make([]byte, ppiSize)
ppi, _, err := procCallNtPowerInformation.Call(
uintptr(processorInformation),
0,
0,
uintptr(unsafe.Pointer(&buf[0])),
uintptr(ppiSize),
)
if ppi != 0 {
return nil, fmt.Errorf("CallNtPowerInformation failed with code %d: %w", ppi, err)
}
ppis := unsafe.Slice((*processorPowerInformation)(unsafe.Pointer(&buf[0])), numLP)
return ppis, nil
}
func InfoWithContext(ctx context.Context) ([]InfoStat, error) { func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
var ret []InfoStat var ret []InfoStat
var dst []win32_Processor var dst []win32_Processor
@@ -121,7 +197,7 @@ func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
Family: strconv.FormatUint(uint64(l.Family), 10), Family: strconv.FormatUint(uint64(l.Family), 10),
VendorID: l.Manufacturer, VendorID: l.Manufacturer,
ModelName: l.Name, ModelName: l.Name,
Cores: int32(l.NumberOfLogicalProcessors), Cores: int32(l.NumberOfLogicalProcessors), // TO BE REMOVED, set by getSystemLogicalProcessorInformationEx
PhysicalID: procID, PhysicalID: procID,
Mhz: float64(l.MaxClockSpeed), Mhz: float64(l.MaxClockSpeed),
Flags: []string{}, Flags: []string{},
@@ -129,6 +205,55 @@ func InfoWithContext(ctx context.Context) ([]InfoStat, error) {
ret = append(ret, cpu) ret = append(ret, cpu)
} }
processorPackages, err := getSystemLogicalProcessorInformationEx(relationProcessorPackage)
if err != nil {
// return an error whem wmi will be removed
// return ret, fmt.Errorf("failed to get processor package information: %w", err)
return ret, nil
}
if len(processorPackages) != len(ret) {
// this should never happen, but it's kept for safety until wmi is removed
return ret, nil
}
ppis, powerInformationErr := getProcessorPowerInformation(ctx)
if powerInformationErr != nil {
// return an error whem wmi will be removed
// return ret, fmt.Errorf("failed to get processor power information: %w", err)
return ret, nil
}
family, processorId, smBIOSErr := getSMBIOSProcessorInfo()
if smBIOSErr != nil {
// return an error whem wmi will be removed
// return ret, smBIOSErr
return ret, nil
}
for i, pkg := range processorPackages {
logicalCount := 0
maxMhz := 0
for _, ga := range pkg.processor.groupMask {
g := int(ga.group)
forEachSetBit64(uint64(ga.mask), func(bit int) {
// the global logical processor label
globalLpl := g*int(maxLogicalProcessorsPerGroup) + bit
if globalLpl >= 0 && globalLpl < len(ppis) {
logicalCount++
m := int(ppis[globalLpl].maxMhz)
if m > maxMhz {
maxMhz = m
}
}
})
}
ret[i].Mhz = float64(maxMhz)
ret[i].Cores = int32(logicalCount)
ret[i].Family = strconv.FormatUint(uint64(family), 10)
ret[i].PhysicalID = processorId
}
return ret, nil return ret, nil
} }
@@ -207,7 +332,7 @@ type systemInfo struct {
} }
type groupAffinity struct { type groupAffinity struct {
mask uintptr // https://learn.microsoft.com/it-it/windows-hardware/drivers/kernel/interrupt-affinity-and-priority#about-kaffinity mask uintptr // https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/interrupt-affinity-and-priority#about-kaffinity
group uint16 group uint16
reserved [3]uint16 reserved [3]uint16
} }
@@ -223,43 +348,117 @@ type processorRelationship struct {
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-system_logical_processor_information_ex // https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-system_logical_processor_information_ex
type systemLogicalProcessorInformationEx struct { type systemLogicalProcessorInformationEx struct {
Relationship uint32 relationship uint32
Size uint32 size uint32
Processor processorRelationship processor processorRelationship
} }
func getPhysicalCoreCount() (int, error) { // getSMBIOSProcessorInfo reads the SMBIOS Type 4 (Processor Information) structure and returns the Processor Family and ProcessorId fields.
var length uint32 // If not found, returns 0 and an empty string.
const relationAll = 0xffff func getSMBIOSProcessorInfo() (family uint8, processorId string, err error) {
const relationProcessorCore = 0x0 // https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemfirmwaretable
size, _, err := procGetSystemFirmwareTable.Call(
uintptr(firmwareTableProviderSignatureRSMB),
0,
0,
0,
)
if size == 0 {
return 0, "", fmt.Errorf("failed to get SMBIOS table size: %w", err)
}
buf := make([]byte, size)
ret, _, err := procGetSystemFirmwareTable.Call(
uintptr(firmwareTableProviderSignatureRSMB),
0,
uintptr(unsafe.Pointer(&buf[0])),
uintptr(size),
)
if ret == 0 {
return 0, "", fmt.Errorf("failed to read SMBIOS table: %w", err)
}
// https://wiki.osdev.org/System_Management_BIOS
i := smBiosHeaderSize // skip SMBIOS header (first 8 bytes)
maxIterations := len(buf) * 2
iterations := 0
for i < len(buf) && iterations < maxIterations {
iterations++
if i+4 > len(buf) {
break
}
typ := buf[i]
length := buf[i+1]
if typ == smbiosEndOfTable {
break
}
if typ == smbiosTypeProcessor && length >= smbiosProcessorMinLength && i+int(length) <= len(buf) {
// Ensure we have enough bytes for procIdBytes
if i+16 > len(buf) {
break
}
// Get the processor family from byte at offset 6
family = buf[i+6]
// Extract processor ID bytes (8 bytes total) from offsets 8-15
procIdBytes := buf[i+8 : i+16]
// Convert first 4 bytes to 32-bit EAX register value (little endian)
eax := uint32(procIdBytes[0]) | uint32(procIdBytes[1])<<8 | uint32(procIdBytes[2])<<16 | uint32(procIdBytes[3])<<24
// Convert last 4 bytes to 32-bit EDX register value (little endian)
edx := uint32(procIdBytes[4]) | uint32(procIdBytes[5])<<8 | uint32(procIdBytes[6])<<16 | uint32(procIdBytes[7])<<24
// Format processor ID as 16 character hex string (EDX+EAX)
procId := fmt.Sprintf("%08X%08X", edx, eax)
return family, procId, nil
}
// skip to next structure
j := i + int(length)
innerIterations := 0
maxInner := len(buf) // failsafe for inner loop
for j+1 < len(buf) && innerIterations < maxInner {
innerIterations++
if buf[j] == 0 && buf[j+1] == 0 {
j += 2
break
}
j++
}
if innerIterations >= maxInner {
break // malformed buffer, avoid infinite loop
}
i = j
}
return 0, "", fmt.Errorf("SMBIOS processor information not found: %w", syscall.ERROR_NOT_FOUND)
}
func getSystemLogicalProcessorInformationEx(relationship relationship) ([]systemLogicalProcessorInformationEx, error) {
var length uint32
// First call to determine the required buffer size // First call to determine the required buffer size
_, _, err := procGetLogicalProcessorInformationEx.Call(uintptr(relationAll), 0, uintptr(unsafe.Pointer(&length))) _, _, err := procGetLogicalProcessorInformationEx.Call(uintptr(relationship), 0, uintptr(unsafe.Pointer(&length)))
if err != nil && !errors.Is(err, windows.ERROR_INSUFFICIENT_BUFFER) { if err != nil && !errors.Is(err, windows.ERROR_INSUFFICIENT_BUFFER) {
return 0, fmt.Errorf("failed to get buffer size: %w", err) return nil, fmt.Errorf("failed to get buffer size: %w", err)
} }
// Allocate the buffer // Allocate the buffer
buffer := make([]byte, length) buffer := make([]byte, length)
// Second call to retrieve the processor information // Second call to retrieve the processor information
_, _, err = procGetLogicalProcessorInformationEx.Call(uintptr(relationAll), uintptr(unsafe.Pointer(&buffer[0])), uintptr(unsafe.Pointer(&length))) _, _, err = procGetLogicalProcessorInformationEx.Call(uintptr(relationship), uintptr(unsafe.Pointer(&buffer[0])), uintptr(unsafe.Pointer(&length)))
if err != nil && !errors.Is(err, windows.NTE_OP_OK) { if err != nil && !errors.Is(err, windows.NTE_OP_OK) {
return 0, fmt.Errorf("failed to get logical processor information: %w", err) return nil, fmt.Errorf("failed to get logical processor information: %w", err)
} }
// Iterate through the buffer to count physical cores // Convert the byte slice into a slice of systemLogicalProcessorInformationEx structs
offset := uintptr(0) offset := uintptr(0)
ncpus := 0 var infos []systemLogicalProcessorInformationEx
for offset < uintptr(length) { for offset < uintptr(length) {
info := (*systemLogicalProcessorInformationEx)(unsafe.Pointer(uintptr(unsafe.Pointer(&buffer[0])) + offset)) info := (*systemLogicalProcessorInformationEx)(unsafe.Pointer(uintptr(unsafe.Pointer(&buffer[0])) + offset))
if info.Relationship == relationProcessorCore { infos = append(infos, *info)
ncpus++ offset += uintptr(info.size)
}
offset += uintptr(info.Size)
} }
return ncpus, nil return infos, nil
}
func getPhysicalCoreCount() (int, error) {
infos, err := getSystemLogicalProcessorInformationEx(relationProcessorCore)
return len(infos), err
} }
func CountsWithContext(_ context.Context, logical bool) (int, error) { func CountsWithContext(_ context.Context, logical bool) (int, error) {

View File

@@ -23,6 +23,7 @@ import (
"path/filepath" "path/filepath"
"reflect" "reflect"
"runtime" "runtime"
"slices"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@@ -290,22 +291,14 @@ func StringsHas(target []string, src string) bool {
// StringsContains checks the src in any string of the target string slice // StringsContains checks the src in any string of the target string slice
func StringsContains(target []string, src string) bool { func StringsContains(target []string, src string) bool {
for _, t := range target { return slices.ContainsFunc(target, func(s string) bool {
if strings.Contains(t, src) { return strings.Contains(s, src)
return true })
}
}
return false
} }
// IntContains checks the src in any int of the target int slice. // IntContains checks the src in any int of the target int slice.
func IntContains(target []int, src int) bool { func IntContains(target []int, src int) bool {
for _, t := range target { return slices.Contains(target, src)
if src == t {
return true
}
}
return false
} }
// get struct attributes. // get struct attributes.

View File

@@ -69,6 +69,7 @@ var (
ModNt = windows.NewLazySystemDLL("ntdll.dll") ModNt = windows.NewLazySystemDLL("ntdll.dll")
ModPdh = windows.NewLazySystemDLL("pdh.dll") ModPdh = windows.NewLazySystemDLL("pdh.dll")
ModPsapi = windows.NewLazySystemDLL("psapi.dll") ModPsapi = windows.NewLazySystemDLL("psapi.dll")
ModPowrProf = windows.NewLazySystemDLL("powrprof.dll")
ProcGetSystemTimes = Modkernel32.NewProc("GetSystemTimes") ProcGetSystemTimes = Modkernel32.NewProc("GetSystemTimes")
ProcNtQuerySystemInformation = ModNt.NewProc("NtQuerySystemInformation") ProcNtQuerySystemInformation = ModNt.NewProc("NtQuerySystemInformation")

View File

@@ -3,12 +3,23 @@ package common
import "fmt" import "fmt"
const (
maxWarnings = 100 // An arbitrary limit to avoid excessive memory usage, it has no sense to store hundreds of errors
tooManyErrorsMessage = "too many errors reported, next errors were discarded"
numberOfWarningsMessage = "Number of warnings:"
)
type Warnings struct { type Warnings struct {
List []error List []error
Verbose bool tooManyErrors bool
Verbose bool
} }
func (w *Warnings) Add(err error) { func (w *Warnings) Add(err error) {
if len(w.List) >= maxWarnings {
w.tooManyErrors = true
return
}
w.List = append(w.List, err) w.List = append(w.List, err)
} }
@@ -25,7 +36,13 @@ func (w *Warnings) Error() string {
for i, e := range w.List { for i, e := range w.List {
str += fmt.Sprintf("\tError %d: %s\n", i, e.Error()) str += fmt.Sprintf("\tError %d: %s\n", i, e.Error())
} }
if w.tooManyErrors {
str += fmt.Sprintf("\t%s\n", tooManyErrorsMessage)
}
return str return str
} }
return fmt.Sprintf("Number of warnings: %v", len(w.List)) if w.tooManyErrors {
return fmt.Sprintf("%s > %v - %s", numberOfWarningsMessage, maxWarnings, tooManyErrorsMessage)
}
return fmt.Sprintf("%s %v", numberOfWarningsMessage, len(w.List))
} }

View File

@@ -348,7 +348,7 @@ func getTableInfo(filename string, table any) (index, step, length int) {
length = int(table.(pmibUDP6TableOwnerPid).DwNumEntries) length = int(table.(pmibUDP6TableOwnerPid).DwNumEntries)
} }
return return index, step, length
} }
func getTCPConnections(family uint32) ([]ConnectionStat, error) { func getTCPConnections(family uint32) ([]ConnectionStat, error) {
@@ -533,7 +533,7 @@ func getExtendedTCPTable(pTCPTable uintptr, pdwSize *uint32, bOrder bool, ulAf u
if r1 != 0 { if r1 != 0 {
errcode = syscall.Errno(r1) errcode = syscall.Errno(r1)
} }
return return errcode
} }
func getExtendedUDPTable(pUDPTable uintptr, pdwSize *uint32, bOrder bool, ulAf uint32, tableClass udpTableClass, reserved uint32) (errcode error) { func getExtendedUDPTable(pUDPTable uintptr, pdwSize *uint32, bOrder bool, ulAf uint32, tableClass udpTableClass, reserved uint32) (errcode error) {
@@ -541,7 +541,7 @@ func getExtendedUDPTable(pUDPTable uintptr, pdwSize *uint32, bOrder bool, ulAf u
if r1 != 0 { if r1 != 0 {
errcode = syscall.Errno(r1) errcode = syscall.Errno(r1)
} }
return return errcode
} }
func getUintptrFromBool(b bool) uintptr { func getUintptrFromBool(b bool) uintptr {

View File

@@ -956,7 +956,7 @@ func getProcessMemoryInfo(h windows.Handle, mem *PROCESS_MEMORY_COUNTERS) (err e
err = syscall.EINVAL err = syscall.EINVAL
} }
} }
return return err
} }
type SYSTEM_TIMES struct { //nolint:revive //FIXME type SYSTEM_TIMES struct { //nolint:revive //FIXME

4
vendor/modules.txt vendored
View File

@@ -261,7 +261,7 @@ github.com/docker/go-plugins-helpers/volume
# github.com/docker/go-units v0.5.0 # github.com/docker/go-units v0.5.0
## explicit ## explicit
github.com/docker/go-units github.com/docker/go-units
# github.com/ebitengine/purego v0.8.4 # github.com/ebitengine/purego v0.9.0
## explicit; go 1.18 ## explicit; go 1.18
github.com/ebitengine/purego github.com/ebitengine/purego
github.com/ebitengine/purego/internal/cgo github.com/ebitengine/purego/internal/cgo
@@ -606,7 +606,7 @@ github.com/secure-systems-lab/go-securesystemslib/encrypted
# github.com/segmentio/ksuid v1.0.4 # github.com/segmentio/ksuid v1.0.4
## explicit; go 1.12 ## explicit; go 1.12
github.com/segmentio/ksuid github.com/segmentio/ksuid
# github.com/shirou/gopsutil/v4 v4.25.8 # github.com/shirou/gopsutil/v4 v4.25.9
## explicit; go 1.23.0 ## explicit; go 1.23.0
github.com/shirou/gopsutil/v4/common github.com/shirou/gopsutil/v4/common
github.com/shirou/gopsutil/v4/cpu github.com/shirou/gopsutil/v4/cpu