0

I am creating a C lib plus a wrapper for easy use in Swift. The C function takes two parameters, an array pointer and an int pointer:

int crgetproclist(struct kinfo_proc *proc_list, size_t *count) {
 int err = 0;
 size_t length = 0;
 
 static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
 
 // Call sysctl with a NULL buffer to get proper length
 err = sysctl((int *)name, (sizeof(name) / sizeof(*name)) - 1, NULL, &length, NULL, 0);
 //if (err) return [-1];
 
 // Get the actual process list
 err = sysctl((int *)name, (sizeof(name) / sizeof(*name)) - 1, proc_list, &length, NULL, 0);
 //if (err) return [-1];
 
 *count = length / sizeof(struct kinfo_proc);
 
 for (int i = 0; i < *count; i++) {
 struct kinfo_proc proc = proc_list[i];
 proc = proc;
 }
 
 return 1;
}

I call that function from my Swift wrapper:

var data: [Process] = []
override func viewDidLoad() {
 super.viewDidLoad()
 
 let proc_list: UnsafeMutablePointer<kinfo_proc> = UnsafeMutablePointer<kinfo_proc>.allocate(capacity: 500)
 var count: size_t = 0
 let result = crgetproclist(proc_list, &count)
 
 var foobar: [Process] = []
 
 if (result == 1) {
 for i in 1..<count {
 var proc: kinfo_proc = proc_list[i]
 var process = Process(proc: proc)
 foobar.append(process) // <---- works
 self.data.append(process) // <---- EXC_BAD_ACCESS ????
 }
 
 self.data.sort(by: {
 (a: Process, b: Process) -> Bool in
 return a.name.lowercased() < b.name.lowercased()
 })
 
 self.myTable.reloadData()
 }
}
class Process: NSObject {
 
 var _proc: kinfo_proc
 var pid: pid_t
 var name: String
 var icon: NSImage?
 var isAlive: Bool = false
 var uid: uid_t = 0
 
 init(proc: kinfo_proc) {
 self._proc = proc
 self.pid = proc.kp_proc.p_pid
 self.name = String(cString: crgetprocname(pid))
 self.uid = crgetuid(pid)
 
 super.init()
 }
}

Questions

  1. How to correctly create and pass an UnsafeMutablePointer to the C function? I hard coded capacity: 500 which works, but how to do it correctly without a hardcoded capacity?

  2. When I try to append it to my class variable array data it runs into a EXC_BAD_ACCESS, but when I append it to foobar which is the same type it works. Why? How to assign it to a class variable without memory error?

asked Jul 8, 2020 at 17:25

1 Answer 1

4

I can only answer the first part of your question: In order to determine the necessary allocation count for the process list you must allow that crgetproclist() is called with a NULL argument (in the same way as sysctl() can be called with a NULL argument for oldp to get the needed buffer size):

int crgetproclist(struct kinfo_proc *proc_list, size_t *count) {
 int err = 0;
 size_t length;
 static const int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
 
 if (proc_list == NULL) {
 // Call sysctl with a NULL buffer to get proper length
 length = 0;
 err = sysctl((int *)name, (sizeof(name) / sizeof(*name)), NULL, &length, NULL, 0);
 } else {
 // Get the actual process list
 length = *count * sizeof(struct kinfo_proc);
 err = sysctl((int *)name, (sizeof(name) / sizeof(*name)), proc_list, &length, NULL, 0);
 }
 if (err) return -1;
 *count = length / sizeof(struct kinfo_proc);
 return 1;
}

Now you can call that function from Swift twice: First to determine the allocation count, and then again to retrieve the process list:

var count: size_t = 0
crgetproclist(nil, &count)
let procList = UnsafeMutablePointer<kinfo_proc>.allocate(capacity: count)
if crgetproclist(procList, &count) == 1 {
 for i in 0..<count {
 let proc = procList[i]
 // ...
 }
}
procList.deallocate()

Note also that you can implement the function easily in pure Swift:

func getProcessList() -> [kinfo_proc]? {
 var name : [Int32] = [ CTL_KERN, KERN_PROC, KERN_PROC_ALL ]
 var length = size_t()
 sysctl(&name, UInt32(name.count), nil, &length, nil, 0)
 let count = length / MemoryLayout<kinfo_proc>.size
 var procList = Array(repeating: kinfo_proc(), count: count)
 let result = sysctl(&name, UInt32(name.count), &procList, &length, nil, 0)
 guard result == 0 else { return nil } // Some error ...
 return Array(procList.prefix(length / MemoryLayout<kinfo_proc>.size))
}
answered Jul 8, 2020 at 18:09
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you, also for the pure Swift implementation. Helps me to get more used to low level C data type usage in Swift.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.