DarwinProcessList: retry getting list of all processes on ENOMEM

The process count might change between the two sysctl() calls getting
the size and getting the data.

Retry (3 times) in case the data-retrieval sysctl() call fails with ENOMEM.

see http://mirror.informatimago.com/next/developer.apple.com/qa/qa2001/qa1123.html

Related: #118
This commit is contained in:
Christian Göttsche 2020-11-17 15:17:19 +01:00 committed by cgzones
parent 6c2849ec81
commit 72df930241
1 changed files with 17 additions and 19 deletions

View File

@ -8,6 +8,7 @@ in the source distribution for its full text.
#include "DarwinProcessList.h"
#include <err.h>
#include <errno.h>
#include <libproc.h>
#include <stdbool.h>
#include <stdio.h>
@ -107,27 +108,24 @@ static struct kinfo_proc* ProcessList_getKInfoProcs(size_t* count) {
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
struct kinfo_proc* processes = NULL;
/* Note the two calls to sysctl(). One to get length and one to get the
* data. This -does- mean that the second call could end up with a missing
* process entry or two.
*/
*count = 0;
if (sysctl(mib, 4, NULL, count, NULL, 0) < 0) {
for (int retry = 3; retry > 0; retry--) {
size_t size = 0;
if (sysctl(mib, 4, NULL, &size, NULL, 0) < 0 || size == 0) {
CRT_fatalError("Unable to get size of kproc_infos");
}
processes = xMalloc(*count);
if (processes == NULL) {
CRT_fatalError("Out of memory for kproc_infos");
}
if (sysctl(mib, 4, processes, count, NULL, 0) < 0) {
CRT_fatalError("Unable to get kinfo_procs");
}
*count = *count / sizeof(struct kinfo_proc);
processes = xRealloc(processes, size);
if (sysctl(mib, 4, processes, &size, NULL, 0) == 0) {
*count = size / sizeof(struct kinfo_proc);
return processes;
}
if (errno != ENOMEM)
break;
}
CRT_fatalError("Unable to get kinfo_procs");
}
ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId) {