diff --git a/cpu/cpu_darwin.go b/cpu/cpu_darwin.go index 29d9a71be..b3e3a668d 100644 --- a/cpu/cpu_darwin.go +++ b/cpu/cpu_darwin.go @@ -10,7 +10,6 @@ import ( "strings" "unsafe" - "github.com/shoenig/go-m1cpu" "github.com/tklauser/go-sysconf" "golang.org/x/sys/unix" @@ -61,7 +60,7 @@ func Times(percpu bool) ([]TimesStat, error) { } func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) { - lib, err := common.NewLibrary(common.Kernel) + lib, err := common.NewLibrary(common.System) if err != nil { return nil, err } @@ -114,15 +113,9 @@ func InfoWithContext(ctx context.Context) ([]InfoStat, error) { c.CacheSize = int32(cacheSize) c.VendorID, _ = unix.Sysctl("machdep.cpu.vendor") - if m1cpu.IsAppleSilicon() { - c.Mhz = float64(m1cpu.PCoreHz() / 1_000_000) - } else { - // Use the rated frequency of the CPU. This is a static value and does not - // account for low power or Turbo Boost modes. - cpuFrequency, err := unix.SysctlUint64("hw.cpufrequency") - if err == nil { - c.Mhz = float64(cpuFrequency) / 1000000.0 - } + v, err := getFrequency() + if err == nil { + c.Mhz = v } return append(ret, c), nil diff --git a/cpu/cpu_darwin_arm64.go b/cpu/cpu_darwin_arm64.go new file mode 100644 index 000000000..05d43229a --- /dev/null +++ b/cpu/cpu_darwin_arm64.go @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: BSD-3-Clause +//go:build darwin && arm64 + +package cpu + +import ( + "fmt" + "unsafe" + + "github.com/shirou/gopsutil/v4/internal/common" +) + +// https://github.com/shoenig/go-m1cpu/blob/v0.1.6/cpu.go +func getFrequency() (float64, error) { + ioKit, err := common.NewLibrary(common.IOKit) + if err != nil { + return 0, err + } + defer ioKit.Close() + + coreFoundation, err := common.NewLibrary(common.CoreFoundation) + if err != nil { + return 0.0, err + } + 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") + + var iterator uint32 + if status := ioServiceGetMatchingServices(common.KIOMainPortDefault, uintptr(matching), &iterator); status != common.KERN_SUCCESS { + return 0.0, fmt.Errorf("IOServiceGetMatchingServices error=%d", status) + } + + pCorekey := cfStringCreateWithCString(common.KCFAllocatorDefault, "voltage-states5-sram", common.KCFStringEncodingUTF8) + defer cfRelease(uintptr(pCorekey)) + + var pCoreHz uint32 + for { + service := ioIteratorNext(iterator) + if !(service > 0) { + break + } + + buf := make([]byte, 512) + ioRegistryEntryGetName(service, &buf[0]) + + if common.GoString(&buf[0]) == "pmgr" { + pCoreRef := ioRegistryEntryCreateCFProperty(service, uintptr(pCorekey), common.KCFAllocatorDefault, common.KNilOptions) + length := cfDataGetLength(uintptr(pCoreRef)) + data := cfDataGetBytePtr(uintptr(pCoreRef)) + + // composite uint32 from the byte array + buf := unsafe.Slice((*byte)(data), length) + b1 := buf[length-5] + b2 := buf[length-6] + b3 := buf[length-7] + b4 := buf[length-8] + + // combine the bytes into a uint32 value + pCoreHz = uint32(b1)<<24 | uint32(b2)<<16 | uint32(b3)<<8 | uint32(b4) + ioObjectRelease(service) + break + } + + ioObjectRelease(service) + } + + return float64(pCoreHz / 1_000_000), nil +} diff --git a/cpu/cpu_darwin_fallback.go b/cpu/cpu_darwin_fallback.go new file mode 100644 index 000000000..b9e52aba1 --- /dev/null +++ b/cpu/cpu_darwin_fallback.go @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: BSD-3-Clause +//go:build darwin && !arm64 + +package cpu + +import "golang.org/x/sys/unix" + +func getFrequency() (float64, error) { + // Use the rated frequency of the CPU. This is a static value and does not + // account for low power or Turbo Boost modes. + cpuFrequency, err := unix.SysctlUint64("hw.cpufrequency") + return float64(cpuFrequency) / 1000000.0, err +} diff --git a/disk/disk_darwin.go b/disk/disk_darwin.go index 6ed7400e2..98f754493 100644 --- a/disk/disk_darwin.go +++ b/disk/disk_darwin.go @@ -5,6 +5,8 @@ package disk import ( "context" + "fmt" + "unsafe" "golang.org/x/sys/unix" @@ -92,3 +94,194 @@ func SerialNumberWithContext(ctx context.Context, name string) (string, error) { func LabelWithContext(ctx context.Context, name string) (string, error) { return "", common.ErrNotImplementedError } + +func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) { + ioKit, err := common.NewLibrary(common.IOKit) + if err != nil { + return nil, err + } + defer ioKit.Close() + + coreFoundation, err := common.NewLibrary(common.CoreFoundation) + if err != nil { + return nil, err + } + 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) + + cfDictionaryAddValue := common.GetFunc[common.CFDictionaryAddValueFunc](coreFoundation, common.CFDictionaryAddValueSym) + cfStringCreateWithCString := common.GetFunc[common.CFStringCreateWithCStringFunc](coreFoundation, common.CFStringCreateWithCStringSym) + cfRelease := common.GetFunc[common.CFReleaseFunc](coreFoundation, common.CFReleaseSym) + + kCFBooleanTruePtr, _ := coreFoundation.Dlsym("kCFBooleanTrue") + + match := ioServiceMatching("IOMedia") + + key := cfStringCreateWithCString(common.KCFAllocatorDefault, common.KIOMediaWholeKey, common.KCFStringEncodingUTF8) + defer cfRelease(uintptr(key)) + + 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 { + return nil, fmt.Errorf("IOServiceGetMatchingServices error=%d", status) + } + defer 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, + } + + stats := make([]IOCountersStat, 0, 16) + for { + d := ioIteratorNext(drives) + if !(d > 0) { + break + } + + stat, err := ic.getDriveStat(d) + if err != nil { + return nil, err + } + + if stat != nil { + stats = append(stats, *stat) + } + + ioObjectRelease(d) + } + + ret := make(map[string]IOCountersStat, 0) + for i := 0; i < len(stats); i++ { + if len(names) > 0 && !common.StringsHas(names, stats[i].Name) { + continue + } + + stats[i].ReadTime = stats[i].ReadTime / 1000 / 1000 // note: read/write time are in ns, but we want ms. + stats[i].WriteTime = stats[i].WriteTime / 1000 / 1000 + stats[i].IoTime = stats[i].ReadTime + stats[i].WriteTime + + ret[stats[i].Name] = stats[i] + } + + return ret, nil +} + +const ( + kIOBSDNameKey = "BSD Name" + kIOMediaSizeKey = "Size" + kIOMediaPreferredBlockSizeKey = "Preferred Block Size" + + kIOBlockStorageDriverStatisticsKey = "Statistics" + kIOBlockStorageDriverStatisticsBytesReadKey = "Bytes (Read)" + kIOBlockStorageDriverStatisticsBytesWrittenKey = "Bytes (Write)" + kIOBlockStorageDriverStatisticsReadsKey = "Operations (Read)" + kIOBlockStorageDriverStatisticsWritesKey = "Operations (Write)" + kIOBlockStorageDriverStatisticsTotalReadTimeKey = "Total Time (Read)" + kIOBlockStorageDriverStatisticsTotalWriteTimeKey = "Total Time (Write)" +) + +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 +} + +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 { + return nil, fmt.Errorf("IORegistryEntryGetParentEntry error=%d", status) + } + defer i.ioObjectRelease(parent) + + if !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, uintptr(unsafe.Pointer(&props)), common.KCFAllocatorDefault, common.KNilOptions); status != common.KERN_SUCCESS { + return nil, fmt.Errorf("IORegistryEntryCreateCFProperties error=%d", status) + } + defer i.cfRelease(uintptr(props)) + + key := i.cfStr(kIOBSDNameKey) + defer i.cfRelease(uintptr(key)) + name := i.cfDictionaryGetValue(uintptr(props), uintptr(key)) + length := cfStringGetLength(uintptr(name)) + 1 + buf := make([]byte, length-1) + cfStringGetCString(uintptr(name), &buf[0], length, common.KCFStringEncodingUTF8) + + stat, err := i.fillStat(parent) + if err != nil { + return nil, err + } + + stat.Name = string(buf) + return stat, nil +} + +func (i *ioCounters) fillStat(d uint32) (*IOCountersStat, error) { + var props unsafe.Pointer + if status := i.ioRegistryEntryCreateCFProperties(d, uintptr(unsafe.Pointer(&props)), common.KCFAllocatorDefault, common.KNilOptions); status != common.KERN_SUCCESS { + return nil, fmt.Errorf("IORegistryEntryCreateCFProperties error=%d", status) + } + defer i.cfRelease(uintptr(props)) + + key := i.cfStr(kIOBlockStorageDriverStatisticsKey) + defer i.cfRelease(uintptr(key)) + v := i.cfDictionaryGetValue(uintptr(props), uintptr(key)) + if v == nil { + return nil, fmt.Errorf("CFDictionaryGetValue failed") + } + + var stat IOCountersStat + statstab := map[string]uintptr{ + kIOBlockStorageDriverStatisticsBytesReadKey: unsafe.Offsetof(stat.ReadBytes), + kIOBlockStorageDriverStatisticsBytesWrittenKey: unsafe.Offsetof(stat.WriteBytes), + kIOBlockStorageDriverStatisticsReadsKey: unsafe.Offsetof(stat.ReadCount), + kIOBlockStorageDriverStatisticsWritesKey: unsafe.Offsetof(stat.WriteCount), + kIOBlockStorageDriverStatisticsTotalReadTimeKey: unsafe.Offsetof(stat.ReadTime), + kIOBlockStorageDriverStatisticsTotalWriteTimeKey: unsafe.Offsetof(stat.WriteTime), + } + + for key, off := range statstab { + s := i.cfStr(key) + defer i.cfRelease(uintptr(s)) + if num := i.cfDictionaryGetValue(uintptr(v), uintptr(s)); num != nil { + i.cfNumberGetValue(uintptr(num), common.KCFNumberSInt64Type, uintptr(unsafe.Pointer(uintptr(unsafe.Pointer(&stat))+off))) + } + } + + return &stat, nil +} + +func (i *ioCounters) cfStr(str string) unsafe.Pointer { + return i.cfStringCreateWithCString(common.KCFAllocatorDefault, str, common.KCFStringEncodingUTF8) +} diff --git a/disk/disk_darwin_cgo.go b/disk/disk_darwin_cgo.go deleted file mode 100644 index 3a98b61e5..000000000 --- a/disk/disk_darwin_cgo.go +++ /dev/null @@ -1,45 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -//go:build darwin && cgo && !ios - -package disk - -/* -#cgo LDFLAGS: -framework CoreFoundation -framework IOKit -#include -#include -#include "iostat_darwin.h" -*/ -import "C" - -import ( - "context" - - "github.com/shirou/gopsutil/v4/internal/common" -) - -func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) { - var buf [C.NDRIVE]C.DriveStats - n, err := C.gopsutil_v4_readdrivestat(&buf[0], C.int(len(buf))) - if err != nil { - return nil, err - } - ret := make(map[string]IOCountersStat, 0) - for i := 0; i < int(n); i++ { - d := IOCountersStat{ - ReadBytes: uint64(buf[i].read), - WriteBytes: uint64(buf[i].written), - ReadCount: uint64(buf[i].nread), - WriteCount: uint64(buf[i].nwrite), - ReadTime: uint64(buf[i].readtime / 1000 / 1000), // note: read/write time are in ns, but we want ms. - WriteTime: uint64(buf[i].writetime / 1000 / 1000), - IoTime: uint64((buf[i].readtime + buf[i].writetime) / 1000 / 1000), - Name: C.GoString(&buf[i].name[0]), - } - if len(names) > 0 && !common.StringsHas(names, d.Name) { - continue - } - - ret[d.Name] = d - } - return ret, nil -} diff --git a/disk/disk_darwin_nocgo.go b/disk/disk_darwin_nocgo.go deleted file mode 100644 index 8d55ca314..000000000 --- a/disk/disk_darwin_nocgo.go +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -//go:build (darwin && !cgo) || ios - -package disk - -import ( - "context" - - "github.com/shirou/gopsutil/v4/internal/common" -) - -func IOCountersWithContext(ctx context.Context, names ...string) (map[string]IOCountersStat, error) { - return nil, common.ErrNotImplementedError -} diff --git a/disk/iostat_darwin.c b/disk/iostat_darwin.c deleted file mode 100644 index ba1e4c505..000000000 --- a/disk/iostat_darwin.c +++ /dev/null @@ -1,131 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// SPDX-FileCopyrightText: Copyright (c) 2017, kadota kyohei -// https://github.com/lufia/iostat/blob/9f7362b77ad333b26c01c99de52a11bdb650ded2/iostat_darwin.c -#include -#include -#include "iostat_darwin.h" - -#define IOKIT 1 /* to get io_name_t in device_types.h */ - -#include -#include -#include -#include - -#include - -static int getdrivestat(io_registry_entry_t d, DriveStats *stat); -static int fillstat(io_registry_entry_t d, DriveStats *stat); - -int -gopsutil_v4_readdrivestat(DriveStats a[], int n) -{ - CFMutableDictionaryRef match; - io_iterator_t drives; - io_registry_entry_t d; - kern_return_t status; - int na, rv; - - match = IOServiceMatching("IOMedia"); - CFDictionaryAddValue(match, CFSTR(kIOMediaWholeKey), kCFBooleanTrue); - status = IOServiceGetMatchingServices(0, match, &drives); - if(status != KERN_SUCCESS) - return -1; - - na = 0; - while(na < n && (d=IOIteratorNext(drives)) > 0){ - rv = getdrivestat(d, &a[na]); - if(rv < 0) - return -1; - if(rv > 0) - na++; - IOObjectRelease(d); - } - IOObjectRelease(drives); - return na; -} - -static int -getdrivestat(io_registry_entry_t d, DriveStats *stat) -{ - io_registry_entry_t parent; - kern_return_t status; - CFDictionaryRef props; - CFStringRef name; - CFNumberRef num; - int rv; - - memset(stat, 0, sizeof *stat); - status = IORegistryEntryGetParentEntry(d, kIOServicePlane, &parent); - if(status != KERN_SUCCESS) - return -1; - if(!IOObjectConformsTo(parent, "IOBlockStorageDriver")){ - IOObjectRelease(parent); - return 0; - } - - status = IORegistryEntryCreateCFProperties(d, (CFMutableDictionaryRef *)&props, kCFAllocatorDefault, kNilOptions); - if(status != KERN_SUCCESS){ - IOObjectRelease(parent); - return -1; - } - name = (CFStringRef)CFDictionaryGetValue(props, CFSTR(kIOBSDNameKey)); - CFStringGetCString(name, stat->name, NAMELEN, CFStringGetSystemEncoding()); - num = (CFNumberRef)CFDictionaryGetValue(props, CFSTR(kIOMediaSizeKey)); - CFNumberGetValue(num, kCFNumberSInt64Type, &stat->size); - num = (CFNumberRef)CFDictionaryGetValue(props, CFSTR(kIOMediaPreferredBlockSizeKey)); - CFNumberGetValue(num, kCFNumberSInt64Type, &stat->blocksize); - CFRelease(props); - - rv = fillstat(parent, stat); - IOObjectRelease(parent); - if(rv < 0) - return -1; - return 1; -} - -static struct { - char *key; - size_t off; -} statstab[] = { - {kIOBlockStorageDriverStatisticsBytesReadKey, offsetof(DriveStats, read)}, - {kIOBlockStorageDriverStatisticsBytesWrittenKey, offsetof(DriveStats, written)}, - {kIOBlockStorageDriverStatisticsReadsKey, offsetof(DriveStats, nread)}, - {kIOBlockStorageDriverStatisticsWritesKey, offsetof(DriveStats, nwrite)}, - {kIOBlockStorageDriverStatisticsTotalReadTimeKey, offsetof(DriveStats, readtime)}, - {kIOBlockStorageDriverStatisticsTotalWriteTimeKey, offsetof(DriveStats, writetime)}, - {kIOBlockStorageDriverStatisticsLatentReadTimeKey, offsetof(DriveStats, readlat)}, - {kIOBlockStorageDriverStatisticsLatentWriteTimeKey, offsetof(DriveStats, writelat)}, -}; - -static int -fillstat(io_registry_entry_t d, DriveStats *stat) -{ - CFDictionaryRef props, v; - CFNumberRef num; - kern_return_t status; - typeof(statstab[0]) *bp, *ep; - - status = IORegistryEntryCreateCFProperties(d, (CFMutableDictionaryRef *)&props, kCFAllocatorDefault, kNilOptions); - if(status != KERN_SUCCESS) - return -1; - v = (CFDictionaryRef)CFDictionaryGetValue(props, CFSTR(kIOBlockStorageDriverStatisticsKey)); - if(v == NULL){ - CFRelease(props); - return -1; - } - - ep = &statstab[sizeof(statstab)/sizeof(statstab[0])]; - for(bp = &statstab[0]; bp < ep; bp++){ - CFStringRef s; - - s = CFStringCreateWithCString(kCFAllocatorDefault, bp->key, CFStringGetSystemEncoding()); - num = (CFNumberRef)CFDictionaryGetValue(v, s); - if(num) - CFNumberGetValue(num, kCFNumberSInt64Type, ((char*)stat)+bp->off); - CFRelease(s); - } - - CFRelease(props); - return 0; -} diff --git a/disk/iostat_darwin.h b/disk/iostat_darwin.h deleted file mode 100644 index 7b702aaa0..000000000 --- a/disk/iostat_darwin.h +++ /dev/null @@ -1,34 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -// SPDX-FileCopyrightText: Copyright (c) 2017, kadota kyohei -// https://github.com/lufia/iostat/blob/9f7362b77ad333b26c01c99de52a11bdb650ded2/iostat_darwin.h -typedef struct DriveStats DriveStats; -typedef struct CPUStats CPUStats; - -enum { - NDRIVE = 16, - NAMELEN = 31 -}; - -struct DriveStats { - char name[NAMELEN+1]; - int64_t size; - int64_t blocksize; - - int64_t read; - int64_t written; - int64_t nread; - int64_t nwrite; - int64_t readtime; - int64_t writetime; - int64_t readlat; - int64_t writelat; -}; - -struct CPUStats { - natural_t user; - natural_t nice; - natural_t sys; - natural_t idle; -}; - -extern int gopsutil_v4_readdrivestat(DriveStats a[], int n); diff --git a/internal/common/common_darwin.go b/internal/common/common_darwin.go index 0a1da931b..673024637 100644 --- a/internal/common/common_darwin.go +++ b/internal/common/common_darwin.go @@ -78,7 +78,7 @@ type Library struct { const ( IOKit = "/System/Library/Frameworks/IOKit.framework/IOKit" CoreFoundation = "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation" - Kernel = "/usr/lib/system/libsystem_kernel.dylib" + System = "/usr/lib/libSystem.B.dylib" ) func NewLibrary(path string) (*Library, error) { @@ -119,12 +119,19 @@ const ( // IOKit functions and symbols. type ( - IOServiceGetMatchingServiceFunc func(mainPort uint32, matching uintptr) uint32 - IOServiceMatchingFunc func(name string) unsafe.Pointer - IOServiceOpenFunc func(service, owningTask, connType uint32, connect *uint32) int - IOServiceCloseFunc func(connect uint32) int - IOObjectReleaseFunc func(object uint32) int - IOConnectCallStructMethodFunc func(connection, selector uint32, inputStruct, inputStructCnt, outputStruct uintptr, outputStructCnt *uintptr) int + IOServiceGetMatchingServiceFunc func(mainPort uint32, matching uintptr) uint32 + IOServiceGetMatchingServicesFunc func(mainPort uint32, matching uintptr, existing *uint32) int + IOServiceMatchingFunc func(name string) unsafe.Pointer + IOServiceOpenFunc func(service, owningTask, connType uint32, connect *uint32) int + IOServiceCloseFunc func(connect uint32) int + IOIteratorNextFunc func(iterator uint32) uint32 + IORegistryEntryGetNameFunc func(entry uint32, name *byte) int + IORegistryEntryGetParentEntryFunc func(entry uint32, plane string, parent *uint32) int + IORegistryEntryCreateCFPropertyFunc func(entry uint32, key, allocator uintptr, options uint32) unsafe.Pointer + IORegistryEntryCreateCFPropertiesFunc func(entry uint32, properties, allocator uintptr, options uint32) int + IOObjectConformsToFunc func(object uint32, className string) bool + IOObjectReleaseFunc func(object uint32) int + IOConnectCallStructMethodFunc func(connection, selector uint32, inputStruct, inputStructCnt, outputStruct uintptr, outputStructCnt *uintptr) int IOHIDEventSystemClientCreateFunc func(allocator uintptr) unsafe.Pointer IOHIDEventSystemClientSetMatchingFunc func(client, match uintptr) int @@ -136,12 +143,19 @@ type ( ) const ( - IOServiceGetMatchingServiceSym = "IOServiceGetMatchingService" - IOServiceMatchingSym = "IOServiceMatching" - IOServiceOpenSym = "IOServiceOpen" - IOServiceCloseSym = "IOServiceClose" - IOObjectReleaseSym = "IOObjectRelease" - IOConnectCallStructMethodSym = "IOConnectCallStructMethod" + 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" @@ -152,49 +166,77 @@ const ( ) const ( + KIOMainPortDefault = 0 + KIOHIDEventTypeTemperature = 15 + + KNilOptions = 0 +) + +const ( + KIOMediaWholeKey = "Media" + KIOServicePlane = "IOService" ) // CoreFoundation functions and symbols. type ( + CFGetTypeIDFunc func(cf uintptr) int32 CFNumberCreateFunc func(allocator uintptr, theType int32, valuePtr uintptr) unsafe.Pointer + CFNumberGetValueFunc func(num uintptr, theType int32, valuePtr uintptr) bool CFDictionaryCreateFunc func(allocator uintptr, keys, values *unsafe.Pointer, numValues int32, keyCallBacks, valueCallBacks uintptr) unsafe.Pointer + CFDictionaryAddValueFunc func(theDict, key, value uintptr) + CFDictionaryGetValueFunc func(theDict, key uintptr) unsafe.Pointer CFArrayGetCountFunc func(theArray uintptr) int32 CFArrayGetValueAtIndexFunc func(theArray uintptr, index int32) unsafe.Pointer CFStringCreateMutableFunc func(alloc uintptr, maxLength int32) unsafe.Pointer CFStringGetLengthFunc func(theString uintptr) int32 CFStringGetCStringFunc func(theString uintptr, buffer *byte, bufferSize int32, encoding uint32) CFStringCreateWithCStringFunc func(alloc uintptr, cStr string, encoding uint32) unsafe.Pointer + CFDataGetLengthFunc func(theData uintptr) int32 + CFDataGetBytePtrFunc func(theData uintptr) unsafe.Pointer 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 KCFNumberIntType = 9 KCFAllocatorDefault = 0 ) // Kernel functions and symbols. +type MachTimeBaseInfo struct { + Numer uint32 + Denom uint32 +} + type ( HostProcessorInfoFunc func(host uint32, flavor int, outProcessorCount *uint32, outProcessorInfo uintptr, outProcessorInfoCnt *uint32) int - HostStatisticsFunc func(host uint32, flavor int, hostInfoOut uintptr, hostInfoOutCnt *uint32) int - MachHostSelfFunc func() uint32 - MachTaskSelfFunc func() uint32 - VMDeallocateFunc func(targetTask uint32, vmAddress, vmSize uintptr) int + HostStatisticsFunc func(host uint32, flavor int, hostInfoOut uintptr, hostInfoOutCnt *uint32) int + MachHostSelfFunc func() uint32 + MachTaskSelfFunc func() uint32 + MachTimeBaseInfoFunc func(info *MachTimeBaseInfo) int + VMDeallocateFunc func(targetTask uint32, vmAddress, vmSize uintptr) int ) const ( @@ -206,12 +248,26 @@ const ( ) const ( + CTL_KERN = 1 + KERN_ARGMAX = 8 + HOST_VM_INFO = 2 HOST_CPU_LOAD_INFO = 3 HOST_VM_INFO_COUNT = 0xf ) +// System functions and symbols. +type ( + SysctlFunc func(name *int, namelen uint32, oldp uintptr, oldlenp *uintptr, newp, newlenp uintptr) bool + ProcPidPathFunc func(pid int, buffer uintptr, bufferSize uint32) int +) + +const ( + SysctlSym = "sysctl" + ProcPidPathSym = "proc_pidpath" +) + // SMC represents a SMC instance. type SMC struct { lib *Library @@ -281,3 +337,18 @@ func (s *SMC) Close() error { } return nil } + +// https://github.com/ebitengine/purego/blob/main/internal/strings/strings.go#L26 +func GoString(cStr *byte) string { + if cStr == nil { + return "" + } + var length int + for { + if *(*byte)(unsafe.Add(unsafe.Pointer(cStr), uintptr(length))) == '\x00' { + break + } + length++ + } + return string(unsafe.Slice(cStr, length)) +} diff --git a/mem/mem_darwin.go b/mem/mem_darwin.go index 4442cbc11..a4c15f691 100644 --- a/mem/mem_darwin.go +++ b/mem/mem_darwin.go @@ -85,7 +85,7 @@ func VirtualMemory() (*VirtualMemoryStat, error) { } func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) { - machLib, err := common.NewLibrary(common.Kernel) + machLib, err := common.NewLibrary(common.System) if err != nil { return nil, err }