Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 23 additions & 9 deletions cpu/cpu_darwin_arm64.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,38 @@ package cpu
import (
"encoding/binary"
"fmt"
"sync"
"unsafe"

"github.com/shirou/gopsutil/v4/internal/common"
)

// Keep IOKit and CoreFoundation libraries open for the process lifetime.
// See: https://github.com/shirou/gopsutil/issues/1832
var (
cpuLibOnce sync.Once
cpuIOKit *common.IOKitLib
cpuCF *common.CoreFoundationLib
cpuLibErr error
)

func initCPULibraries() {
cpuIOKit, cpuLibErr = common.NewIOKitLib()
if cpuLibErr != nil {
return
}
cpuCF, cpuLibErr = common.NewCoreFoundationLib()
}

// https://github.com/shoenig/go-m1cpu/blob/v0.1.6/cpu.go
func getFrequency() (float64, error) {
iokit, err := common.NewIOKitLib()
if err != nil {
return 0, err
cpuLibOnce.Do(initCPULibraries)
if cpuLibErr != nil {
return 0, cpuLibErr
}
defer iokit.Close()

corefoundation, err := common.NewCoreFoundationLib()
if err != nil {
return 0, err
}
defer corefoundation.Close()
iokit := cpuIOKit
corefoundation := cpuCF

matching := iokit.IOServiceMatching("AppleARMIODevice")

Expand Down
32 changes: 23 additions & 9 deletions disk/disk_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"errors"
"fmt"
"strings"
"sync"
"unsafe"

"golang.org/x/sys/unix"
Expand Down Expand Up @@ -157,18 +158,31 @@ func LabelWithContext(_ context.Context, _ string) (string, error) {
return "", common.ErrNotImplementedError
}

func IOCountersWithContext(_ context.Context, names ...string) (map[string]IOCountersStat, error) {
iokit, err := common.NewIOKitLib()
if err != nil {
return nil, err
// Keep IOKit and CoreFoundation libraries open for the process lifetime.
// See: https://github.com/shirou/gopsutil/issues/1832
var (
diskLibOnce sync.Once
diskIOKit *common.IOKitLib
diskCF *common.CoreFoundationLib
diskLibErr error
)

func initDiskLibraries() {
diskIOKit, diskLibErr = common.NewIOKitLib()
if diskLibErr != nil {
return
}
defer iokit.Close()
diskCF, diskLibErr = common.NewCoreFoundationLib()
}

corefoundation, err := common.NewCoreFoundationLib()
if err != nil {
return nil, err
func IOCountersWithContext(_ context.Context, names ...string) (map[string]IOCountersStat, error) {
diskLibOnce.Do(initDiskLibraries)
if diskLibErr != nil {
return nil, diskLibErr
}
defer corefoundation.Close()

iokit := diskIOKit
corefoundation := diskCF

match := iokit.IOServiceMatching("IOMedia")

Expand Down
28 changes: 22 additions & 6 deletions internal/common/common_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"errors"
"fmt"
"math"
"sync"
"unsafe"

"github.com/ebitengine/purego"
Expand All @@ -16,6 +17,7 @@ import (
type library struct {
handle uintptr
fnMap map[string]any
mu sync.RWMutex
}

// library paths
Expand All @@ -41,15 +43,29 @@ func (lib *library) Dlsym(symbol string) (uintptr, error) {
return purego.Dlsym(lib.handle, symbol)
}

// getFunc resolves a function pointer from the library, caching it in fnMap.
// Thread-safe via double-checked locking to support shared library handles.
func getFunc[T any](lib *library, symbol string) T {
var dlfun *dlFunc[T]
// Fast path: read lock only
lib.mu.RLock()
if f, ok := lib.fnMap[symbol].(*dlFunc[T]); ok {
dlfun = f
} else {
dlfun = newDlfunc[T](symbol)
dlfun.init(lib.handle)
lib.fnMap[symbol] = dlfun
lib.mu.RUnlock()
return f.fn
}
lib.mu.RUnlock()

// Slow path: write lock for first-time resolution
lib.mu.Lock()
defer lib.mu.Unlock()

// Double-check after acquiring write lock
if f, ok := lib.fnMap[symbol].(*dlFunc[T]); ok {
return f.fn
}

dlfun := newDlfunc[T](symbol)
dlfun.init(lib.handle)
lib.fnMap[symbol] = dlfun
return dlfun.fn
}

Expand Down
44 changes: 29 additions & 15 deletions sensors/sensors_darwin_arm64.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package sensors

import (
"context"
"sync"
"unsafe"

"github.com/shirou/gopsutil/v4/internal/common"
Expand All @@ -15,35 +16,48 @@ const (
kHIDPageAppleVendorTemperatureSensor = 5
)

// Keep IOKit and CoreFoundation libraries open for the process lifetime.
// Opening and closing them on every call causes SIGBUS/SIGSEGV crashes
// because the Go runtime (GC, timers) can interact with invalidated
// library handles after Dlclose.
// See: https://github.com/shirou/gopsutil/issues/1832
var (
sensorLibOnce sync.Once
sensorIOKit *common.IOKitLib
sensorCF *common.CoreFoundationLib
sensorLibErr error
)

func initSensorLibraries() {
sensorIOKit, sensorLibErr = common.NewIOKitLib()
if sensorLibErr != nil {
return
}
sensorCF, sensorLibErr = common.NewCoreFoundationLib()
}

func ReadTemperaturesArm() []TemperatureStat {
temperatures, _ := TemperaturesWithContext(context.Background())
return temperatures
}

func TemperaturesWithContext(_ context.Context) ([]TemperatureStat, error) {
iokit, err := common.NewIOKitLib()
if err != nil {
return nil, err
}
defer iokit.Close()

cf, err := common.NewCoreFoundationLib()
if err != nil {
return nil, err
sensorLibOnce.Do(initSensorLibraries)
if sensorLibErr != nil {
return nil, sensorLibErr
}
defer cf.Close()

ta := &temperatureArm{
iokit: iokit,
cf: cf,
iokit: sensorIOKit,
cf: sensorCF,
}

sensors := ta.matching(kHIDPageAppleVendor, kHIDPageAppleVendorTemperatureSensor)
defer cf.CFRelease(uintptr(sensors))
defer sensorCF.CFRelease(uintptr(sensors))

// Create HID system client
system := iokit.IOHIDEventSystemClientCreate(common.KCFAllocatorDefault)
defer cf.CFRelease(uintptr(system))
system := sensorIOKit.IOHIDEventSystemClientCreate(common.KCFAllocatorDefault)
defer sensorCF.CFRelease(uintptr(system))

return ta.getSensors(system, sensors), nil
}
Expand Down
Loading