3
var cpuInfo: processor_info_array_t = nil
var numCpuInfo: mach_msg_type_number_t = 0
var coresTotalUsage: Float = 0.0
var numCPUsU: natural_t = 0
let err = host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numCPUsU, &cpuInfo, &numCpuInfo);
assert(err == KERN_SUCCESS, "Failed call to host_processor_info")

Hi, I am calling the above C API host_processor_info to get process load informations from swift, no problem there. cpuInfo is a inout parameter (pointer) that, on return, will point to a structure containing the CPU information allocated by that API. The caller is reponsible for deallocating the memory; I can do that easily from objective C but haven't had any luck in swift. I know I could wrap that call into an objective C extension but I'm trying to learn swift and would like, if possible, avoid the obj-c solution.

in obj-c I would deallocate with:

size_t cpuInfoSize = sizeof(integer_t) * numCpuInfo;
vm_deallocate(mach_task_self(), (vm_address_t) cpuInfo, cpuInfoSize)

cpuInfo in swift is an UnsafeMutablePointer not convertible into a vm_address_t.

Any help appreciated, thanks.

Pippo
  • 31
  • 1

2 Answers2

5

processor_info_array_t is a pointer type, and vm_address_t is an integer type (ultimately an alias for UInt). (Judging from the comments in <i386/vm_types.h> this might to be for historical reasons.) The only way to convert a pointer to an integer (of the same size) in Swift is unsafeBitCast.

mach_init.h defines

extern mach_port_t      mach_task_self_;
#define mach_task_self() mach_task_self_

Only the extern variable is visible in Swift, not the macro.

This gives:

let cpuInfoSize = vm_size_t(sizeof(integer_t)) * vm_size_t(numCpuInfo)
vm_deallocate(mach_task_self_, unsafeBitCast(cpuInfo, vm_address_t.self), cpuInfoSize)
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • `var prevCpuInfoSize: vm_size_t = UInt(UInt32(sizeof(integer_t)) * numPrevCpuInfo) as vm_size_t vm_deallocate(mach_task_self_, unsafeBitCast(prevCpuInfo, vm_address_t.self), prevCpuInfoSize)` Thank you Martin! Small modification but that pretty much works, no more memory leaks. I didn't quite get why just the extern variable is visible in swift and not the macro. – Pippo Oct 25 '14 at 18:37
  • @Pippo: Some (Objective-)C macros are imported and some are not, compare http://stackoverflow.com/questions/24325477/how-to-use-a-objective-c-define-from-swift. – Martin R Oct 25 '14 at 18:48
  • @Pippo: You are right, I forgot about the multiplication. I have updated the answer as a reference for future readers. – Martin R Oct 25 '14 at 18:49
  • This still works in Swift 3.1. Just wanna say a thank you, Martin! – lightpen Jun 12 '17 at 11:19
  • @lightpen: Good to know, thanks for the confirmation! – Martin R Jun 12 '17 at 11:19
3

In Swift 4, the equivalent code appears to be:

let cpuInfoSize = vm_size_t(MemoryLayout<integer_t>.stride * Int(numCpuInfo))
vm_deallocate(mach_task_self_, vm_address_t(bitPattern: cpuInfo), cpuInfoSize)

In particular, the initializer UInt(bitPattern:) is now apparently preferred to unsafeBitCast() to initialize an unsigned integer with the bit pattern of a pointer (I guess this usage is not longer considered "unsafe"). It correctly handles a nil pointer, returning 0 in this case.

rsfinn
  • 1,073
  • 14
  • 26