diff options
author | Daniel Lange <DLange@git.local> | 2021-09-21 08:35:19 +0200 |
---|---|---|
committer | Daniel Lange <DLange@git.local> | 2021-09-21 08:35:19 +0200 |
commit | 69f439eff387a6ecb52734e400b297a3c85f2285 (patch) | |
tree | 2a988b7868b749654796183ba70b4272965da1bf /darwin | |
parent | c55320e9e2a8916e911bcd39ab37b79e3a7d03b2 (diff) | |
download | debian_htop-69f439eff387a6ecb52734e400b297a3c85f2285.tar.gz debian_htop-69f439eff387a6ecb52734e400b297a3c85f2285.tar.bz2 debian_htop-69f439eff387a6ecb52734e400b297a3c85f2285.zip |
New upstream version 3.1.0upstream/3.1.0
Diffstat (limited to 'darwin')
-rw-r--r-- | darwin/DarwinProcess.c | 131 | ||||
-rw-r--r-- | darwin/DarwinProcess.h | 7 | ||||
-rw-r--r-- | darwin/DarwinProcessList.c | 43 | ||||
-rw-r--r-- | darwin/DarwinProcessList.h | 4 | ||||
-rw-r--r-- | darwin/Platform.c | 178 | ||||
-rw-r--r-- | darwin/Platform.h | 68 | ||||
-rw-r--r-- | darwin/ProcessField.h | 2 |
7 files changed, 284 insertions, 149 deletions
diff --git a/darwin/DarwinProcess.c b/darwin/DarwinProcess.c index bedfefe..20e91f7 100644 --- a/darwin/DarwinProcess.c +++ b/darwin/DarwinProcess.c @@ -5,7 +5,7 @@ Released under the GNU GPLv2, see the COPYING file in the source distribution for its full text. */ -#include "DarwinProcess.h" +#include "darwin/DarwinProcess.h" #include <libproc.h> #include <stdio.h> @@ -14,8 +14,8 @@ in the source distribution for its full text. #include <mach/mach.h> #include "CRT.h" -#include "Platform.h" #include "Process.h" +#include "darwin/Platform.h" const ProcessFieldData Process_fields[LAST_PROCESSFIELD] = { @@ -26,24 +26,27 @@ const ProcessFieldData Process_fields[LAST_PROCESSFIELD] = { [PPID] = { .name = "PPID", .title = "PPID", .description = "Parent process ID", .flags = 0, .pidColumn = true, }, [PGRP] = { .name = "PGRP", .title = "PGRP", .description = "Process group ID", .flags = 0, .pidColumn = true, }, [SESSION] = { .name = "SESSION", .title = "SID", .description = "Process's session ID", .flags = 0, .pidColumn = true, }, - [TTY_NR] = { .name = "TTY_NR", .title = " TTY ", .description = "Controlling terminal", .flags = 0, }, + [TTY] = { .name = "TTY", .title = "TTY ", .description = "Controlling terminal", .flags = 0, }, [TPGID] = { .name = "TPGID", .title = "TPGID", .description = "Process ID of the fg process group of the controlling terminal", .flags = 0, .pidColumn = true, }, - [MINFLT] = { .name = "MINFLT", .title = " MINFLT ", .description = "Number of minor faults which have not required loading a memory page from disk", .flags = 0, }, - [MAJFLT] = { .name = "MAJFLT", .title = " MAJFLT ", .description = "Number of major faults which have required loading a memory page from disk", .flags = 0, }, + [MINFLT] = { .name = "MINFLT", .title = " MINFLT ", .description = "Number of minor faults which have not required loading a memory page from disk", .flags = 0, .defaultSortDesc = true, }, + [MAJFLT] = { .name = "MAJFLT", .title = " MAJFLT ", .description = "Number of major faults which have required loading a memory page from disk", .flags = 0, .defaultSortDesc = true, }, [PRIORITY] = { .name = "PRIORITY", .title = "PRI ", .description = "Kernel's internal priority for the process", .flags = 0, }, [NICE] = { .name = "NICE", .title = " NI ", .description = "Nice value (the higher the value, the more it lets other processes take priority)", .flags = 0, }, [STARTTIME] = { .name = "STARTTIME", .title = "START ", .description = "Time the process was started", .flags = 0, }, - + [ELAPSED] = { .name = "ELAPSED", .title = "ELAPSED ", .description = "Time since the process was started", .flags = 0, }, [PROCESSOR] = { .name = "PROCESSOR", .title = "CPU ", .description = "Id of the CPU the process last executed on", .flags = 0, }, - [M_VIRT] = { .name = "M_VIRT", .title = " VIRT ", .description = "Total program size in virtual memory", .flags = 0, }, - [M_RESIDENT] = { .name = "M_RESIDENT", .title = " RES ", .description = "Resident set size, size of the text and data sections, plus stack usage", .flags = 0, }, + [M_VIRT] = { .name = "M_VIRT", .title = " VIRT ", .description = "Total program size in virtual memory", .flags = 0, .defaultSortDesc = true, }, + [M_RESIDENT] = { .name = "M_RESIDENT", .title = " RES ", .description = "Resident set size, size of the text and data sections, plus stack usage", .flags = 0, .defaultSortDesc = true, }, [ST_UID] = { .name = "ST_UID", .title = " UID ", .description = "User ID of the process owner", .flags = 0, }, - [PERCENT_CPU] = { .name = "PERCENT_CPU", .title = "CPU% ", .description = "Percentage of the CPU time the process used in the last sampling", .flags = 0, }, - [PERCENT_MEM] = { .name = "PERCENT_MEM", .title = "MEM% ", .description = "Percentage of the memory the process is using, based on resident memory size", .flags = 0, }, + [PERCENT_CPU] = { .name = "PERCENT_CPU", .title = "CPU% ", .description = "Percentage of the CPU time the process used in the last sampling", .flags = 0, .defaultSortDesc = true, }, + [PERCENT_NORM_CPU] = { .name = "PERCENT_NORM_CPU", .title = "NCPU%", .description = "Normalized percentage of the CPU time the process used in the last sampling (normalized by cpu count)", .flags = 0, .defaultSortDesc = true, }, + [PERCENT_MEM] = { .name = "PERCENT_MEM", .title = "MEM% ", .description = "Percentage of the memory the process is using, based on resident memory size", .flags = 0, .defaultSortDesc = true, }, [USER] = { .name = "USER", .title = "USER ", .description = "Username of the process owner (or user ID if name cannot be determined)", .flags = 0, }, - [TIME] = { .name = "TIME", .title = " TIME+ ", .description = "Total time the process has spent in user and system time", .flags = 0, }, + [TIME] = { .name = "TIME", .title = " TIME+ ", .description = "Total time the process has spent in user and system time", .flags = 0, .defaultSortDesc = true, }, [NLWP] = { .name = "NLWP", .title = "NLWP ", .description = "Number of threads in the process", .flags = 0, }, [TGID] = { .name = "TGID", .title = "TGID", .description = "Thread group ID (i.e. process ID)", .flags = 0, .pidColumn = true, }, + [PROC_EXE] = { .name = "EXE", .title = "EXE ", .description = "Basename of exe of the process from /proc/[pid]/exe", .flags = 0, }, + [CWD] = { .name = "CWD", .title = "CWD ", .description = "The current working directory of the process", .flags = PROCESS_FLAG_CWD, }, [TRANSLATED] = { .name = "TRANSLATED", .title = "T ", .description = "Translation info (T translated, N native)", .flags = 0, }, }; @@ -95,16 +98,42 @@ static int DarwinProcess_compareByKey(const Process* v1, const Process* v2, Proc } } -bool Process_isThread(const Process* this) { - (void) this; - return false; +static void DarwinProcess_updateExe(pid_t pid, Process* proc) { + char path[PROC_PIDPATHINFO_MAXSIZE]; + + int r = proc_pidpath(pid, path, sizeof(path)); + if (r <= 0) + return; + + Process_updateExe(proc, path); } -static char* DarwinProcess_getCmdLine(const struct kinfo_proc* k, int* basenameOffset) { +static void DarwinProcess_updateCwd(pid_t pid, Process* proc) { + struct proc_vnodepathinfo vpi; + + int r = proc_pidinfo(pid, PROC_PIDVNODEPATHINFO, 0, &vpi, sizeof(vpi)); + if (r <= 0) { + free(proc->procCwd); + proc->procCwd = NULL; + return; + } + + if (!vpi.pvi_cdir.vip_path[0]) { + free(proc->procCwd); + proc->procCwd = NULL; + return; + } + + free_and_xStrdup(&proc->procCwd, vpi.pvi_cdir.vip_path); +} + +static void DarwinProcess_updateCmdLine(const struct kinfo_proc* k, Process* proc) { + Process_updateComm(proc, k->kp_proc.p_comm); + /* This function is from the old Mac version of htop. Originally from ps? */ int mib[3], argmax, nargs, c = 0; size_t size; - char *procargs, *sp, *np, *cp, *retval; + char *procargs, *sp, *np, *cp; /* Get the maximum process arguments size. */ mib[0] = CTL_KERN; @@ -198,7 +227,7 @@ static char* DarwinProcess_getCmdLine(const struct kinfo_proc* k, int* basenameO /* Save where the argv[0] string starts. */ sp = cp; - *basenameOffset = 0; + int end = 0; for ( np = NULL; c < nargs && cp < &procargs[size]; cp++ ) { if ( *cp == '\0' ) { c++; @@ -208,8 +237,8 @@ static char* DarwinProcess_getCmdLine(const struct kinfo_proc* k, int* basenameO } /* Note location of current '\0'. */ np = cp; - if (*basenameOffset == 0) { - *basenameOffset = cp - sp; + if (end == 0) { + end = cp - sp; } } } @@ -222,25 +251,29 @@ static char* DarwinProcess_getCmdLine(const struct kinfo_proc* k, int* basenameO /* Empty or unterminated string. */ goto ERROR_B; } - if (*basenameOffset == 0) { - *basenameOffset = np - sp; + if (end == 0) { + end = np - sp; } - /* Make a copy of the string. */ - retval = xStrdup(sp); + Process_updateCmdline(proc, sp, 0, end); /* Clean up. */ free( procargs ); - return retval; + return; ERROR_B: free( procargs ); + ERROR_A: - retval = xStrdup(k->kp_proc.p_comm); - *basenameOffset = strlen(retval); + Process_updateCmdline(proc, k->kp_proc.p_comm, 0, strlen(k->kp_proc.p_comm)); +} - return retval; +// Converts nanoseconds to hundredths of a second (centiseconds) as needed by the "time" field of the Process struct. +static long long int nanosecondsToCentiseconds(uint64_t nanoseconds) { + const uint64_t centiseconds_per_second = 100; + const uint64_t nanoseconds_per_second = 1e9; + return nanoseconds / nanoseconds_per_second * centiseconds_per_second; } void DarwinProcess_setFromKInfoProc(Process* proc, const struct kinfo_proc* ps, bool exists) { @@ -270,16 +303,28 @@ void DarwinProcess_setFromKInfoProc(Process* proc, const struct kinfo_proc* ps, proc->session = 0; /* TODO Get the session id */ proc->tpgid = ps->kp_eproc.e_tpgid; proc->tgid = proc->pid; - proc->st_uid = ps->kp_eproc.e_ucred.cr_uid; - /* e_tdev = (major << 24) | (minor & 0xffffff) */ - /* e_tdev == -1 for "no device" */ - proc->tty_nr = ps->kp_eproc.e_tdev & 0xff; /* TODO tty_nr is unsigned */ + proc->isKernelThread = false; + proc->isUserlandThread = false; dp->translated = ps->kp_proc.p_flag & P_TRANSLATED; + proc->tty_nr = ps->kp_eproc.e_tdev; + const char* name = (ps->kp_eproc.e_tdev != NODEV) ? devname(ps->kp_eproc.e_tdev, S_IFCHR) : NULL; + if (!name) { + free(proc->tty_name); + proc->tty_name = NULL; + } else { + free_and_xStrdup(&proc->tty_name, name); + } + proc->starttime_ctime = ep->p_starttime.tv_sec; Process_fillStarttimeBuffer(proc); - proc->comm = DarwinProcess_getCmdLine(ps, &(proc->basenameOffset)); + DarwinProcess_updateExe(ep->p_pid, proc); + DarwinProcess_updateCmdLine(ps, proc); + + if (proc->settings->flags & PROCESS_FLAG_CWD) { + DarwinProcess_updateCwd(ep->p_pid, proc); + } } /* Mutable information */ @@ -292,21 +337,25 @@ void DarwinProcess_setFromKInfoProc(Process* proc, const struct kinfo_proc* ps, proc->updated = true; } -void DarwinProcess_setFromLibprocPidinfo(DarwinProcess* proc, DarwinProcessList* dpl, double time_interval) { +void DarwinProcess_setFromLibprocPidinfo(DarwinProcess* proc, DarwinProcessList* dpl, double timeIntervalNS) { struct proc_taskinfo pti; if (sizeof(pti) == proc_pidinfo(proc->super.pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti))) { - uint64_t total_existing_time = proc->stime + proc->utime; - uint64_t total_current_time = pti.pti_total_system + pti.pti_total_user; + uint64_t total_existing_time_ns = proc->stime + proc->utime; + + uint64_t user_time_ns = Platform_machTicksToNanoseconds(pti.pti_total_user); + uint64_t system_time_ns = Platform_machTicksToNanoseconds(pti.pti_total_system); + + uint64_t total_current_time_ns = user_time_ns + system_time_ns; - if (total_existing_time && 1E-6 < time_interval) { - uint64_t total_time_diff = total_current_time - total_existing_time; - proc->super.percent_cpu = ((double)total_time_diff / time_interval) * 100.0; + if (total_existing_time_ns && 1E-6 < timeIntervalNS) { + uint64_t total_time_diff_ns = total_current_time_ns - total_existing_time_ns; + proc->super.percent_cpu = ((double)total_time_diff_ns / timeIntervalNS) * 100.0; } else { proc->super.percent_cpu = 0.0; } - proc->super.time = total_current_time / 10000000; + proc->super.time = nanosecondsToCentiseconds(total_current_time_ns); proc->super.nlwp = pti.pti_threadnum; proc->super.m_virt = pti.pti_virtual_size / ONE_K; proc->super.m_resident = pti.pti_resident_size / ONE_K; @@ -314,8 +363,8 @@ void DarwinProcess_setFromLibprocPidinfo(DarwinProcess* proc, DarwinProcessList* proc->super.percent_mem = (double)pti.pti_resident_size * 100.0 / (double)dpl->host_info.max_mem; - proc->stime = pti.pti_total_system; - proc->utime = pti.pti_total_user; + proc->stime = system_time_ns; + proc->utime = user_time_ns; dpl->super.kernelThreads += 0; /*pti.pti_threads_system;*/ dpl->super.userlandThreads += pti.pti_threadnum; /*pti.pti_threads_user;*/ diff --git a/darwin/DarwinProcess.h b/darwin/DarwinProcess.h index f87dd18..0a49eea 100644 --- a/darwin/DarwinProcess.h +++ b/darwin/DarwinProcess.h @@ -9,9 +9,8 @@ in the source distribution for its full text. #include <sys/sysctl.h> -#include "DarwinProcessList.h" #include "Settings.h" - +#include "darwin/DarwinProcessList.h" typedef struct DarwinProcess_ { Process super; @@ -30,11 +29,9 @@ Process* DarwinProcess_new(const Settings* settings); void Process_delete(Object* cast); -bool Process_isThread(const Process* this); - void DarwinProcess_setFromKInfoProc(Process* proc, const struct kinfo_proc* ps, bool exists); -void DarwinProcess_setFromLibprocPidinfo(DarwinProcess* proc, DarwinProcessList* dpl, double time_interval); +void DarwinProcess_setFromLibprocPidinfo(DarwinProcess* proc, DarwinProcessList* dpl, double timeIntervalNS); /* * Scan threads for process state information. diff --git a/darwin/DarwinProcessList.c b/darwin/DarwinProcessList.c index 4333710..7dd86ff 100644 --- a/darwin/DarwinProcessList.c +++ b/darwin/DarwinProcessList.c @@ -5,7 +5,7 @@ Released under the GNU GPLv2, see the COPYING file in the source distribution for its full text. */ -#include "DarwinProcessList.h" +#include "darwin/DarwinProcessList.h" #include <errno.h> #include <libproc.h> @@ -19,10 +19,10 @@ in the source distribution for its full text. #include <sys/sysctl.h> #include "CRT.h" -#include "DarwinProcess.h" -#include "Platform.h" #include "ProcessList.h" -#include "zfs/openzfs_sysctl.h" +#include "darwin/DarwinProcess.h" +#include "darwin/Platform.h" +#include "generic/openzfs_sysctl.h" #include "zfs/ZfsArcStats.h" @@ -128,13 +128,15 @@ static struct kinfo_proc* ProcessList_getKInfoProcs(size_t* count) { CRT_fatalError("Unable to get kinfo_procs"); } -ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId) { +ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* dynamicColumns, Hashtable* pidMatchList, uid_t userId) { DarwinProcessList* this = xCalloc(1, sizeof(DarwinProcessList)); - ProcessList_init(&this->super, Class(DarwinProcess), usersTable, pidMatchList, userId); + ProcessList_init(&this->super, Class(DarwinProcess), usersTable, dynamicMeters, dynamicColumns, pidMatchList, userId); /* Initialize the CPU information */ - this->super.cpuCount = ProcessList_allocateCPULoadInfo(&this->prev_load); + this->super.activeCPUs = ProcessList_allocateCPULoadInfo(&this->prev_load); + // TODO: support offline CPUs and hot swapping + this->super.existingCPUs = this->super.activeCPUs; ProcessList_getHostInfo(&this->host_info); ProcessList_allocateCPULoadInfo(&this->curr_load); @@ -158,11 +160,6 @@ void ProcessList_delete(ProcessList* this) { free(this); } -static double ticksToNanoseconds(const double ticks) { - const double nanos_per_sec = 1e9; - return (ticks / Platform_timebaseToNS) * (nanos_per_sec / (double) Platform_clockTicksPerSec); -} - void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) { DarwinProcessList* dpl = (DarwinProcessList*)super; bool preExisting = true; @@ -184,13 +181,13 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) { /* Get the time difference */ dpl->global_diff = 0; - for (int i = 0; i < dpl->super.cpuCount; ++i) { + for (unsigned int i = 0; i < dpl->super.existingCPUs; ++i) { for (size_t j = 0; j < CPU_STATE_MAX; ++j) { dpl->global_diff += dpl->curr_load[i].cpu_ticks[j] - dpl->prev_load[i].cpu_ticks[j]; } } - const double time_interval = ticksToNanoseconds(dpl->global_diff) / (double) dpl->super.cpuCount; + const double time_interval_ns = Platform_schedulerTicksToNanoseconds(dpl->global_diff) / (double) dpl->super.activeCPUs; /* Clear the thread counts */ super->kernelThreads = 0; @@ -211,7 +208,12 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) { proc = (DarwinProcess*)ProcessList_getProcess(super, ps[i].kp_proc.p_pid, &preExisting, DarwinProcess_new); DarwinProcess_setFromKInfoProc(&proc->super, &ps[i], preExisting); - DarwinProcess_setFromLibprocPidinfo(proc, dpl, time_interval); + DarwinProcess_setFromLibprocPidinfo(proc, dpl, time_interval_ns); + + 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(super->usersTable, proc->super.st_uid); + } // Disabled for High Sierra due to bug in macOS High Sierra bool isScanThreadSupported = ! ( CompareKernelVersion(17, 0, 0) >= 0 && CompareKernelVersion(17, 5, 0) < 0); @@ -223,11 +225,18 @@ void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate) { super->totalTasks += 1; if (!preExisting) { - proc->super.user = UsersTable_getRef(super->usersTable, proc->super.st_uid); - ProcessList_add(super, &proc->super); } } free(ps); } + +bool ProcessList_isCPUonline(const ProcessList* super, unsigned int id) { + assert(id < super->existingCPUs); + + // TODO: support offline CPUs and hot swapping + (void) super; (void) id; + + return true; +} diff --git a/darwin/DarwinProcessList.h b/darwin/DarwinProcessList.h index 1ae2f2b..af1140b 100644 --- a/darwin/DarwinProcessList.h +++ b/darwin/DarwinProcessList.h @@ -28,10 +28,12 @@ typedef struct DarwinProcessList_ { ZfsArcStats zfs; } DarwinProcessList; -ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* pidMatchList, uid_t userId); +ProcessList* ProcessList_new(UsersTable* usersTable, Hashtable* dynamicMeters, Hashtable* dynamicColumns, Hashtable* pidMatchList, uid_t userId); void ProcessList_delete(ProcessList* this); void ProcessList_goThroughEntries(ProcessList* super, bool pauseProcessUpdate); +bool ProcessList_isCPUonline(const ProcessList* super, unsigned int id); + #endif diff --git a/darwin/Platform.c b/darwin/Platform.c index a4ed464..93262bb 100644 --- a/darwin/Platform.c +++ b/darwin/Platform.c @@ -8,7 +8,7 @@ in the source distribution for its full text. #include "config.h" // IWYU pragma: keep -#include "Platform.h" +#include "darwin/Platform.h" #include <errno.h> #include <math.h> @@ -22,20 +22,26 @@ in the source distribution for its full text. #include "ClockMeter.h" #include "CPUMeter.h" #include "CRT.h" -#include "DarwinProcessList.h" #include "DateMeter.h" #include "DateTimeMeter.h" #include "HostnameMeter.h" #include "LoadAverageMeter.h" #include "Macros.h" #include "MemoryMeter.h" +#include "MemorySwapMeter.h" #include "ProcessLocksScreen.h" #include "SwapMeter.h" +#include "SysArchMeter.h" #include "TasksMeter.h" #include "UptimeMeter.h" +#include "darwin/DarwinProcessList.h" #include "zfs/ZfsArcMeter.h" #include "zfs/ZfsCompressedArcMeter.h" +#ifdef HAVE_HOST_GET_CLOCK_SERVICE +#include <mach/clock.h> +#include <mach/mach.h> +#endif #ifdef HAVE_MACH_MACH_TIME_H #include <mach/mach_time.h> #endif @@ -90,9 +96,11 @@ const MeterClass* const Platform_meterTypes[] = { &LoadMeter_class, &MemoryMeter_class, &SwapMeter_class, + &MemorySwapMeter_class, &TasksMeter_class, &BatteryMeter_class, &HostnameMeter_class, + &SysArchMeter_class, &UptimeMeter_class, &AllCPUsMeter_class, &AllCPUs2Meter_class, @@ -112,9 +120,9 @@ const MeterClass* const Platform_meterTypes[] = { NULL }; -double Platform_timebaseToNS = 1.0; +static double Platform_nanosecondsPerMachTick = 1.0; -long Platform_clockTicksPerSec = -1; +static double Platform_nanosecondsPerSchedulerTick = -1; void Platform_init(void) { // Check if we can determine the timebase used on this system. @@ -122,18 +130,33 @@ void Platform_init(void) { #ifdef HAVE_MACH_TIMEBASE_INFO mach_timebase_info_data_t info; mach_timebase_info(&info); - Platform_timebaseToNS = (double)info.numer / (double)info.denom; + Platform_nanosecondsPerMachTick = (double)info.numer / (double)info.denom; #else - Platform_timebaseToNS = 1.0; + Platform_nanosecondsPerMachTick = 1.0; #endif - // Determine the number of clock ticks per second + // Determine the number of scheduler clock ticks per second errno = 0; - Platform_clockTicksPerSec = sysconf(_SC_CLK_TCK); + long scheduler_ticks_per_sec = sysconf(_SC_CLK_TCK); - if (errno || Platform_clockTicksPerSec < 1) { + if (errno || scheduler_ticks_per_sec < 1) { CRT_fatalError("Unable to retrieve clock tick rate"); } + + const double nanos_per_sec = 1e9; + Platform_nanosecondsPerSchedulerTick = nanos_per_sec / scheduler_ticks_per_sec; +} + +// Converts ticks in the Mach "timebase" to nanoseconds. +// See `mach_timebase_info`, as used to define the `Platform_nanosecondsPerMachTick` constant. +uint64_t Platform_machTicksToNanoseconds(uint64_t mach_ticks) { + return (uint64_t) ((double) mach_ticks * Platform_nanosecondsPerMachTick); +} + +// Converts "scheduler ticks" to nanoseconds. +// See `sysconf(_SC_CLK_TCK)`, as used to define the `Platform_nanosecondsPerSchedulerTick` constant. +double Platform_schedulerTicksToNanoseconds(const double scheduler_ticks) { + return scheduler_ticks * Platform_nanosecondsPerSchedulerTick; } void Platform_done(void) { @@ -180,24 +203,24 @@ int Platform_getMaxPid() { static double Platform_setCPUAverageValues(Meter* mtr) { const ProcessList* dpl = mtr->pl; - int cpus = dpl->cpuCount; + unsigned int activeCPUs = dpl->activeCPUs; double sumNice = 0.0; double sumNormal = 0.0; double sumKernel = 0.0; double sumPercent = 0.0; - for (int i = 1; i <= cpus; i++) { + for (unsigned int i = 1; i <= dpl->existingCPUs; i++) { sumPercent += Platform_setCPUValues(mtr, i); sumNice += mtr->values[CPU_METER_NICE]; sumNormal += mtr->values[CPU_METER_NORMAL]; sumKernel += mtr->values[CPU_METER_KERNEL]; } - mtr->values[CPU_METER_NICE] = sumNice / cpus; - mtr->values[CPU_METER_NORMAL] = sumNormal / cpus; - mtr->values[CPU_METER_KERNEL] = sumKernel / cpus; - return sumPercent / cpus; + mtr->values[CPU_METER_NICE] = sumNice / activeCPUs; + mtr->values[CPU_METER_NORMAL] = sumNormal / activeCPUs; + mtr->values[CPU_METER_KERNEL] = sumKernel / activeCPUs; + return sumPercent / activeCPUs; } -double Platform_setCPUValues(Meter* mtr, int cpu) { +double Platform_setCPUValues(Meter* mtr, unsigned int cpu) { if (cpu == 0) { return Platform_setCPUAverageValues(mtr); @@ -239,7 +262,9 @@ void Platform_setMemoryValues(Meter* mtr) { mtr->total = dpl->host_info.max_mem / 1024; mtr->values[0] = (double)(vm->active_count + vm->wire_count) * page_K; mtr->values[1] = (double)vm->purgeable_count * page_K; - mtr->values[2] = (double)vm->inactive_count * page_K; + // mtr->values[2] = "shared memory, like tmpfs and shm" + mtr->values[3] = (double)vm->inactive_count * page_K; + // mtr->values[4] = "available memory" } void Platform_setSwapValues(Meter* mtr) { @@ -316,14 +341,14 @@ char* Platform_getProcessEnv(pid_t pid) { } char* Platform_getInodeFilename(pid_t pid, ino_t inode) { - (void)pid; - (void)inode; - return NULL; + (void)pid; + (void)inode; + return NULL; } FileLocks_ProcessData* Platform_getProcessLocks(pid_t pid) { - (void)pid; - return NULL; + (void)pid; + return NULL; } bool Platform_getDiskIO(DiskIOData* data) { @@ -332,78 +357,83 @@ bool Platform_getDiskIO(DiskIOData* data) { return false; } -bool Platform_getNetworkIO(unsigned long int* bytesReceived, - unsigned long int* packetsReceived, - unsigned long int* bytesTransmitted, - unsigned long int* packetsTransmitted) { +bool Platform_getNetworkIO(NetworkIOData* data) { // TODO - *bytesReceived = 0; - *packetsReceived = 0; - *bytesTransmitted = 0; - *packetsTransmitted = 0; + (void)data; return false; } void Platform_getBattery(double* percent, ACPresence* isOnAC) { - CFTypeRef power_sources = IOPSCopyPowerSourcesInfo(); - *percent = NAN; *isOnAC = AC_ERROR; - if (NULL == power_sources) - return; + CFArrayRef list = NULL; - CFArrayRef list = IOPSCopyPowerSourcesList(power_sources); - CFDictionaryRef battery = NULL; - int len; - - if (NULL == list) { - CFRelease(power_sources); + CFTypeRef power_sources = IOPSCopyPowerSourcesInfo(); + if (!power_sources) + goto cleanup; - return; - } + list = IOPSCopyPowerSourcesList(power_sources); + if (!list) + goto cleanup; - len = CFArrayGetCount(list); + double cap_current = 0.0; + double cap_max = 0.0; /* Get the battery */ - for (int i = 0; i < len && battery == NULL; ++i) { - CFDictionaryRef candidate = IOPSGetPowerSourceDescription(power_sources, - CFArrayGetValueAtIndex(list, i)); /* GET rule */ - CFStringRef type; - - if (NULL != candidate) { - type = (CFStringRef) CFDictionaryGetValue(candidate, - CFSTR(kIOPSTransportTypeKey)); /* GET rule */ - - if (kCFCompareEqualTo == CFStringCompare(type, CFSTR(kIOPSInternalType), 0)) { - CFRetain(candidate); - battery = candidate; - } - } - } + for (int i = 0, len = CFArrayGetCount(list); i < len; ++i) { + CFDictionaryRef power_source = IOPSGetPowerSourceDescription(power_sources, CFArrayGetValueAtIndex(list, i)); /* GET rule */ + + if (!power_source) + continue; + + CFStringRef power_type = CFDictionaryGetValue(power_source, CFSTR(kIOPSTransportTypeKey)); /* GET rule */ + + if (kCFCompareEqualTo != CFStringCompare(power_type, CFSTR(kIOPSInternalType), 0)) + continue; - if (NULL != battery) { /* Determine the AC state */ - CFStringRef power_state = CFDictionaryGetValue(battery, CFSTR(kIOPSPowerSourceStateKey)); + CFStringRef power_state = CFDictionaryGetValue(power_source, CFSTR(kIOPSPowerSourceStateKey)); - *isOnAC = (kCFCompareEqualTo == CFStringCompare(power_state, CFSTR(kIOPSACPowerValue), 0)) - ? AC_PRESENT - : AC_ABSENT; + if (*isOnAC != AC_PRESENT) + *isOnAC = (kCFCompareEqualTo == CFStringCompare(power_state, CFSTR(kIOPSACPowerValue), 0)) ? AC_PRESENT : AC_ABSENT; /* Get the percentage remaining */ - double current; - double max; + double tmp; + CFNumberGetValue(CFDictionaryGetValue(power_source, CFSTR(kIOPSCurrentCapacityKey)), kCFNumberDoubleType, &tmp); + cap_current += tmp; + CFNumberGetValue(CFDictionaryGetValue(power_source, CFSTR(kIOPSMaxCapacityKey)), kCFNumberDoubleType, &tmp); + cap_max += tmp; + } - CFNumberGetValue(CFDictionaryGetValue(battery, CFSTR(kIOPSCurrentCapacityKey)), - kCFNumberDoubleType, ¤t); - CFNumberGetValue(CFDictionaryGetValue(battery, CFSTR(kIOPSMaxCapacityKey)), - kCFNumberDoubleType, &max); + if (cap_max > 0.0) + *percent = 100.0 * cap_current / cap_max; - *percent = (current * 100.0) / max; +cleanup: + if (list) + CFRelease(list); - CFRelease(battery); - } + if (power_sources) + CFRelease(power_sources); +} + +void Platform_gettime_monotonic(uint64_t* msec) { + +#ifdef HAVE_HOST_GET_CLOCK_SERVICE + + clock_serv_t cclock; + mach_timespec_t mts; + + host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock); + clock_get_time(cclock, &mts); + mach_port_deallocate(mach_task_self(), cclock); + + *msec = ((uint64_t)mts.tv_sec * 1000) + ((uint64_t)mts.tv_nsec / 1000000); + +#else + + Generic_gettime_monotonic(msec); + +#endif - CFRelease(list); - CFRelease(power_sources); } diff --git a/darwin/Platform.h b/darwin/Platform.h index 623063b..e7647db 100644 --- a/darwin/Platform.h +++ b/darwin/Platform.h @@ -14,18 +14,19 @@ in the source distribution for its full text. #include "Action.h" #include "BatteryMeter.h" #include "CPUMeter.h" -#include "DarwinProcess.h" #include "DiskIOMeter.h" +#include "Hashtable.h" +#include "NetworkIOMeter.h" #include "ProcessLocksScreen.h" #include "SignalsPanel.h" +#include "darwin/DarwinProcess.h" +#include "generic/gettime.h" +#include "generic/hostname.h" +#include "generic/uname.h" extern const ProcessField Platform_defaultFields[]; -extern double Platform_timebaseToNS; - -extern long Platform_clockTicksPerSec; - extern const SignalItem Platform_signals[]; extern const unsigned int Platform_numberOfSignals; @@ -34,6 +35,14 @@ extern const MeterClass* const Platform_meterTypes[]; void Platform_init(void); +// Converts ticks in the Mach "timebase" to nanoseconds. +// See `mach_timebase_info`, as used to define the `Platform_nanosecondsPerMachTick` constant. +uint64_t Platform_machTicksToNanoseconds(uint64_t mach_ticks); + +// Converts "scheduler ticks" to nanoseconds. +// See `sysconf(_SC_CLK_TCK)`, as used to define the `Platform_nanosecondsPerSchedulerTick` constant. +double Platform_schedulerTicksToNanoseconds(const double scheduler_ticks); + void Platform_done(void); void Platform_setBindings(Htop_Action* keys); @@ -44,7 +53,7 @@ void Platform_getLoadAverage(double* one, double* five, double* fifteen); int Platform_getMaxPid(void); -double Platform_setCPUValues(Meter* mtr, int cpu); +double Platform_setCPUValues(Meter* mtr, unsigned int cpu); void Platform_setMemoryValues(Meter* mtr); @@ -62,11 +71,48 @@ FileLocks_ProcessData* Platform_getProcessLocks(pid_t pid); bool Platform_getDiskIO(DiskIOData* data); -bool Platform_getNetworkIO(unsigned long int* bytesReceived, - unsigned long int* packetsReceived, - unsigned long int* bytesTransmitted, - unsigned long int* packetsTransmitted); +bool Platform_getNetworkIO(NetworkIOData* data); + +void Platform_getBattery(double* percent, ACPresence* isOnAC); + +static inline void Platform_getHostname(char* buffer, size_t size) { + Generic_hostname(buffer, size); +} + +static inline void Platform_getRelease(char** string) { + *string = Generic_uname(); +} + +#define PLATFORM_LONG_OPTIONS + +static inline void Platform_longOptionsUsage(ATTR_UNUSED const char* name) { } + +static inline bool Platform_getLongOption(ATTR_UNUSED int opt, ATTR_UNUSED int argc, ATTR_UNUSED char** argv) { + return false; +} + +static inline void Platform_gettime_realtime(struct timeval* tv, uint64_t* msec) { + Generic_gettime_realtime(tv, msec); +} + +void Platform_gettime_monotonic(uint64_t* msec); + +static inline Hashtable* Platform_dynamicMeters(void) { return NULL; } + +static inline void Platform_dynamicMetersDone(ATTR_UNUSED Hashtable* table) { } + +static inline void Platform_dynamicMeterInit(ATTR_UNUSED Meter* meter) { } + +static inline void Platform_dynamicMeterUpdateValues(ATTR_UNUSED Meter* meter) { } + +static inline void Platform_dynamicMeterDisplay(ATTR_UNUSED const Meter* meter, ATTR_UNUSED RichString* out) { } + +static inline Hashtable* Platform_dynamicColumns(void) { return NULL; } + +static inline void Platform_dynamicColumnsDone(ATTR_UNUSED Hashtable* table) { } + +static inline const char* Platform_dynamicColumnInit(ATTR_UNUSED unsigned int key) { return NULL; } -void Platform_getBattery(double *percent, ACPresence *isOnAC); +static inline bool Platform_dynamicColumnWriteField(ATTR_UNUSED const Process* proc, ATTR_UNUSED RichString* str, ATTR_UNUSED unsigned int key) { return false; } #endif diff --git a/darwin/ProcessField.h b/darwin/ProcessField.h index 5a8090f..25dbb45 100644 --- a/darwin/ProcessField.h +++ b/darwin/ProcessField.h @@ -10,6 +10,8 @@ in the source distribution for its full text. #define PLATFORM_PROCESS_FIELDS \ TRANSLATED = 100, \ + \ + DUMMY_BUMP_FIELD = CWD, \ // End of list |