diff --git a/cpu/cpu_darwin.go b/cpu/cpu_darwin.go index c61a470fba..d3b6dbc532 100644 --- a/cpu/cpu_darwin.go +++ b/cpu/cpu_darwin.go @@ -61,17 +61,17 @@ func Times(percpu bool) ([]TimesStat, error) { } func TimesWithContext(_ context.Context, percpu bool) ([]TimesStat, error) { - lib, err := common.NewLibrary(common.System) + sys, err := common.NewSystemLib() if err != nil { return nil, err } - defer lib.Close() + defer sys.Close() if percpu { - return perCPUTimes(lib) + return perCPUTimes(sys) } - return allCPUTimes(lib) + return allCPUTimes(sys) } // Returns only one CPUInfoStat on FreeBSD @@ -138,16 +138,12 @@ func CountsWithContext(_ context.Context, logical bool) (int, error) { return int(count), nil } -func perCPUTimes(machLib *common.Library) ([]TimesStat, error) { - machHostSelf := common.GetFunc[common.MachHostSelfFunc](machLib, common.MachHostSelfSym) - machTaskSelf := common.GetFunc[common.MachTaskSelfFunc](machLib, common.MachTaskSelfSym) - hostProcessorInfo := common.GetFunc[common.HostProcessorInfoFunc](machLib, common.HostProcessorInfoSym) - vmDeallocate := common.GetFunc[common.VMDeallocateFunc](machLib, common.VMDeallocateSym) - +func perCPUTimes(sys *common.SystemLib) ([]TimesStat, error) { var count, ncpu uint32 var cpuload *hostCpuLoadInfoData - status := hostProcessorInfo(machHostSelf(), processorCpuLoadInfo, &ncpu, uintptr(unsafe.Pointer(&cpuload)), &count) + status := sys.HostProcessorInfo(sys.MachHostSelf(), processorCpuLoadInfo, + &ncpu, uintptr(unsafe.Pointer(&cpuload)), &count) if status != common.KERN_SUCCESS { return nil, fmt.Errorf("host_processor_info error=%d", status) @@ -157,7 +153,7 @@ func perCPUTimes(machLib *common.Library) ([]TimesStat, error) { return nil, errors.New("host_processor_info returned nil cpuload") } - defer vmDeallocate(machTaskSelf(), uintptr(unsafe.Pointer(cpuload)), uintptr(ncpu)) + defer sys.VMDeallocate(sys.MachTaskSelf(), uintptr(unsafe.Pointer(cpuload)), uintptr(ncpu)) ret := []TimesStat{} loads := unsafe.Slice(cpuload, ncpu) @@ -170,21 +166,17 @@ func perCPUTimes(machLib *common.Library) ([]TimesStat, error) { Nice: float64(loads[i].cpuTicks[cpuStateNice]) / ClocksPerSec, Idle: float64(loads[i].cpuTicks[cpuStateIdle]) / ClocksPerSec, } - ret = append(ret, c) } return ret, nil } -func allCPUTimes(machLib *common.Library) ([]TimesStat, error) { - machHostSelf := common.GetFunc[common.MachHostSelfFunc](machLib, common.MachHostSelfSym) - hostStatistics := common.GetFunc[common.HostStatisticsFunc](machLib, common.HostStatisticsSym) - +func allCPUTimes(sys *common.SystemLib) ([]TimesStat, error) { var cpuload hostCpuLoadInfoData count := uint32(cpuStateMax) - status := hostStatistics(machHostSelf(), common.HOST_CPU_LOAD_INFO, + status := sys.HostStatistics(sys.MachHostSelf(), common.HOST_CPU_LOAD_INFO, uintptr(unsafe.Pointer(&cpuload)), &count) if status != common.KERN_SUCCESS { diff --git a/cpu/cpu_darwin_arm64.go b/cpu/cpu_darwin_arm64.go index f6948f62cf..2effcadf8d 100644 --- a/cpu/cpu_darwin_arm64.go +++ b/cpu/cpu_darwin_arm64.go @@ -13,55 +13,43 @@ import ( // https://github.com/shoenig/go-m1cpu/blob/v0.1.6/cpu.go func getFrequency() (float64, error) { - ioKit, err := common.NewLibrary(common.IOKit) + iokit, err := common.NewIOKitLib() if err != nil { return 0, err } - defer ioKit.Close() + defer iokit.Close() - coreFoundation, err := common.NewLibrary(common.CoreFoundation) + corefoundation, err := common.NewCoreFoundationLib() if err != nil { return 0, err } - defer coreFoundation.Close() + defer corefoundation.Close() - ioServiceMatching := common.GetFunc[common.IOServiceMatchingFunc](ioKit, common.IOServiceMatchingSym) - ioServiceGetMatchingServices := common.GetFunc[common.IOServiceGetMatchingServicesFunc](ioKit, common.IOServiceGetMatchingServicesSym) - ioIteratorNext := common.GetFunc[common.IOIteratorNextFunc](ioKit, common.IOIteratorNextSym) - ioRegistryEntryGetName := common.GetFunc[common.IORegistryEntryGetNameFunc](ioKit, common.IORegistryEntryGetNameSym) - ioRegistryEntryCreateCFProperty := common.GetFunc[common.IORegistryEntryCreateCFPropertyFunc](ioKit, common.IORegistryEntryCreateCFPropertySym) - ioObjectRelease := common.GetFunc[common.IOObjectReleaseFunc](ioKit, common.IOObjectReleaseSym) - - cfStringCreateWithCString := common.GetFunc[common.CFStringCreateWithCStringFunc](coreFoundation, common.CFStringCreateWithCStringSym) - cfDataGetLength := common.GetFunc[common.CFDataGetLengthFunc](coreFoundation, common.CFDataGetLengthSym) - cfDataGetBytePtr := common.GetFunc[common.CFDataGetBytePtrFunc](coreFoundation, common.CFDataGetBytePtrSym) - cfRelease := common.GetFunc[common.CFReleaseFunc](coreFoundation, common.CFReleaseSym) - - matching := ioServiceMatching("AppleARMIODevice") + matching := iokit.IOServiceMatching("AppleARMIODevice") var iterator uint32 - if status := ioServiceGetMatchingServices(common.KIOMainPortDefault, uintptr(matching), &iterator); status != common.KERN_SUCCESS { + if status := iokit.IOServiceGetMatchingServices(common.KIOMainPortDefault, uintptr(matching), &iterator); status != common.KERN_SUCCESS { return 0.0, fmt.Errorf("IOServiceGetMatchingServices error=%d", status) } - defer ioObjectRelease(iterator) + defer iokit.IOObjectRelease(iterator) - pCorekey := cfStringCreateWithCString(common.KCFAllocatorDefault, "voltage-states5-sram", common.KCFStringEncodingUTF8) - defer cfRelease(uintptr(pCorekey)) + pCorekey := corefoundation.CFStringCreateWithCString(common.KCFAllocatorDefault, "voltage-states5-sram", common.KCFStringEncodingUTF8) + defer corefoundation.CFRelease(uintptr(pCorekey)) var pCoreHz uint32 for { - service := ioIteratorNext(iterator) + service := iokit.IOIteratorNext(iterator) if service <= 0 { break } buf := common.NewCStr(512) - ioRegistryEntryGetName(service, buf) + iokit.IORegistryEntryGetName(service, buf) if buf.GoString() == "pmgr" { - pCoreRef := ioRegistryEntryCreateCFProperty(service, uintptr(pCorekey), common.KCFAllocatorDefault, common.KNilOptions) - length := cfDataGetLength(uintptr(pCoreRef)) - data := cfDataGetBytePtr(uintptr(pCoreRef)) + pCoreRef := iokit.IORegistryEntryCreateCFProperty(service, uintptr(pCorekey), common.KCFAllocatorDefault, common.KNilOptions) + length := corefoundation.CFDataGetLength(uintptr(pCoreRef)) + data := corefoundation.CFDataGetBytePtr(uintptr(pCoreRef)) // composite uint32 from the byte array buf := unsafe.Slice((*byte)(data), length) @@ -69,12 +57,12 @@ func getFrequency() (float64, error) { // combine the bytes into a uint32 value b := buf[length-8 : length-4] pCoreHz = binary.LittleEndian.Uint32(b) - cfRelease(uintptr(pCoreRef)) - ioObjectRelease(service) + corefoundation.CFRelease(uintptr(pCoreRef)) + iokit.IOObjectRelease(service) break } - ioObjectRelease(service) + iokit.IOObjectRelease(service) } return float64(pCoreHz / 1_000_000), nil diff --git a/disk/disk_darwin.go b/disk/disk_darwin.go index a4b04af3de..2d46f81582 100644 --- a/disk/disk_darwin.go +++ b/disk/disk_darwin.go @@ -158,58 +158,41 @@ func LabelWithContext(_ context.Context, _ string) (string, error) { } func IOCountersWithContext(_ context.Context, names ...string) (map[string]IOCountersStat, error) { - ioKit, err := common.NewLibrary(common.IOKit) + iokit, err := common.NewIOKitLib() if err != nil { return nil, err } - defer ioKit.Close() + defer iokit.Close() - coreFoundation, err := common.NewLibrary(common.CoreFoundation) + corefoundation, err := common.NewCoreFoundationLib() if err != nil { return nil, err } - defer coreFoundation.Close() + defer corefoundation.Close() - ioServiceMatching := common.GetFunc[common.IOServiceMatchingFunc](ioKit, common.IOServiceMatchingSym) - ioServiceGetMatchingServices := common.GetFunc[common.IOServiceGetMatchingServicesFunc](ioKit, common.IOServiceGetMatchingServicesSym) - ioIteratorNext := common.GetFunc[common.IOIteratorNextFunc](ioKit, common.IOIteratorNextSym) - ioObjectRelease := common.GetFunc[common.IOObjectReleaseFunc](ioKit, common.IOObjectReleaseSym) + match := iokit.IOServiceMatching("IOMedia") - cfDictionaryAddValue := common.GetFunc[common.CFDictionaryAddValueFunc](coreFoundation, common.CFDictionaryAddValueSym) - cfStringCreateWithCString := common.GetFunc[common.CFStringCreateWithCStringFunc](coreFoundation, common.CFStringCreateWithCStringSym) - cfRelease := common.GetFunc[common.CFReleaseFunc](coreFoundation, common.CFReleaseSym) + key := corefoundation.CFStringCreateWithCString(common.KCFAllocatorDefault, common.KIOMediaWholeKey, common.KCFStringEncodingUTF8) + defer corefoundation.CFRelease(uintptr(key)) - kCFBooleanTruePtr, _ := coreFoundation.Dlsym("kCFBooleanTrue") - - match := ioServiceMatching("IOMedia") - - key := cfStringCreateWithCString(common.KCFAllocatorDefault, common.KIOMediaWholeKey, common.KCFStringEncodingUTF8) - defer cfRelease(uintptr(key)) + kCFBooleanTruePtr, _ := corefoundation.Dlsym("kCFBooleanTrue") + kCFBooleanTrue := **(**uintptr)(unsafe.Pointer(&kCFBooleanTruePtr)) + corefoundation.CFDictionaryAddValue(uintptr(match), uintptr(key), kCFBooleanTrue) var drives uint32 - kCFBooleanTrue := **(**uintptr)(unsafe.Pointer(&kCFBooleanTruePtr)) - cfDictionaryAddValue(uintptr(match), uintptr(key), kCFBooleanTrue) - if status := ioServiceGetMatchingServices(common.KIOMainPortDefault, uintptr(match), &drives); status != common.KERN_SUCCESS { + if status := iokit.IOServiceGetMatchingServices(common.KIOMainPortDefault, uintptr(match), &drives); status != common.KERN_SUCCESS { return nil, fmt.Errorf("IOServiceGetMatchingServices error=%d", status) } - defer ioObjectRelease(drives) + defer iokit.IOObjectRelease(drives) ic := &ioCounters{ - ioKit: ioKit, - coreFoundation: coreFoundation, - - ioRegistryEntryCreateCFProperties: common.GetFunc[common.IORegistryEntryCreateCFPropertiesFunc](ioKit, common.IORegistryEntryCreateCFPropertiesSym), - ioObjectRelease: ioObjectRelease, - - cfStringCreateWithCString: cfStringCreateWithCString, - cfDictionaryGetValue: common.GetFunc[common.CFDictionaryGetValueFunc](coreFoundation, common.CFDictionaryGetValueSym), - cfNumberGetValue: common.GetFunc[common.CFNumberGetValueFunc](coreFoundation, common.CFNumberGetValueSym), - cfRelease: cfRelease, + iokit: iokit, + corefoundation: corefoundation, } stats := make([]IOCountersStat, 0, 16) for { - d := ioIteratorNext(drives) + d := iokit.IOIteratorNext(drives) if d <= 0 { break } @@ -223,7 +206,7 @@ func IOCountersWithContext(_ context.Context, names ...string) (map[string]IOCou stats = append(stats, *stat) } - ioObjectRelease(d) + iokit.IOObjectRelease(d) } ret := make(map[string]IOCountersStat, 0) @@ -243,9 +226,9 @@ func IOCountersWithContext(_ context.Context, names ...string) (map[string]IOCou } const ( - kIOBSDNameKey = "BSD Name" - kIOMediaSizeKey = "Size" - kIOMediaPreferredBlockSizeKey = "Preferred Block Size" + kIOBSDNameKey = "BSD Name" + // kIOMediaSizeKey = "Size" + // kIOMediaPreferredBlockSizeKey = "Preferred Block Size" kIOBlockStorageDriverStatisticsKey = "Statistics" kIOBlockStorageDriverStatisticsBytesReadKey = "Bytes (Read)" @@ -257,48 +240,34 @@ const ( ) type ioCounters struct { - ioKit *common.Library - coreFoundation *common.Library - - ioRegistryEntryCreateCFProperties common.IORegistryEntryCreateCFPropertiesFunc - ioObjectRelease common.IOObjectReleaseFunc - - cfStringCreateWithCString common.CFStringCreateWithCStringFunc - cfDictionaryGetValue common.CFDictionaryGetValueFunc - cfNumberGetValue common.CFNumberGetValueFunc - cfRelease common.CFReleaseFunc + iokit *common.IOKitLib + corefoundation *common.CoreFoundationLib } func (i *ioCounters) getDriveStat(d uint32) (*IOCountersStat, error) { - ioRegistryEntryGetParentEntry := common.GetFunc[common.IORegistryEntryGetParentEntryFunc](i.ioKit, common.IORegistryEntryGetParentEntrySym) - ioObjectConformsTo := common.GetFunc[common.IOObjectConformsToFunc](i.ioKit, common.IOObjectConformsToSym) - - cfStringGetLength := common.GetFunc[common.CFStringGetLengthFunc](i.coreFoundation, common.CFStringGetLengthSym) - cfStringGetCString := common.GetFunc[common.CFStringGetCStringFunc](i.coreFoundation, common.CFStringGetCStringSym) - var parent uint32 - if status := ioRegistryEntryGetParentEntry(d, common.KIOServicePlane, &parent); status != common.KERN_SUCCESS { + if status := i.iokit.IORegistryEntryGetParentEntry(d, common.KIOServicePlane, &parent); status != common.KERN_SUCCESS { return nil, fmt.Errorf("IORegistryEntryGetParentEntry error=%d", status) } - defer i.ioObjectRelease(parent) + defer i.iokit.IOObjectRelease(parent) - if !ioObjectConformsTo(parent, "IOBlockStorageDriver") { + if !i.iokit.IOObjectConformsTo(parent, "IOBlockStorageDriver") { // return nil, fmt.Errorf("ERROR: the object is not of the IOBlockStorageDriver class") return nil, nil } var props unsafe.Pointer - if status := i.ioRegistryEntryCreateCFProperties(d, unsafe.Pointer(&props), common.KCFAllocatorDefault, common.KNilOptions); status != common.KERN_SUCCESS { + if status := i.iokit.IORegistryEntryCreateCFProperties(d, unsafe.Pointer(&props), common.KCFAllocatorDefault, common.KNilOptions); status != common.KERN_SUCCESS { return nil, fmt.Errorf("IORegistryEntryCreateCFProperties error=%d", status) } - defer i.cfRelease(uintptr(props)) + defer i.corefoundation.CFRelease(uintptr(props)) key := i.cfStr(kIOBSDNameKey) - defer i.cfRelease(uintptr(key)) - name := i.cfDictionaryGetValue(uintptr(props), uintptr(key)) + defer i.corefoundation.CFRelease(uintptr(key)) + name := i.corefoundation.CFDictionaryGetValue(uintptr(props), uintptr(key)) - buf := common.NewCStr(cfStringGetLength(uintptr(name))) - cfStringGetCString(uintptr(name), buf, buf.Length(), common.KCFStringEncodingUTF8) + buf := common.NewCStr(i.corefoundation.CFStringGetLength(uintptr(name))) + i.corefoundation.CFStringGetCString(uintptr(name), buf, buf.Length(), common.KCFStringEncodingUTF8) stat, err := i.fillStat(parent) if err != nil { @@ -314,19 +283,19 @@ func (i *ioCounters) getDriveStat(d uint32) (*IOCountersStat, error) { func (i *ioCounters) fillStat(d uint32) (*IOCountersStat, error) { var props unsafe.Pointer - status := i.ioRegistryEntryCreateCFProperties(d, unsafe.Pointer(&props), common.KCFAllocatorDefault, common.KNilOptions) + status := i.iokit.IORegistryEntryCreateCFProperties(d, unsafe.Pointer(&props), common.KCFAllocatorDefault, common.KNilOptions) if status != common.KERN_SUCCESS { return nil, fmt.Errorf("IORegistryEntryCreateCFProperties error=%d", status) } if props == nil { return nil, nil } - defer i.cfRelease(uintptr(props)) + defer i.corefoundation.CFRelease(uintptr(props)) key := i.cfStr(kIOBlockStorageDriverStatisticsKey) - defer i.cfRelease(uintptr(key)) + defer i.corefoundation.CFRelease(uintptr(key)) - v := i.cfDictionaryGetValue(uintptr(props), uintptr(key)) + v := i.corefoundation.CFDictionaryGetValue(uintptr(props), uintptr(key)) if v == nil { return nil, errors.New("CFDictionaryGetValue failed") } @@ -343,15 +312,15 @@ func (i *ioCounters) fillStat(d uint32) (*IOCountersStat, error) { for key, off := range statstab { s := i.cfStr(key) - if num := i.cfDictionaryGetValue(uintptr(v), uintptr(s)); num != nil { - i.cfNumberGetValue(uintptr(num), common.KCFNumberSInt64Type, uintptr(unsafe.Add(unsafe.Pointer(&stat), off))) + if num := i.corefoundation.CFDictionaryGetValue(uintptr(v), uintptr(s)); num != nil { + i.corefoundation.CFNumberGetValue(uintptr(num), common.KCFNumberSInt64Type, uintptr(unsafe.Add(unsafe.Pointer(&stat), off))) } - i.cfRelease(uintptr(s)) + i.corefoundation.CFRelease(uintptr(s)) } return &stat, nil } func (i *ioCounters) cfStr(str string) unsafe.Pointer { - return i.cfStringCreateWithCString(common.KCFAllocatorDefault, str, common.KCFStringEncodingUTF8) + return i.corefoundation.CFStringCreateWithCString(common.KCFAllocatorDefault, str, common.KCFStringEncodingUTF8) } diff --git a/internal/common/common_darwin.go b/internal/common/common_darwin.go index bf5e047334..0c9747b790 100644 --- a/internal/common/common_darwin.go +++ b/internal/common/common_darwin.go @@ -12,48 +12,311 @@ import ( ) // Library represents a dynamic library loaded by purego. -type Library struct { - addr uintptr - path string - close func() +type library struct { + handle uintptr + fnMap map[string]any } // library paths const ( - IOKit = "/System/Library/Frameworks/IOKit.framework/IOKit" - CoreFoundation = "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation" - System = "/usr/lib/libSystem.B.dylib" + IOKitLibPath = "/System/Library/Frameworks/IOKit.framework/IOKit" + CoreFoundationLibPath = "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation" + SystemLibPath = "/usr/lib/libSystem.B.dylib" ) -func NewLibrary(path string) (*Library, error) { +func newLibrary(path string) (*library, error) { lib, err := purego.Dlopen(path, purego.RTLD_LAZY|purego.RTLD_GLOBAL) if err != nil { return nil, err } - closeFunc := func() { - purego.Dlclose(lib) + return &library{ + handle: lib, + fnMap: make(map[string]any), + }, nil +} + +func (lib *library) Dlsym(symbol string) (uintptr, error) { + return purego.Dlsym(lib.handle, symbol) +} + +func getFunc[T any](lib *library, symbol string) T { + var dlfun *dlFunc[T] + if f, ok := lib.fnMap[symbol].(*dlFunc[T]); ok { + dlfun = f + } else { + dlfun = newDlfunc[T](symbol) + dlfun.init(lib.handle) + lib.fnMap[symbol] = dlfun } + return dlfun.fn +} - return &Library{ - addr: lib, - path: path, - close: closeFunc, - }, nil +func (lib *library) Close() { + purego.Dlclose(lib.handle) +} + +type dlFunc[T any] struct { + sym string + fn T +} + +func (d *dlFunc[T]) init(handle uintptr) { + purego.RegisterLibFunc(&d.fn, handle, d.sym) +} + +func newDlfunc[T any](sym string) *dlFunc[T] { + return &dlFunc[T]{sym: sym} +} + +type CoreFoundationLib struct { + *library +} + +func NewCoreFoundationLib() (*CoreFoundationLib, error) { + library, err := newLibrary(CoreFoundationLibPath) + if err != nil { + return nil, err + } + return &CoreFoundationLib{library}, nil +} + +func (c *CoreFoundationLib) CFGetTypeID(cf uintptr) int32 { + fn := getFunc[CFGetTypeIDFunc](c.library, "CFGetTypeID") + return fn(cf) +} + +func (c *CoreFoundationLib) CFNumberCreate(allocator uintptr, theType int32, valuePtr uintptr) unsafe.Pointer { + fn := getFunc[CFNumberCreateFunc](c.library, "CFNumberCreate") + return fn(allocator, theType, valuePtr) +} + +func (c *CoreFoundationLib) CFNumberGetValue(num uintptr, theType int32, valuePtr uintptr) bool { + fn := getFunc[CFNumberGetValueFunc](c.library, "CFNumberGetValue") + return fn(num, theType, valuePtr) +} + +func (c *CoreFoundationLib) CFDictionaryCreate(allocator uintptr, keys, values *unsafe.Pointer, numValues int32, + keyCallBacks, valueCallBacks uintptr, +) unsafe.Pointer { + fn := getFunc[CFDictionaryCreateFunc](c.library, "CFDictionaryCreate") + return fn(allocator, keys, values, numValues, keyCallBacks, valueCallBacks) +} + +func (c *CoreFoundationLib) CFDictionaryAddValue(theDict, key, value uintptr) { + fn := getFunc[CFDictionaryAddValueFunc](c.library, "CFDictionaryAddValue") + fn(theDict, key, value) +} + +func (c *CoreFoundationLib) CFDictionaryGetValue(theDict, key uintptr) unsafe.Pointer { + fn := getFunc[CFDictionaryGetValueFunc](c.library, "CFDictionaryGetValue") + return fn(theDict, key) +} + +func (c *CoreFoundationLib) CFArrayGetCount(theArray uintptr) int32 { + fn := getFunc[CFArrayGetCountFunc](c.library, "CFArrayGetCount") + return fn(theArray) +} + +func (c *CoreFoundationLib) CFArrayGetValueAtIndex(theArray uintptr, index int32) unsafe.Pointer { + fn := getFunc[CFArrayGetValueAtIndexFunc](c.library, "CFArrayGetValueAtIndex") + return fn(theArray, index) +} + +func (c *CoreFoundationLib) CFStringCreateMutable(alloc uintptr, maxLength int32) unsafe.Pointer { + fn := getFunc[CFStringCreateMutableFunc](c.library, "CFStringCreateMutable") + return fn(alloc, maxLength) +} + +func (c *CoreFoundationLib) CFStringGetLength(theString uintptr) int32 { + fn := getFunc[CFStringGetLengthFunc](c.library, "CFStringGetLength") + return fn(theString) +} + +func (c *CoreFoundationLib) CFStringGetCString(theString uintptr, buffer CStr, bufferSize int32, encoding uint32) { + fn := getFunc[CFStringGetCStringFunc](c.library, "CFStringGetCString") + fn(theString, buffer, bufferSize, encoding) +} + +func (c *CoreFoundationLib) CFStringCreateWithCString(alloc uintptr, cStr string, encoding uint32) unsafe.Pointer { + fn := getFunc[CFStringCreateWithCStringFunc](c.library, "CFStringCreateWithCString") + return fn(alloc, cStr, encoding) +} + +func (c *CoreFoundationLib) CFDataGetLength(theData uintptr) int32 { + fn := getFunc[CFDataGetLengthFunc](c.library, "CFDataGetLength") + return fn(theData) } -func (lib *Library) Dlsym(symbol string) (uintptr, error) { - return purego.Dlsym(lib.addr, symbol) +func (c *CoreFoundationLib) CFDataGetBytePtr(theData uintptr) unsafe.Pointer { + fn := getFunc[CFDataGetBytePtrFunc](c.library, "CFDataGetBytePtr") + return fn(theData) } -func GetFunc[T any](lib *Library, symbol string) T { - var fptr T - purego.RegisterLibFunc(&fptr, lib.addr, symbol) - return fptr +func (c *CoreFoundationLib) CFRelease(cf uintptr) { + fn := getFunc[CFReleaseFunc](c.library, "CFRelease") + fn(cf) } -func (lib *Library) Close() { - lib.close() +type IOKitLib struct { + *library +} + +func NewIOKitLib() (*IOKitLib, error) { + library, err := newLibrary(IOKitLibPath) + if err != nil { + return nil, err + } + return &IOKitLib{library}, nil +} + +func (l *IOKitLib) IOServiceGetMatchingService(mainPort uint32, matching uintptr) uint32 { + fn := getFunc[IOServiceGetMatchingServiceFunc](l.library, "IOServiceGetMatchingService") + return fn(mainPort, matching) +} + +func (l *IOKitLib) IOServiceGetMatchingServices(mainPort uint32, matching uintptr, existing *uint32) int { + fn := getFunc[IOServiceGetMatchingServicesFunc](l.library, "IOServiceGetMatchingServices") + return fn(mainPort, matching, existing) +} + +func (l *IOKitLib) IOServiceMatching(name string) unsafe.Pointer { + fn := getFunc[IOServiceMatchingFunc](l.library, "IOServiceMatching") + return fn(name) +} + +func (l *IOKitLib) IOServiceOpen(service, owningTask, connType uint32, connect *uint32) int { + fn := getFunc[IOServiceOpenFunc](l.library, "IOServiceOpen") + return fn(service, owningTask, connType, connect) +} + +func (l *IOKitLib) IOServiceClose(connect uint32) int { + fn := getFunc[IOServiceCloseFunc](l.library, "IOServiceClose") + return fn(connect) +} + +func (l *IOKitLib) IOIteratorNext(iterator uint32) uint32 { + fn := getFunc[IOIteratorNextFunc](l.library, "IOIteratorNext") + return fn(iterator) +} + +func (l *IOKitLib) IORegistryEntryGetName(entry uint32, name CStr) int { + fn := getFunc[IORegistryEntryGetNameFunc](l.library, "IORegistryEntryGetName") + return fn(entry, name) +} + +func (l *IOKitLib) IORegistryEntryGetParentEntry(entry uint32, plane string, parent *uint32) int { + fn := getFunc[IORegistryEntryGetParentEntryFunc](l.library, "IORegistryEntryGetParentEntry") + return fn(entry, plane, parent) +} + +func (l *IOKitLib) IORegistryEntryCreateCFProperty(entry uint32, key, allocator uintptr, options uint32) unsafe.Pointer { + fn := getFunc[IORegistryEntryCreateCFPropertyFunc](l.library, "IORegistryEntryCreateCFProperty") + return fn(entry, key, allocator, options) +} + +func (l *IOKitLib) IORegistryEntryCreateCFProperties(entry uint32, properties unsafe.Pointer, allocator uintptr, options uint32) int { + fn := getFunc[IORegistryEntryCreateCFPropertiesFunc](l.library, "IORegistryEntryCreateCFProperties") + return fn(entry, properties, allocator, options) +} + +func (l *IOKitLib) IOObjectConformsTo(object uint32, className string) bool { + fn := getFunc[IOObjectConformsToFunc](l.library, "IOObjectConformsTo") + return fn(object, className) +} + +func (l *IOKitLib) IOObjectRelease(object uint32) int { + fn := getFunc[IOObjectReleaseFunc](l.library, "IOObjectRelease") + return fn(object) +} + +func (l *IOKitLib) IOConnectCallStructMethod(connection, selector uint32, inputStruct, inputStructCnt, outputStruct uintptr, outputStructCnt *uintptr) int { + fn := getFunc[IOConnectCallStructMethodFunc](l.library, "IOConnectCallStructMethod") + return fn(connection, selector, inputStruct, inputStructCnt, outputStruct, outputStructCnt) +} + +func (l *IOKitLib) IOHIDEventSystemClientCreate(allocator uintptr) unsafe.Pointer { + fn := getFunc[IOHIDEventSystemClientCreateFunc](l.library, "IOHIDEventSystemClientCreate") + return fn(allocator) +} + +func (l *IOKitLib) IOHIDEventSystemClientSetMatching(client, match uintptr) int { + fn := getFunc[IOHIDEventSystemClientSetMatchingFunc](l.library, "IOHIDEventSystemClientSetMatching") + return fn(client, match) +} + +func (l *IOKitLib) IOHIDServiceClientCopyEvent(service uintptr, eventType int64, options int32, timeout int64) unsafe.Pointer { + fn := getFunc[IOHIDServiceClientCopyEventFunc](l.library, "IOHIDServiceClientCopyEvent") + return fn(service, eventType, options, timeout) +} + +func (l *IOKitLib) IOHIDServiceClientCopyProperty(service, property uintptr) unsafe.Pointer { + fn := getFunc[IOHIDServiceClientCopyPropertyFunc](l.library, "IOHIDServiceClientCopyProperty") + return fn(service, property) +} + +func (l *IOKitLib) IOHIDEventGetFloatValue(event uintptr, field int32) float64 { + fn := getFunc[IOHIDEventGetFloatValueFunc](l.library, "IOHIDEventGetFloatValue") + return fn(event, field) +} + +func (l *IOKitLib) IOHIDEventSystemClientCopyServices(client uintptr) unsafe.Pointer { + fn := getFunc[IOHIDEventSystemClientCopyServicesFunc](l.library, "IOHIDEventSystemClientCopyServices") + return fn(client) +} + +type SystemLib struct { + *library +} + +func NewSystemLib() (*SystemLib, error) { + library, err := newLibrary(SystemLibPath) + if err != nil { + return nil, err + } + return &SystemLib{library}, nil +} + +func (s *SystemLib) HostProcessorInfo(host uint32, flavor int32, outProcessorCount *uint32, outProcessorInfo uintptr, + outProcessorInfoCnt *uint32, +) int { + fn := getFunc[HostProcessorInfoFunc](s.library, "host_processor_info") + return fn(host, flavor, outProcessorCount, outProcessorInfo, outProcessorInfoCnt) +} + +func (s *SystemLib) HostStatistics(host uint32, flavor int32, hostInfoOut uintptr, hostInfoOutCnt *uint32) int { + fn := getFunc[HostStatisticsFunc](s.library, "host_statistics") + return fn(host, flavor, hostInfoOut, hostInfoOutCnt) +} + +func (s *SystemLib) MachHostSelf() uint32 { + fn := getFunc[MachHostSelfFunc](s.library, "mach_host_self") + return fn() +} + +func (s *SystemLib) MachTaskSelf() uint32 { + fn := getFunc[MachTaskSelfFunc](s.library, "mach_task_self") + return fn() +} + +func (s *SystemLib) MachTimeBaseInfo(info uintptr) int { + fn := getFunc[MachTimeBaseInfoFunc](s.library, "mach_timebase_info") + return fn(info) +} + +func (s *SystemLib) VMDeallocate(targetTask uint32, vmAddress, vmSize uintptr) int { + fn := getFunc[VMDeallocateFunc](s.library, "vm_deallocate") + return fn(targetTask, vmAddress, vmSize) +} + +func (s *SystemLib) ProcPidPath(pid int32, buffer uintptr, bufferSize uint32) int32 { + fn := getFunc[ProcPidPathFunc](s.library, "proc_pidpath") + return fn(pid, buffer, bufferSize) +} + +func (s *SystemLib) ProcPidInfo(pid, flavor int32, arg uint64, buffer uintptr, bufferSize int32) int32 { + fn := getFunc[ProcPidInfoFunc](s.library, "proc_pidinfo") + return fn(pid, flavor, arg, buffer, bufferSize) } // status codes @@ -61,7 +324,7 @@ const ( KERN_SUCCESS = 0 ) -// IOKit functions and symbols. +// IOKit types and constants. type ( IOServiceGetMatchingServiceFunc func(mainPort uint32, matching uintptr) uint32 IOServiceGetMatchingServicesFunc func(mainPort uint32, matching uintptr, existing *uint32) int @@ -86,29 +349,6 @@ type ( IOHIDEventSystemClientCopyServicesFunc func(client uintptr) unsafe.Pointer ) -const ( - IOServiceGetMatchingServiceSym = "IOServiceGetMatchingService" - IOServiceGetMatchingServicesSym = "IOServiceGetMatchingServices" - IOServiceMatchingSym = "IOServiceMatching" - IOServiceOpenSym = "IOServiceOpen" - IOServiceCloseSym = "IOServiceClose" - IOIteratorNextSym = "IOIteratorNext" - IORegistryEntryGetNameSym = "IORegistryEntryGetName" - IORegistryEntryGetParentEntrySym = "IORegistryEntryGetParentEntry" - IORegistryEntryCreateCFPropertySym = "IORegistryEntryCreateCFProperty" - IORegistryEntryCreateCFPropertiesSym = "IORegistryEntryCreateCFProperties" - IOObjectConformsToSym = "IOObjectConformsTo" - IOObjectReleaseSym = "IOObjectRelease" - IOConnectCallStructMethodSym = "IOConnectCallStructMethod" - - IOHIDEventSystemClientCreateSym = "IOHIDEventSystemClientCreate" - IOHIDEventSystemClientSetMatchingSym = "IOHIDEventSystemClientSetMatching" - IOHIDServiceClientCopyEventSym = "IOHIDServiceClientCopyEvent" - IOHIDServiceClientCopyPropertySym = "IOHIDServiceClientCopyProperty" - IOHIDEventGetFloatValueSym = "IOHIDEventGetFloatValue" - IOHIDEventSystemClientCopyServicesSym = "IOHIDEventSystemClientCopyServices" -) - const ( KIOMainPortDefault = 0 @@ -122,7 +362,7 @@ const ( KIOServicePlane = "IOService" ) -// CoreFoundation functions and symbols. +// CoreFoundation types and constants. type ( CFGetTypeIDFunc func(cf uintptr) int32 CFNumberCreateFunc func(allocator uintptr, theType int32, valuePtr uintptr) unsafe.Pointer @@ -142,24 +382,6 @@ type ( CFReleaseFunc func(cf uintptr) ) -const ( - CFGetTypeIDSym = "CFGetTypeID" - CFNumberCreateSym = "CFNumberCreate" - CFNumberGetValueSym = "CFNumberGetValue" - CFDictionaryCreateSym = "CFDictionaryCreate" - CFDictionaryAddValueSym = "CFDictionaryAddValue" - CFDictionaryGetValueSym = "CFDictionaryGetValue" - CFArrayGetCountSym = "CFArrayGetCount" - CFArrayGetValueAtIndexSym = "CFArrayGetValueAtIndex" - CFStringCreateMutableSym = "CFStringCreateMutable" - CFStringGetLengthSym = "CFStringGetLength" - CFStringGetCStringSym = "CFStringGetCString" - CFStringCreateWithCStringSym = "CFStringCreateWithCString" - CFDataGetLengthSym = "CFDataGetLength" - CFDataGetBytePtrSym = "CFDataGetBytePtr" - CFReleaseSym = "CFRelease" -) - const ( KCFStringEncodingUTF8 = 0x08000100 KCFNumberSInt64Type = 4 @@ -167,7 +389,7 @@ const ( KCFAllocatorDefault = 0 ) -// Kernel functions and symbols. +// libSystem types and constants. type MachTimeBaseInfo struct { Numer uint32 Denom uint32 @@ -199,7 +421,6 @@ const ( HOST_VM_INFO_COUNT = 0xf ) -// System functions and symbols. type ( ProcPidPathFunc func(pid int32, buffer uintptr, bufferSize uint32) int32 ProcPidInfoFunc func(pid, flavor int32, arg uint64, buffer uintptr, bufferSize int32) int32 @@ -221,9 +442,8 @@ const ( // SMC represents a SMC instance. type SMC struct { - lib *Library - conn uint32 - callStruct IOConnectCallStructMethodFunc + lib *IOKitLib + conn uint32 } const ioServiceSMC = "AppleSMC" @@ -245,47 +465,39 @@ const ( KSMCKeyNotFound = 132 ) -func NewSMC(ioKit *Library) (*SMC, error) { - if ioKit.path != IOKit { - return nil, errors.New("library is not IOKit") +func NewSMC() (*SMC, error) { + iokit, err := NewIOKitLib() + if err != nil { + return nil, err } - ioServiceGetMatchingService := GetFunc[IOServiceGetMatchingServiceFunc](ioKit, IOServiceGetMatchingServiceSym) - ioServiceMatching := GetFunc[IOServiceMatchingFunc](ioKit, IOServiceMatchingSym) - ioServiceOpen := GetFunc[IOServiceOpenFunc](ioKit, IOServiceOpenSym) - ioObjectRelease := GetFunc[IOObjectReleaseFunc](ioKit, IOObjectReleaseSym) - machTaskSelf := GetFunc[MachTaskSelfFunc](ioKit, MachTaskSelfSym) - - ioConnectCallStructMethod := GetFunc[IOConnectCallStructMethodFunc](ioKit, IOConnectCallStructMethodSym) - - service := ioServiceGetMatchingService(0, uintptr(ioServiceMatching(ioServiceSMC))) + service := iokit.IOServiceGetMatchingService(0, uintptr(iokit.IOServiceMatching(ioServiceSMC))) if service == 0 { return nil, fmt.Errorf("ERROR: %s NOT FOUND", ioServiceSMC) } var conn uint32 - if result := ioServiceOpen(service, machTaskSelf(), 0, &conn); result != 0 { + machTaskSelf := getFunc[MachTaskSelfFunc](iokit.library, "mach_task_self") + if result := iokit.IOServiceOpen(service, machTaskSelf(), 0, &conn); result != 0 { return nil, errors.New("ERROR: IOServiceOpen failed") } - ioObjectRelease(service) + iokit.IOObjectRelease(service) return &SMC{ - lib: ioKit, - conn: conn, - callStruct: ioConnectCallStructMethod, + lib: iokit, + conn: conn, }, nil } func (s *SMC) CallStruct(selector uint32, inputStruct, inputStructCnt, outputStruct uintptr, outputStructCnt *uintptr) int { - return s.callStruct(s.conn, selector, inputStruct, inputStructCnt, outputStruct, outputStructCnt) + return s.lib.IOConnectCallStructMethod(s.conn, selector, inputStruct, inputStructCnt, outputStruct, outputStructCnt) } func (s *SMC) Close() error { - ioServiceClose := GetFunc[IOServiceCloseFunc](s.lib, IOServiceCloseSym) - - if result := ioServiceClose(s.conn); result != 0 { + if result := s.lib.IOServiceClose(s.conn); result != 0 { return errors.New("ERROR: IOServiceClose failed") } + s.lib.Close() return nil } diff --git a/mem/mem_darwin.go b/mem/mem_darwin.go index 7d96a3bb09..1b3e9f21be 100644 --- a/mem/mem_darwin.go +++ b/mem/mem_darwin.go @@ -85,26 +85,23 @@ func VirtualMemory() (*VirtualMemoryStat, error) { } func VirtualMemoryWithContext(_ context.Context) (*VirtualMemoryStat, error) { - machLib, err := common.NewLibrary(common.System) + sys, err := common.NewSystemLib() if err != nil { return nil, err } - defer machLib.Close() - - hostStatistics := common.GetFunc[common.HostStatisticsFunc](machLib, common.HostStatisticsSym) - machHostSelf := common.GetFunc[common.MachHostSelfFunc](machLib, common.MachHostSelfSym) + defer sys.Close() count := uint32(common.HOST_VM_INFO_COUNT) var vmstat vmStatisticsData - status := hostStatistics(machHostSelf(), common.HOST_VM_INFO, + status := sys.HostStatistics(sys.MachHostSelf(), common.HOST_VM_INFO, uintptr(unsafe.Pointer(&vmstat)), &count) if status != common.KERN_SUCCESS { return nil, fmt.Errorf("host_statistics error=%d", status) } - pageSizeAddr, _ := machLib.Dlsym("vm_kernel_page_size") + pageSizeAddr, _ := sys.Dlsym("vm_kernel_page_size") pageSize := **(**uint64)(unsafe.Pointer(&pageSizeAddr)) total, err := getHwMemsize() if err != nil { diff --git a/process/process_darwin.go b/process/process_darwin.go index 9c703e3223..d7fb921cbf 100644 --- a/process/process_darwin.go +++ b/process/process_darwin.go @@ -280,31 +280,21 @@ func callPsWithContext(ctx context.Context, arg string, pid int32, threadOption, } type dlFuncs struct { - lib *common.Library - - procPidPath common.ProcPidPathFunc - procPidInfo common.ProcPidInfoFunc - machTimeBaseInfo common.MachTimeBaseInfoFunc + lib *common.SystemLib } func loadProcFuncs() (*dlFuncs, error) { - lib, err := common.NewLibrary(common.System) + lib, err := common.NewSystemLib() if err != nil { return nil, err } - - return &dlFuncs{ - lib: lib, - procPidPath: common.GetFunc[common.ProcPidPathFunc](lib, common.ProcPidPathSym), - procPidInfo: common.GetFunc[common.ProcPidInfoFunc](lib, common.ProcPidInfoSym), - machTimeBaseInfo: common.GetFunc[common.MachTimeBaseInfoFunc](lib, common.MachTimeBaseInfoSym), - }, nil + return &dlFuncs{lib}, err } func (f *dlFuncs) getTimeScaleToNanoSeconds() float64 { var timeBaseInfo common.MachTimeBaseInfo - f.machTimeBaseInfo(uintptr(unsafe.Pointer(&timeBaseInfo))) + f.lib.MachTimeBaseInfo(uintptr(unsafe.Pointer(&timeBaseInfo))) return float64(timeBaseInfo.Numer) / float64(timeBaseInfo.Denom) } @@ -321,7 +311,7 @@ func (p *Process) ExeWithContext(_ context.Context) (string, error) { defer funcs.Close() buf := common.NewCStr(common.PROC_PIDPATHINFO_MAXSIZE) - ret := funcs.procPidPath(p.Pid, buf.Addr(), common.PROC_PIDPATHINFO_MAXSIZE) + ret := funcs.lib.ProcPidPath(p.Pid, buf.Addr(), common.PROC_PIDPATHINFO_MAXSIZE) if ret <= 0 { return "", fmt.Errorf("unknown error: proc_pidpath returned %d", ret) @@ -348,7 +338,7 @@ func (p *Process) CwdWithContext(_ context.Context) (string, error) { var vpi vnodePathInfo const vpiSize = int32(unsafe.Sizeof(vpi)) - ret := funcs.procPidInfo(p.Pid, common.PROC_PIDVNODEPATHINFO, 0, uintptr(unsafe.Pointer(&vpi)), vpiSize) + ret := funcs.lib.ProcPidInfo(p.Pid, common.PROC_PIDVNODEPATHINFO, 0, uintptr(unsafe.Pointer(&vpi)), vpiSize) errno, _ := funcs.lib.Dlsym("errno") err = *(**unix.Errno)(unsafe.Pointer(&errno)) if errors.Is(err, unix.EPERM) { @@ -440,7 +430,7 @@ func (p *Process) NumThreadsWithContext(_ context.Context) (int32, error) { defer funcs.Close() var ti ProcTaskInfo - funcs.procPidInfo(p.Pid, common.PROC_PIDTASKINFO, 0, uintptr(unsafe.Pointer(&ti)), int32(unsafe.Sizeof(ti))) + funcs.lib.ProcPidInfo(p.Pid, common.PROC_PIDTASKINFO, 0, uintptr(unsafe.Pointer(&ti)), int32(unsafe.Sizeof(ti))) return int32(ti.Threadnum), nil } @@ -453,7 +443,7 @@ func (p *Process) TimesWithContext(_ context.Context) (*cpu.TimesStat, error) { defer funcs.Close() var ti ProcTaskInfo - funcs.procPidInfo(p.Pid, common.PROC_PIDTASKINFO, 0, uintptr(unsafe.Pointer(&ti)), int32(unsafe.Sizeof(ti))) + funcs.lib.ProcPidInfo(p.Pid, common.PROC_PIDTASKINFO, 0, uintptr(unsafe.Pointer(&ti)), int32(unsafe.Sizeof(ti))) timescaleToNanoSeconds := funcs.getTimeScaleToNanoSeconds() ret := &cpu.TimesStat{ @@ -472,7 +462,7 @@ func (p *Process) MemoryInfoWithContext(_ context.Context) (*MemoryInfoStat, err defer funcs.Close() var ti ProcTaskInfo - funcs.procPidInfo(p.Pid, common.PROC_PIDTASKINFO, 0, uintptr(unsafe.Pointer(&ti)), int32(unsafe.Sizeof(ti))) + funcs.lib.ProcPidInfo(p.Pid, common.PROC_PIDTASKINFO, 0, uintptr(unsafe.Pointer(&ti)), int32(unsafe.Sizeof(ti))) ret := &MemoryInfoStat{ RSS: uint64(ti.Resident_size), @@ -500,7 +490,7 @@ func (p *Process) NumFDsWithContext(_ context.Context) (int32, error) { defer funcs.Close() // First call: get required buffer size - bufferSize := funcs.procPidInfo( + bufferSize := funcs.lib.ProcPidInfo( p.Pid, common.PROC_PIDLISTFDS, 0, @@ -517,7 +507,7 @@ func (p *Process) NumFDsWithContext(_ context.Context) (int32, error) { buf := make([]procFDInfo, numEntries) // Second call: get actual data - ret := funcs.procPidInfo( + ret := funcs.lib.ProcPidInfo( p.Pid, common.PROC_PIDLISTFDS, 0, diff --git a/sensors/sensors_darwin.go b/sensors/sensors_darwin.go index fa091c0a8b..eb2c4bc527 100644 --- a/sensors/sensors_darwin.go +++ b/sensors/sensors_darwin.go @@ -12,13 +12,7 @@ import ( ) func TemperaturesWithContext(_ context.Context) ([]TemperatureStat, error) { - ioKit, err := common.NewLibrary(common.IOKit) - if err != nil { - return nil, err - } - defer ioKit.Close() - - smc, err := common.NewSMC(ioKit) + smc, err := common.NewSMC() if err != nil { return nil, err } diff --git a/sensors/sensors_darwin_arm64.go b/sensors/sensors_darwin_arm64.go index d0867ce9e8..e6e62ccbfb 100644 --- a/sensors/sensors_darwin_arm64.go +++ b/sensors/sensors_darwin_arm64.go @@ -21,106 +21,72 @@ func ReadTemperaturesArm() []TemperatureStat { } func TemperaturesWithContext(_ context.Context) ([]TemperatureStat, error) { - ioKit, err := common.NewLibrary(common.IOKit) + iokit, err := common.NewIOKitLib() if err != nil { return nil, err } - defer ioKit.Close() + defer iokit.Close() - coreFoundation, err := common.NewLibrary(common.CoreFoundation) + cf, err := common.NewCoreFoundationLib() if err != nil { return nil, err } - defer coreFoundation.Close() + defer cf.Close() ta := &temperatureArm{ - ioKit: ioKit, - cf: coreFoundation, - cfRelease: common.GetFunc[common.CFReleaseFunc](coreFoundation, common.CFReleaseSym), - cfStringCreateWithCString: common.GetFunc[common.CFStringCreateWithCStringFunc](coreFoundation, common.CFStringCreateWithCStringSym), - cfArrayGetCount: common.GetFunc[common.CFArrayGetCountFunc](coreFoundation, common.CFArrayGetCountSym), - cfArrayGetValueAtIndex: common.GetFunc[common.CFArrayGetValueAtIndexFunc](coreFoundation, common.CFArrayGetValueAtIndexSym), - - ioHIDEventSystemClientCreate: common.GetFunc[common.IOHIDEventSystemClientCreateFunc](ioKit, common.IOHIDEventSystemClientCreateSym), - ioHIDEventSystemClientSetMatching: common.GetFunc[common.IOHIDEventSystemClientSetMatchingFunc](ioKit, common.IOHIDEventSystemClientSetMatchingSym), - ioHIDEventSystemClientCopyServices: common.GetFunc[common.IOHIDEventSystemClientCopyServicesFunc](ioKit, common.IOHIDEventSystemClientCopyServicesSym), - - ioHIDServiceClientCopyProperty: common.GetFunc[common.IOHIDServiceClientCopyPropertyFunc](ioKit, common.IOHIDServiceClientCopyPropertySym), - cfStringGetLength: common.GetFunc[common.CFStringGetLengthFunc](coreFoundation, common.CFStringGetLengthSym), - cfStringGetCString: common.GetFunc[common.CFStringGetCStringFunc](coreFoundation, common.CFStringGetCStringSym), - ioHIDServiceClientCopyEvent: common.GetFunc[common.IOHIDServiceClientCopyEventFunc](ioKit, common.IOHIDServiceClientCopyEventSym), - ioHIDEventGetFloatValue: common.GetFunc[common.IOHIDEventGetFloatValueFunc](ioKit, common.IOHIDEventGetFloatValueSym), - cfNumberCreate: common.GetFunc[common.CFNumberCreateFunc](coreFoundation, common.CFNumberCreateSym), - cfDictionaryCreate: common.GetFunc[common.CFDictionaryCreateFunc](coreFoundation, common.CFDictionaryCreateSym), + iokit: iokit, + cf: cf, } sensors := ta.matching(kHIDPageAppleVendor, kHIDPageAppleVendorTemperatureSensor) - defer ta.cfRelease(uintptr(sensors)) + defer cf.CFRelease(uintptr(sensors)) // Create HID system client - system := ta.ioHIDEventSystemClientCreate(common.KCFAllocatorDefault) - defer ta.cfRelease(uintptr(system)) + system := iokit.IOHIDEventSystemClientCreate(common.KCFAllocatorDefault) + defer cf.CFRelease(uintptr(system)) return ta.getSensors(system, sensors), nil } type temperatureArm struct { - ioKit *common.Library - cf *common.Library - - cfRelease common.CFReleaseFunc - cfStringCreateWithCString common.CFStringCreateWithCStringFunc - cfArrayGetCount common.CFArrayGetCountFunc - cfArrayGetValueAtIndex common.CFArrayGetValueAtIndexFunc - cfStringGetLength common.CFStringGetLengthFunc - cfStringGetCString common.CFStringGetCStringFunc - cfNumberCreate common.CFNumberCreateFunc - cfDictionaryCreate common.CFDictionaryCreateFunc - - ioHIDEventSystemClientCreate common.IOHIDEventSystemClientCreateFunc - ioHIDEventSystemClientSetMatching common.IOHIDEventSystemClientSetMatchingFunc - ioHIDEventSystemClientCopyServices common.IOHIDEventSystemClientCopyServicesFunc - ioHIDServiceClientCopyProperty common.IOHIDServiceClientCopyPropertyFunc - ioHIDServiceClientCopyEvent common.IOHIDServiceClientCopyEventFunc - ioHIDEventGetFloatValue common.IOHIDEventGetFloatValueFunc + iokit *common.IOKitLib + cf *common.CoreFoundationLib } func (ta *temperatureArm) getSensors(system, sensors unsafe.Pointer) []TemperatureStat { - ta.ioHIDEventSystemClientSetMatching(uintptr(system), uintptr(sensors)) - matchingsrvs := ta.ioHIDEventSystemClientCopyServices(uintptr(system)) + ta.iokit.IOHIDEventSystemClientSetMatching(uintptr(system), uintptr(sensors)) + matchingsrvs := ta.iokit.IOHIDEventSystemClientCopyServices(uintptr(system)) if matchingsrvs == nil { return nil } - defer ta.cfRelease(uintptr(matchingsrvs)) + defer ta.cf.CFRelease(uintptr(matchingsrvs)) - str := ta.cfStr("Product") - defer ta.cfRelease(uintptr(str)) + str := ta.cf.CFStringCreateWithCString(common.KCFAllocatorDefault, "Product", common.KCFStringEncodingUTF8) + defer ta.cf.CFRelease(uintptr(str)) - count := ta.cfArrayGetCount(uintptr(matchingsrvs)) + count := ta.cf.CFArrayGetCount(uintptr(matchingsrvs)) stats := make([]TemperatureStat, 0, count) nameSet := make(map[string]struct{}) - var i int32 - // traverse backward to keep the latest result first - for i = count - 1; i >= 0; i-- { - sc := ta.cfArrayGetValueAtIndex(uintptr(matchingsrvs), i) - event := ta.ioHIDServiceClientCopyEvent(uintptr(sc), common.KIOHIDEventTypeTemperature, 0, 0) + for i := count - 1; i >= 0; i-- { + sc := ta.cf.CFArrayGetValueAtIndex(uintptr(matchingsrvs), i) + event := ta.iokit.IOHIDServiceClientCopyEvent(uintptr(sc), common.KIOHIDEventTypeTemperature, 0, 0) if event == nil { continue } - temp := ta.ioHIDEventGetFloatValue(uintptr(event), ioHIDEventFieldBase(common.KIOHIDEventTypeTemperature)) - ta.cfRelease(uintptr(event)) + temp := ta.iokit.IOHIDEventGetFloatValue(uintptr(event), ioHIDEventFieldBase(common.KIOHIDEventTypeTemperature)) + ta.cf.CFRelease(uintptr(event)) - nameRef := ta.ioHIDServiceClientCopyProperty(uintptr(sc), uintptr(str)) + nameRef := ta.iokit.IOHIDServiceClientCopyProperty(uintptr(sc), uintptr(str)) if nameRef != nil { - buf := common.NewCStr(ta.cfStringGetLength(uintptr(nameRef))) - ta.cfStringGetCString(uintptr(nameRef), buf, buf.Length(), common.KCFStringEncodingUTF8) + buf := common.NewCStr(ta.cf.CFStringGetLength(uintptr(nameRef))) + ta.cf.CFStringGetCString(uintptr(nameRef), buf, buf.Length(), common.KCFStringEncodingUTF8) name := buf.GoString() if _, ok := nameSet[name]; ok { - ta.cfRelease(uintptr(nameRef)) + ta.cf.CFRelease(uintptr(nameRef)) continue } @@ -129,7 +95,7 @@ func (ta *temperatureArm) getSensors(system, sensors unsafe.Pointer) []Temperatu Temperature: temp, }) nameSet[name] = struct{}{} - ta.cfRelease(uintptr(nameRef)) + ta.cf.CFRelease(uintptr(nameRef)) } } @@ -137,17 +103,17 @@ func (ta *temperatureArm) getSensors(system, sensors unsafe.Pointer) []Temperatu } func (ta *temperatureArm) matching(page, usage int32) unsafe.Pointer { - pageNum := ta.cfNumberCreate(common.KCFAllocatorDefault, common.KCFNumberIntType, uintptr(unsafe.Pointer(&page))) - defer ta.cfRelease(uintptr(pageNum)) + pageNum := ta.cf.CFNumberCreate(common.KCFAllocatorDefault, common.KCFNumberIntType, uintptr(unsafe.Pointer(&page))) + defer ta.cf.CFRelease(uintptr(pageNum)) - usageNum := ta.cfNumberCreate(common.KCFAllocatorDefault, common.KCFNumberIntType, uintptr(unsafe.Pointer(&usage))) - defer ta.cfRelease(uintptr(usageNum)) + usageNum := ta.cf.CFNumberCreate(common.KCFAllocatorDefault, common.KCFNumberIntType, uintptr(unsafe.Pointer(&usage))) + defer ta.cf.CFRelease(uintptr(usageNum)) - k1 := ta.cfStr("PrimaryUsagePage") - k2 := ta.cfStr("PrimaryUsage") + k1 := ta.cf.CFStringCreateWithCString(common.KCFAllocatorDefault, "PrimaryUsagePage", common.KCFStringEncodingUTF8) + k2 := ta.cf.CFStringCreateWithCString(common.KCFAllocatorDefault, "PrimaryUsage", common.KCFStringEncodingUTF8) - defer ta.cfRelease(uintptr(k1)) - defer ta.cfRelease(uintptr(k2)) + defer ta.cf.CFRelease(uintptr(k1)) + defer ta.cf.CFRelease(uintptr(k2)) keys := []unsafe.Pointer{k1, k2} values := []unsafe.Pointer{pageNum, usageNum} @@ -155,15 +121,11 @@ func (ta *temperatureArm) matching(page, usage int32) unsafe.Pointer { kCFTypeDictionaryKeyCallBacks, _ := ta.cf.Dlsym("kCFTypeDictionaryKeyCallBacks") kCFTypeDictionaryValueCallBacks, _ := ta.cf.Dlsym("kCFTypeDictionaryValueCallBacks") - return ta.cfDictionaryCreate(common.KCFAllocatorDefault, &keys[0], &values[0], 2, + return ta.cf.CFDictionaryCreate(common.KCFAllocatorDefault, &keys[0], &values[0], 2, kCFTypeDictionaryKeyCallBacks, kCFTypeDictionaryValueCallBacks) } -func (ta *temperatureArm) cfStr(str string) unsafe.Pointer { - return ta.cfStringCreateWithCString(common.KCFAllocatorDefault, str, common.KCFStringEncodingUTF8) -} - func ioHIDEventFieldBase(i int32) int32 { return i << 16 }