Swift pointer problems with MACH_TASK_BASIC_INFO

后端 未结 6 2127
一个人的身影
一个人的身影 2020-12-08 08:58

I am trying to convert an ObjC stackoverflow answer to Swift and failing. It looks like I am passing a UnsafeMutablePointer when I

6条回答
  •  情歌与酒
    2020-12-08 09:31

    When interacting with C functions, you can't rely on the compiler's error messages - break it down parameter by parameter, command-clicking until you know what you're working with. To start with, the types you're running into are:

    • task_name_t: UInt32
    • task_flavor_t: UInt32
    • task_info_t: UnsafeMutablePointer
    • UnsafeMutablePointer: UnsafeMutablePointer
    • kern_return_t - Int32

    There's one tricky Swift bit along with a bug in your code standing in your way here. First, the task_info_out parameter needs to be a UnsafeMutablePointer, but needs to actually point to an instance of mach_task_basic_info. We can get around this by creating a UnsafeMutablePointer and wrapping it in another UnsafeMutablePointer at call time - the compiler will use type inference to know we want that wrapping pointer to be sub-typed as UInt32.

    Second, you're calling sizeof(mach_task_basic_info_t) (the pointer to mach_task_basic_info) when you should be calling sizeinfo(mach_task_basic_info), so your byte count ends up too low to hold the data structure.

    On further research, this got a little more complicated. The original code for this was incorrect, in that size should be initialized to the constant MACH_TASK_BASIC_INFO_COUNT. Unfortunately, that's a macro, not a simple constant:

    #define MACH_TASK_BASIC_INFO_COUNT (sizeof(mach_task_basic_info_data_t) / sizeof(natural_t)) 
    

    Swift doesn't import those, so we'll need to redefine it ourselves. Here's working code for all this:

    // constant
    let MACH_TASK_BASIC_INFO_COUNT = (sizeof(mach_task_basic_info_data_t) / sizeof(natural_t))
    
    // prepare parameters
    let name   = mach_task_self_
    let flavor = task_flavor_t(MACH_TASK_BASIC_INFO)
    var size   = mach_msg_type_number_t(MACH_TASK_BASIC_INFO_COUNT)
    
    // allocate pointer to mach_task_basic_info
    var infoPointer = UnsafeMutablePointer.alloc(1)
    
    // call task_info - note extra UnsafeMutablePointer(...) call
    let kerr = task_info(name, flavor, UnsafeMutablePointer(infoPointer), &size)
    
    // get mach_task_basic_info struct out of pointer
    let info = infoPointer.move()
    
    // deallocate pointer
    infoPointer.dealloc(1)
    
    // check return value for success / failure
    if kerr == KERN_SUCCESS {
        println("Memory in use (in bytes): \(info.resident_size)")
    } else {
        let errorString = String(CString: mach_error_string(kerr), encoding: NSASCIIStringEncoding)
        println(errorString ?? "Error: couldn't parse error string")
    }
    

提交回复
热议问题