1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
/*
htop - DarwinProcessTable.c
(C) 2014 Hisham H. Muhammad
Released under the GNU GPLv2+, see the COPYING file
in the source distribution for its full text.
*/
#include "darwin/DarwinProcessTable.h"
#include <errno.h>
#include <libproc.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <utmpx.h>
#include <sys/mman.h>
#include <sys/sysctl.h>
#include "CRT.h"
#include "ProcessTable.h"
#include "darwin/DarwinMachine.h"
#include "darwin/DarwinProcess.h"
#include "darwin/Platform.h"
#include "darwin/PlatformHelpers.h"
#include "generic/openzfs_sysctl.h"
#include "zfs/ZfsArcStats.h"
static struct kinfo_proc* ProcessTable_getKInfoProcs(size_t* count) {
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
struct kinfo_proc* processes = NULL;
for (unsigned int retry = 0; retry < 4; 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");
}
size += 16 * retry * retry * 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");
}
ProcessTable* ProcessTable_new(Machine* host, Hashtable* pidMatchList) {
DarwinProcessTable* this = xCalloc(1, sizeof(DarwinProcessTable));
Object_setClass(this, Class(ProcessTable));
ProcessTable* super = &this->super;
ProcessTable_init(super, Class(DarwinProcess), host, pidMatchList);
return super;
}
void ProcessTable_delete(Object* cast) {
DarwinProcessTable* this = (DarwinProcessTable*) cast;
ProcessTable_done(&this->super);
free(this);
}
void ProcessTable_goThroughEntries(ProcessTable* super) {
const Machine* host = super->super.host;
const DarwinMachine* dhost = (const DarwinMachine*) host;
DarwinProcessTable* dpt = (DarwinProcessTable*) super;
bool preExisting = true;
struct kinfo_proc* ps;
size_t count;
DarwinProcess* proc;
/* Get the time difference */
dpt->global_diff = 0;
for (unsigned int i = 0; i < host->existingCPUs; ++i) {
for (size_t j = 0; j < CPU_STATE_MAX; ++j) {
dpt->global_diff += dhost->curr_load[i].cpu_ticks[j] - dhost->prev_load[i].cpu_ticks[j];
}
}
const double time_interval_ns = Platform_schedulerTicksToNanoseconds(dpt->global_diff) / (double) host->activeCPUs;
/* We use kinfo_procs for initial data since :
*
* 1) They always succeed.
* 2) They contain the basic information.
*
* We attempt to fill-in additional information with libproc.
*/
ps = ProcessTable_getKInfoProcs(&count);
for (size_t i = 0; i < count; ++i) {
proc = (DarwinProcess*)ProcessTable_getProcess(super, ps[i].kp_proc.p_pid, &preExisting, DarwinProcess_new);
DarwinProcess_setFromKInfoProc(&proc->super, &ps[i], preExisting);
DarwinProcess_setFromLibprocPidinfo(proc, dpt, time_interval_ns);
// Deduce further process states not covered in the libproc call above
if (ps[i].kp_proc.p_stat == SZOMB) {
proc->super.state = ZOMBIE;
} else if (ps[i].kp_proc.p_stat == SSTOP) {
proc->super.state = STOPPED;
}
if (proc->super.st_uid != ps[i].kp_eproc.e_ucred.cr_uid) {
proc->super.st_uid = ps[i].kp_eproc.e_ucred.cr_uid;
proc->super.user = UsersTable_getRef(host->usersTable, proc->super.st_uid);
}
// Disabled for High Sierra due to bug in macOS High Sierra
bool isScanThreadSupported = !Platform_KernelVersionIsBetween((KernelVersion) {17, 0, 0}, (KernelVersion) {17, 5, 0});
if (isScanThreadSupported) {
DarwinProcess_scanThreads(proc, dpt);
}
super->totalTasks += 1;
if (!preExisting) {
ProcessTable_add(super, &proc->super);
}
}
free(ps);
}
|