evisum/src/bin/system/process.c

1076 lines
23 KiB
C
Raw Normal View History

2018-06-04 03:11:21 -07:00
#if defined(__MACH__) && defined(__APPLE__)
# define __MacOS__
#endif
#if defined(__MacOS__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
# include <sys/types.h>
# include <sys/sysctl.h>
# include <sys/user.h>
# include <sys/proc.h>
# include <libgen.h>
2018-06-04 03:11:21 -07:00
#endif
2020-04-14 10:24:27 -07:00
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
# include <libgen.h>
2020-04-14 10:24:27 -07:00
# include <unistd.h>
# include <fcntl.h>
2018-06-04 03:11:21 -07:00
# include <kvm.h>
# include <limits.h>
# include <sys/proc.h>
# include <sys/param.h>
# include <sys/resource.h>
#endif
#if defined(__MacOS__)
# include <libproc.h>
# include <sys/proc_info.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include <limits.h>
#include "process.h"
#include <Eina.h>
#include <Ecore.h>
#include <Ecore_File.h>
2020-04-14 10:24:27 -07:00
#if defined(__linux__) && !defined(PF_KTHREAD)
# define PF_KTHREAD 0x00200000
#endif
2020-07-09 13:37:34 -07:00
#include "macros.h"
static Eina_Bool _show_kthreads = EINA_FALSE;
void
proc_info_kthreads_show_set(Eina_Bool enabled)
{
_show_kthreads = enabled;
}
Eina_Bool
proc_info_kthreads_show_get(void)
{
return _show_kthreads;
}
2018-06-04 03:11:21 -07:00
static const char *
_process_state_name(char state)
{
const char *statename = NULL;
#if defined(__linux__)
switch (state)
{
case 'D':
statename = "dsleep";
2018-06-04 03:11:21 -07:00
break;
case 'I':
statename = "idle";
2018-06-04 03:11:21 -07:00
break;
case 'R':
statename = "run";
2018-06-04 03:11:21 -07:00
break;
case 'S':
statename = "sleep";
2018-06-04 03:11:21 -07:00
break;
case 'T':
case 't':
statename = "stop";
2018-06-04 03:11:21 -07:00
break;
case 'X':
statename = "dead";
2018-06-04 03:11:21 -07:00
break;
case 'Z':
statename = "zomb";
2018-06-04 03:11:21 -07:00
break;
}
#else
switch (state)
{
case SIDL:
statename = "idle";
2018-06-04 03:11:21 -07:00
break;
case SRUN:
statename = "run";
2018-06-04 03:11:21 -07:00
break;
case SSLEEP:
statename = "sleep";
2018-06-04 03:11:21 -07:00
break;
case SSTOP:
statename = "stop";
2018-06-04 03:11:21 -07:00
break;
#if !defined(__MacOS__)
#if !defined(__OpenBSD__)
case SWAIT:
statename = "wait";
2018-06-04 03:11:21 -07:00
break;
case SLOCK:
statename = "lock";
2018-06-04 03:11:21 -07:00
break;
#endif
case SZOMB:
statename = "zomb";
2018-06-04 03:11:21 -07:00
break;
#endif
#if defined(__OpenBSD__)
case SDEAD:
statename = "dead";
2018-06-04 03:11:21 -07:00
break;
case SONPROC:
statename = "onproc";
2018-06-04 03:11:21 -07:00
break;
#endif
}
#endif
return statename;
}
#if defined(__linux__)
static unsigned long
_parse_line(const char *line)
{
char *p, *tok;
p = strchr(line, ':') + 1;
while (isspace(*p))
p++;
tok = strtok(p, " ");
return atol(tok);
}
2020-04-22 06:30:30 -07:00
static void
2020-05-12 18:11:10 -07:00
_mem_size(Proc_Info *proc)
2020-04-22 06:30:30 -07:00
{
FILE *f;
char buf[1024];
2020-04-22 10:28:20 -07:00
unsigned int dummy, size, shared, resident, data, text;
2020-07-09 13:37:34 -07:00
static int pagesize = 0;
if (!pagesize) pagesize = getpagesize();
2020-04-22 06:30:30 -07:00
2020-05-12 18:11:10 -07:00
f = fopen(eina_slstr_printf("/proc/%d/statm", proc->pid), "r");
2020-04-22 06:30:30 -07:00
if (!f) return;
if (fgets(buf, sizeof(buf), f))
{
2020-05-11 02:22:26 -07:00
if (sscanf(buf, "%u %u %u %u %u %u %u",
&size, &resident, &shared, &text,
2020-04-22 06:30:30 -07:00
&dummy, &data, &dummy) == 7)
{
2020-07-09 15:39:15 -07:00
proc->mem_rss = MEMSZ(resident) * MEMSZ(pagesize);
proc->mem_shared = MEMSZ(shared) * MEMSZ(pagesize);
2020-05-11 08:12:04 -07:00
proc->mem_size = proc->mem_rss - proc->mem_shared;
2020-07-09 15:39:15 -07:00
proc->mem_virt = MEMSZ(size) * MEMSZ(pagesize);
2020-04-22 06:30:30 -07:00
}
}
fclose(f);
}
static void
2020-05-12 18:11:10 -07:00
_cmd_args(Proc_Info *p, char *name, size_t len)
{
char line[4096];
2020-05-12 18:11:10 -07:00
int pid = p->pid;
char *link = ecore_file_readlink(eina_slstr_printf("/proc/%d/exe", pid));
if (link)
{
snprintf(name, len, "%s", ecore_file_file_get(link));
free(link);
}
FILE *f = fopen(eina_slstr_printf("/proc/%d/cmdline", pid), "r");
if (f)
{
if (fgets(line, sizeof(line), f))
{
Eina_Strbuf *buf = eina_strbuf_new();
const char *n;
if (ecore_file_exists(line))
snprintf(name, len, "%s", ecore_file_file_get(line));
n = line;
while (*n && (*n + 1))
{
eina_strbuf_append(buf, n);
n = strchr(n, '\0') + 1;
if (*n && (*n + 1)) eina_strbuf_append(buf, " ");
}
p->arguments = eina_strbuf_release(buf);
}
fclose(f);
}
char *end = strchr(name, ' ');
if (end) *end = '\0';
p->command = strdup(name);
}
static int
_uid(int pid)
{
FILE *f;
int uid;
char line[1024];
f = fopen(eina_slstr_printf("/proc/%d/status", pid), "r");
if (!f) return -1;
while ((fgets(line, sizeof(line), f)) != NULL)
{
if (!strncmp(line, "Uid:", 4))
{
uid = _parse_line(line);
break;
}
}
fclose(f);
return uid;
}
typedef struct {
2020-08-11 04:21:40 -07:00
int pid, ppid, utime, stime, cutime, cstime;
int psr, pri, nice, numthreads;
char state;
unsigned int mem_rss, flags;
unsigned long mem_virt;
char name[1024];
} Stat;
static Eina_Bool
_stat(const char *path, Stat *st)
{
FILE *f;
char line[4096];
int dummy, res = 0;
memset(st, 0, sizeof(Stat));
f = fopen(path, "r");
if (!f) return EINA_FALSE;
if (fgets(line, sizeof(line), f))
{
char *end, *start = strchr(line, '(') + 1;
end = strchr(line, ')');
strncpy(st->name, start, end - start);
st->name[end - start] = '\0';
res = sscanf(end + 2, "%c %d %d %d %d %d %u %u %u %u %u %d %d %d"
" %d %d %d %u %u %d %lu %u %u %u %u %u %u %u %d %d %d %d %u"
" %d %d %d %d %d %d %d %d %d",
2020-08-11 04:21:40 -07:00
&st->state, &st->ppid, &dummy, &dummy, &dummy, &dummy, &st->flags,
&dummy, &dummy, &dummy, &dummy, &st->utime, &st->stime, &st->cutime,
&st->cstime, &st->pri, &st->nice, &st->numthreads, &dummy, &dummy,
&st->mem_virt, &st->mem_rss, &dummy, &dummy, &dummy, &dummy, &dummy,
&dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy,
&dummy, &dummy, &st->psr, &dummy, &dummy, &dummy, &dummy, &dummy);
}
fclose(f);
if (res != 42) return EINA_FALSE;
return EINA_TRUE;
}
2018-06-04 03:11:21 -07:00
static Eina_List *
_process_list_linux_get(void)
{
Eina_List *files, *list;
char *n;
Stat st;
2018-06-04 03:11:21 -07:00
list = NULL;
2018-06-04 03:11:21 -07:00
files = ecore_file_ls("/proc");
2020-04-22 06:30:30 -07:00
EINA_LIST_FREE(files, n)
2018-06-04 03:11:21 -07:00
{
int pid = atoi(n);
2020-04-22 06:30:30 -07:00
free(n);
2018-06-04 03:11:21 -07:00
if (!pid) continue;
if (!_stat(eina_slstr_printf("/proc/%d/stat", pid), &st))
continue;
2018-06-04 03:11:21 -07:00
if (st.flags & PF_KTHREAD && !proc_info_kthreads_show_get())
continue;
2020-04-14 10:24:27 -07:00
2020-04-22 02:10:02 -07:00
Proc_Info *p = calloc(1, sizeof(Proc_Info));
if (!p) return NULL;
2018-06-04 03:11:21 -07:00
p->pid = pid;
2020-08-11 04:21:40 -07:00
p->ppid = st.ppid;
p->uid = _uid(pid);
p->cpu_id = st.psr;
p->state = _process_state_name(st.state);
p->cpu_time = st.utime + st.stime;
p->nice = st.nice;
p->priority = st.pri;
p->numthreads = st.numthreads;
2020-05-12 18:11:10 -07:00
_mem_size(p);
_cmd_args(p, st.name, sizeof(st.name));
2018-06-04 03:11:21 -07:00
list = eina_list_append(list, p);
}
return list;
}
static void
_proc_thread_info(Proc_Info *p)
{
Eina_List *files;
char *n;
Stat st;
files = ecore_file_ls(eina_slstr_printf("/proc/%d/task", p->pid));
EINA_LIST_FREE(files, n)
{
int tid = atoi(n);
free(n);
if (!_stat(eina_slstr_printf("/proc/%d/task/%d/stat", p->pid, tid), &st))
continue;
Proc_Info *t = calloc(1, sizeof(Proc_Info));
if (!t) continue;
t->cpu_id = st.psr;
t->state = _process_state_name(st.state);
t->cpu_time = st.utime + st.stime;
t->nice = st.nice;
t->priority = st.pri;
t->numthreads = st.numthreads;
t->mem_virt = st.mem_virt;
t->mem_rss = st.mem_rss;
2020-05-15 13:17:00 -07:00
t->tid = tid;
t->thread_name = strdup(st.name);
p->threads = eina_list_append(p->threads, t);
}
}
2020-04-16 14:03:25 -07:00
Proc_Info *
2018-06-04 03:11:21 -07:00
proc_info_by_pid(int pid)
{
Stat st;
2018-06-04 03:11:21 -07:00
if (!_stat(eina_slstr_printf("/proc/%d/stat", pid), &st))
return NULL;
2018-06-04 03:11:21 -07:00
2020-04-22 02:10:02 -07:00
Proc_Info *p = calloc(1, sizeof(Proc_Info));
if (!p) return NULL;
2018-06-04 03:11:21 -07:00
p->pid = pid;
2020-08-11 04:21:40 -07:00
p->ppid = st.ppid;
p->uid = _uid(pid);
p->cpu_id = st.psr;
p->state = _process_state_name(st.state);
p->cpu_time = st.utime + st.stime;
p->priority = st.pri;
p->nice = st.nice;
p->numthreads = st.numthreads;
2020-05-12 18:11:10 -07:00
_mem_size(p);
_cmd_args(p, st.name, sizeof(st.name));
_proc_thread_info(p);
2018-06-04 03:11:21 -07:00
return p;
}
#endif
#if defined(__OpenBSD__)
static void
_proc_get(Proc_Info *p, struct kinfo_proc *kp)
2018-06-04 03:11:21 -07:00
{
static int pagesize = 0;
2018-06-04 03:11:21 -07:00
if (!pagesize) pagesize = getpagesize();
2020-02-15 18:03:32 -08:00
2018-06-04 03:11:21 -07:00
p->pid = kp->p_pid;
2020-08-11 04:54:06 -07:00
p->ppid = kp->p_ppid;
2018-06-04 03:11:21 -07:00
p->uid = kp->p_uid;
p->cpu_id = kp->p_cpuid;
p->state = _process_state_name(kp->p_stat);
p->cpu_time = kp->p_uticks + kp->p_sticks + kp->p_iticks;
2020-07-09 15:39:15 -07:00
p->mem_virt = p->mem_size = (MEMSZ(kp->p_vm_tsize) * MEMSZ(pagesize)) +
(MEMSZ(kp->p_vm_dsize) * MEMSZ(pagesize)) + (MEMSZ(kp->p_vm_ssize) * MEMSZ(pagesize));
p->mem_rss = MEMSZ(kp->p_vm_rssize) * MEMSZ(pagesize);
2018-06-04 03:11:21 -07:00
p->priority = kp->p_priority - PZERO;
p->nice = kp->p_nice - NZERO;
p->tid = kp->p_tid;
}
static void
_cmd_get(Proc_Info *p, kvm_t *kern, struct kinfo_proc *kp)
{
char **args;
char name[1024];
2018-06-04 03:11:21 -07:00
2020-04-22 02:52:22 -07:00
if ((args = kvm_getargv(kern, kp, sizeof(name)-1)))
2020-04-21 13:44:24 -07:00
{
2020-04-22 02:52:22 -07:00
Eina_Strbuf *buf = eina_strbuf_new();
for (int i = 0; args[i]; i++)
2020-04-21 13:44:24 -07:00
{
2020-04-22 02:52:22 -07:00
eina_strbuf_append(buf, args[i]);
2020-05-15 08:15:27 -07:00
if (args[i + 1])
eina_strbuf_append(buf, " ");
2020-04-21 13:44:24 -07:00
}
2020-04-22 02:52:22 -07:00
p->arguments = eina_strbuf_string_steal(buf);
eina_strbuf_free(buf);
2020-05-11 09:52:48 -07:00
if (args[0] && ecore_file_exists(args[0]))
p->command = strdup(ecore_file_file_get(args[0]));
2020-04-21 13:44:24 -07:00
}
2020-05-11 09:52:48 -07:00
if (!p->command)
p->command = strdup(kp->p_comm);
}
Proc_Info *
proc_info_by_pid(int pid)
{
struct kinfo_proc *kp, *kpt;
kvm_t *kern;
char errbuf[_POSIX2_LINE_MAX];
int count, pid_count;
kern = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
if (!kern) return NULL;
kp = kvm_getprocs(kern, KERN_PROC_PID, pid, sizeof(*kp), &count);
if (!kp) return NULL;
if (count == 0) return NULL;
Proc_Info *p = calloc(1, sizeof(Proc_Info));
if (!p) return NULL;
_proc_get(p, kp);
_cmd_get(p, kern, kp);
2020-05-11 09:52:48 -07:00
2018-06-04 03:11:21 -07:00
kp = kvm_getprocs(kern, KERN_PROC_SHOW_THREADS, 0, sizeof(*kp), &pid_count);
for (int i = 0; i < pid_count; i++)
{
2020-05-15 08:15:27 -07:00
if (kp[i].p_pid != p->pid) continue;
kpt = &kp[i];
if (kpt->p_tid <= 0) continue;
2020-05-15 08:15:27 -07:00
Proc_Info *t = calloc(1, sizeof(Proc_Info));
if (!t) continue;
_proc_get(t, kpt);
t->tid = kpt->p_tid;
t->thread_name = strdup(kpt->p_comm);
2020-05-15 08:15:27 -07:00
p->threads = eina_list_append(p->threads, t);
2018-06-04 03:11:21 -07:00
}
p->numthreads = eina_list_count(p->threads);
2018-06-04 03:11:21 -07:00
kvm_close(kern);
return p;
}
static Eina_List *
_process_list_openbsd_get(void)
{
2020-04-21 13:44:24 -07:00
struct kinfo_proc *kps, *kp;
2020-04-16 14:03:25 -07:00
Proc_Info *p;
2018-06-04 03:11:21 -07:00
char errbuf[4096];
kvm_t *kern;
int pid_count;
2020-04-21 13:44:24 -07:00
Eina_List *list = NULL;
2018-06-04 03:11:21 -07:00
kern = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf);
if (!kern) return NULL;
2020-04-21 13:44:24 -07:00
kps = kvm_getprocs(kern, KERN_PROC_ALL, 0, sizeof(*kps), &pid_count);
if (!kps) return NULL;
2018-06-04 03:11:21 -07:00
for (int i = 0; i < pid_count; i++)
{
2020-04-16 14:03:25 -07:00
p = calloc(1, sizeof(Proc_Info));
2020-02-15 18:03:32 -08:00
if (!p) return NULL;
2020-04-21 13:44:24 -07:00
kp = &kps[i];
2020-05-11 09:52:48 -07:00
_proc_get(p, kp);
_cmd_get(p, kern, kp);
2020-05-11 09:52:48 -07:00
2018-06-04 03:11:21 -07:00
list = eina_list_append(list, p);
}
kvm_close(kern);
return list;
}
#endif
#if defined(__MacOS__)
static void
_cmd_get(Proc_Info *p, int pid)
{
char *cp, *args, **argv;
int mib[3], argmax, argc;
size_t size;
mib[0] = CTL_KERN;
mib[1] = KERN_ARGMAX;
size = sizeof(argmax);
if (sysctl(mib, 2, &argmax, &size, NULL, 0) == -1) return;
mib[0] = CTL_KERN;
mib[1] = KERN_PROCARGS2;
mib[2] = pid;
size = (size_t) argmax;
args = malloc(argmax);
if (!args) return;
/* See libtop.c (top) for the origin of this comment, which is necessary as
* there is little other documentation...thanks Apple.
*
* Make a sysctl() call to get the raw argument space of the process.
* The layout is documented in start.s, which is part of the Csu
* project. In summary, it looks like:
*
* /---------------\ 0x00000000
* : :
* : :
* |---------------|
* | argc |
* |---------------|
* | arg[0] |
* |---------------|
* : :
* : :
* |---------------|
* | arg[argc - 1] |
* |---------------|
* | 0 |
* |---------------|
* | env[0] |
* |---------------|
* : :
* : :
* |---------------|
* | env[n] |
* |---------------|
* | 0 |
* |---------------| <-- Beginning of data returned by sysctl() is here.
* | argc |
* |---------------|
* | exec_path |
* |:::::::::::::::|
* | |
* | String area. |
* | |
* |---------------| <-- Top of stack.
* : :
* : :
* \---------------/ 0xffffffff
*/
if (sysctl(mib, 3, args, &size, NULL, 0) == -1) return;
memcpy(&argc, args, sizeof(argc));
cp = args + sizeof(argc);
/* Skip exec path */
for (;cp < &args[size]; cp++)
{
if (*cp == '\0') break;
}
if (cp == &args[size]) return;
2020-04-27 05:48:35 -07:00
/* Skip any padded NULLs. */
for (;cp < &args[size]; cp++)
{
if (*cp == '\0') break;
}
if (cp == &args[size]) return;
argv = malloc(1 + argc * sizeof(char *));
if (!argv) return;
int i = 0;
argv[i] = cp;
for (cp = args + sizeof(int); cp < &args[size] && i < argc; cp++)
{
if (*cp == '\0')
{
while (*cp == '\0') cp++;
argv[i++] = cp;
}
}
if (i == 0) i++;
argv[i] = NULL;
p->command = strdup(basename(argv[0]));
Eina_Strbuf *buf = eina_strbuf_new();
for (i = 0; i < argc; i++)
eina_strbuf_append_printf(buf, "%s ", argv[i]);
if (argc > 0)
p->arguments = eina_strbuf_release(buf);
else
eina_strbuf_free(buf);
free(args);
free(argv);
}
static Proc_Info *
_proc_pidinfo(size_t pid)
{
struct proc_taskallinfo taskinfo;
int size = proc_pidinfo(pid, PROC_PIDTASKALLINFO, 0, &taskinfo, sizeof(taskinfo));
if (size != sizeof(taskinfo)) return NULL;
Proc_Info *p = calloc(1, sizeof(Proc_Info));
if (!p) return NULL;
p->pid = pid;
2020-08-11 04:00:02 -07:00
p->ppid = taskinfo.pbsd.pbi_ppid;
p->uid = taskinfo.pbsd.pbi_uid;
p->cpu_id = -1;
p->cpu_time = taskinfo.ptinfo.pti_total_user +
taskinfo.ptinfo.pti_total_system;
p->cpu_time /= 10000000;
p->state = _process_state_name(taskinfo.pbsd.pbi_status);
p->mem_size = p->mem_virt = taskinfo.ptinfo.pti_virtual_size;
p->mem_rss = taskinfo.ptinfo.pti_resident_size;
p->priority = taskinfo.ptinfo.pti_priority;
p->nice = taskinfo.pbsd.pbi_nice;
p->numthreads = taskinfo.ptinfo.pti_threadnum;
_cmd_get(p, pid);
return p;
}
2018-06-04 03:11:21 -07:00
static Eina_List *
_process_list_macos_fallback_get(void)
2018-06-04 03:11:21 -07:00
{
Eina_List *list = NULL;
for (int i = 1; i <= PID_MAX; i++)
{
Proc_Info *p = _proc_pidinfo(i);
if (p)
list = eina_list_append(list, p);
}
2018-06-04 03:11:21 -07:00
return list;
}
2020-02-15 18:03:32 -08:00
static Eina_List *
_process_list_macos_get(void)
{
Eina_List *list = NULL;
pid_t *pids = NULL;
int size, pid_count;
2018-06-04 03:11:21 -07:00
size = proc_listpids(PROC_ALL_PIDS, 0, NULL, 0);
if (size == -1)
return _process_list_macos_fallback_get();
pids = malloc(size * sizeof(pid_t));
if (!pids) return NULL;
size = proc_listpids(PROC_ALL_PIDS, 0, pids, size * sizeof(pid_t));
if (size == -1)
{
free(pids);
return _process_list_macos_fallback_get();
}
pid_count = size / sizeof(pid_t);
for (int i = 0; i < pid_count; i++)
{
pid_t pid = pids[i];
Proc_Info *p = _proc_pidinfo(pid);
if (p)
list = eina_list_append(list, p);
2018-06-04 03:11:21 -07:00
}
free(pids);
2018-06-04 03:11:21 -07:00
return list;
}
2020-04-16 14:03:25 -07:00
Proc_Info *
2018-06-04 03:11:21 -07:00
proc_info_by_pid(int pid)
{
struct proc_taskallinfo taskinfo;
struct proc_workqueueinfo workqueue;
size_t size;
size = proc_pidinfo(pid, PROC_PIDTASKALLINFO, 0, &taskinfo, sizeof(taskinfo));
if (size != sizeof(taskinfo))
return NULL;
size = proc_pidinfo(pid, PROC_PIDWORKQUEUEINFO, 0, &workqueue, sizeof(workqueue));
if (size != sizeof(workqueue))
memset(&workqueue, 0, sizeof(struct proc_workqueueinfo));
2018-06-04 03:11:21 -07:00
2020-04-16 14:03:25 -07:00
Proc_Info *p = calloc(1, sizeof(Proc_Info));
2020-02-15 18:03:32 -08:00
if (!p) return NULL;
2018-06-04 03:11:21 -07:00
p->pid = pid;
p->uid = taskinfo.pbsd.pbi_uid;
p->cpu_id = workqueue.pwq_nthreads;
2020-05-11 02:22:26 -07:00
p->cpu_time = taskinfo.ptinfo.pti_total_user +
taskinfo.ptinfo.pti_total_system;
2018-06-04 03:11:21 -07:00
p->cpu_time /= 10000000;
p->state = _process_state_name(taskinfo.pbsd.pbi_status);
p->mem_size = p->mem_virt = taskinfo.ptinfo.pti_virtual_size;
2018-06-04 03:11:21 -07:00
p->mem_rss = taskinfo.ptinfo.pti_resident_size;
p->priority = taskinfo.ptinfo.pti_priority;
p->nice = taskinfo.pbsd.pbi_nice;
p->numthreads = taskinfo.ptinfo.pti_threadnum;
_cmd_get(p, pid);
2018-06-04 03:11:21 -07:00
return p;
}
#endif
#if defined(__FreeBSD__) || defined(__DragonFly__)
static int
_pid_max(void)
{
size_t len;
static int pid_max = 0;
if (pid_max != 0) return pid_max;
len = sizeof(pid_max);
if (sysctlbyname("kern.pid_max", &pid_max, &len, NULL, 0) == -1)
{
#if defined(__FreeBSD__)
pid_max = 99999;
#elif defined(__DragonFly__)
pid_max = 999999;
#else
pid_max = PID_MAX;
#endif
}
return pid_max;
}
2020-05-15 06:27:34 -07:00
static void
_cmd_get(Proc_Info *p, struct kinfo_proc *kp)
{
kvm_t * kern;
char **args;
char name[1024];
Eina_Bool have_command = EINA_FALSE;
kern = kvm_open(NULL, "/dev/null", NULL, O_RDONLY, "kvm_open");
2020-05-16 04:12:09 -07:00
if (kern)
2020-05-15 06:27:34 -07:00
{
2020-05-16 04:12:09 -07:00
if ((args = kvm_getargv(kern, kp, sizeof(name)-1)) && (args[0]))
2020-05-15 06:27:34 -07:00
{
2020-05-16 04:12:09 -07:00
char *base = strdup(args[0]);
if (base)
2020-05-15 06:27:34 -07:00
{
2020-05-16 04:12:09 -07:00
char *spc = strchr(base, ' ');
if (spc) *spc = '\0';
if (ecore_file_exists(base))
2020-05-15 06:27:34 -07:00
{
2020-05-16 04:12:09 -07:00
snprintf(name, sizeof(name), "%s", basename(base));
have_command = EINA_TRUE;
2020-05-15 06:27:34 -07:00
}
2020-05-16 04:12:09 -07:00
free(base);
2020-05-15 06:27:34 -07:00
}
Eina_Strbuf *buf = eina_strbuf_new();
for (int i = 0; args[i] != NULL; i++)
{
eina_strbuf_append(buf, args[i]);
if (args[i + 1])
eina_strbuf_append(buf, " ");
}
p->arguments = eina_strbuf_string_steal(buf);
eina_strbuf_free(buf);
}
kvm_close(kern);
}
if (!have_command)
snprintf(name, sizeof(name), "%s", kp->ki_comm);
p->command = strdup(name);
}
2020-05-16 03:57:57 -07:00
static Proc_Info *
_proc_thread_info(struct kinfo_proc *kp, Eina_Bool is_thread)
{
struct rusage *usage;
Proc_Info *p;
static int pagesize = 0;
if (!pagesize) pagesize = getpagesize();
p = calloc(1, sizeof(Proc_Info));
if (!p) return NULL;
p->pid = kp->ki_pid;
2020-08-11 03:49:49 -07:00
p->ppid = kp->ki_ppid;
2020-05-16 03:57:57 -07:00
p->uid = kp->ki_uid;
if (!is_thread)
_cmd_get(p, kp);
p->cpu_id = kp->ki_oncpu;
if (p->cpu_id == -1)
p->cpu_id = kp->ki_lastcpu;
usage = &kp->ki_rusage;
p->cpu_time = (usage->ru_utime.tv_sec * 1000000) + usage->ru_utime.tv_usec +
(usage->ru_stime.tv_sec * 1000000) + usage->ru_stime.tv_usec;
p->cpu_time /= 10000;
p->state = _process_state_name(kp->ki_stat);
p->mem_virt = kp->ki_size;
2020-07-09 15:39:15 -07:00
p->mem_rss = MEMSZ(kp->ki_rssize) * MEMSZ(pagesize);
2020-05-16 03:57:57 -07:00
p->mem_size = p->mem_virt;
p->nice = kp->ki_nice - NZERO;
p->priority = kp->ki_pri.pri_level - PZERO;
p->numthreads = kp->ki_numthreads;
p->tid = kp->ki_tid;
p->thread_name = strdup(kp->ki_tdname);
return p;
}
static Eina_List *
_process_list_freebsd_fallback_get(void)
{
Eina_List *list;
struct kinfo_proc kp;
int mib[4];
size_t len;
2020-07-10 02:50:35 -07:00
static int pid_max;
2020-05-16 03:57:57 -07:00
pid_max = _pid_max();
list = NULL;
len = sizeof(int);
if (sysctlnametomib("kern.proc.pid", mib, &len) == -1)
return NULL;
for (int i = 1; i <= pid_max; i++)
{
mib[3] = i;
len = sizeof(kp);
if (sysctl(mib, 4, &kp, &len, NULL, 0) == -1)
continue;
if (kp.ki_flag & P_KPROC && !proc_info_kthreads_show_get())
2020-05-16 03:57:57 -07:00
continue;
Proc_Info *p = _proc_thread_info(&kp, EINA_FALSE);
if (p)
list = eina_list_append(list, p);
}
return list;
}
2020-05-15 06:27:34 -07:00
2020-04-14 10:24:27 -07:00
static Eina_List *
_process_list_freebsd_get(void)
{
kvm_t *kern;
Eina_List *list = NULL;
struct kinfo_proc *kps, *kp;
2020-04-14 10:24:27 -07:00
char errbuf[_POSIX2_LINE_MAX];
int pid_count;
kern = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
if (!kern)
return _process_list_freebsd_fallback_get();
kps = kvm_getprocs(kern, KERN_PROC_PROC, 0, &pid_count);
if (!kps)
{
kvm_close(kern);
return _process_list_freebsd_fallback_get();
}
2020-04-14 10:24:27 -07:00
for (int i = 0; i < pid_count; i++)
{
if (kps[i].ki_flag & P_KPROC && !proc_info_kthreads_show_get())
2020-04-14 10:24:27 -07:00
continue;
kp = &kps[i];
2020-04-22 03:05:17 -07:00
2020-05-16 03:57:57 -07:00
Proc_Info *p = _proc_thread_info(kp, EINA_FALSE);
if (p)
list = eina_list_append(list, p);
2020-04-14 10:24:27 -07:00
}
kvm_close(kern);
2020-04-14 10:24:27 -07:00
return list;
}
2020-05-15 06:24:38 -07:00
static Proc_Info *
_proc_info_by_pid_fallback(int pid)
2018-06-04 03:11:21 -07:00
{
struct kinfo_proc kp;
int mib[4];
size_t len;
len = sizeof(int);
if (sysctlnametomib("kern.proc.pid", mib, &len) == -1)
return NULL;
mib[3] = pid;
len = sizeof(kp);
if (sysctl(mib, 4, &kp, &len, NULL, 0) == -1)
return NULL;
2020-05-16 03:57:57 -07:00
Proc_Info *p = _proc_thread_info(&kp, EINA_FALSE);
2020-05-15 13:27:59 -07:00
2020-05-15 06:24:38 -07:00
return p;
}
Proc_Info *
proc_info_by_pid(int pid)
{
kvm_t *kern;
struct kinfo_proc *kps, *kp;
char errbuf[_POSIX2_LINE_MAX];
int pid_count;
kern = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
if (!kern)
return _proc_info_by_pid_fallback(pid);
kps = kvm_getprocs(kern, KERN_PROC_ALL, 0, &pid_count);
if (!kps)
{
kvm_close(kern);
return _proc_info_by_pid_fallback(pid);
}
Proc_Info *p = NULL;
for (int i = 0; i < pid_count; i++)
{
if (kps[i].ki_flag & P_KPROC && !proc_info_kthreads_show_get())
2020-05-15 06:24:38 -07:00
continue;
if (kps[i].ki_pid != pid)
continue;
kp = &kps[i];
Proc_Info *t = _proc_thread_info(kp, EINA_TRUE);
if (!p)
{
p = _proc_thread_info(kp, EINA_FALSE);
p->cpu_time = 0;
}
2020-05-15 06:24:38 -07:00
p->cpu_time += t->cpu_time;
2020-05-15 06:24:38 -07:00
p->threads = eina_list_append(p->threads, t);
}
kvm_close(kern);
if (!p) return _proc_info_by_pid_fallback(pid);
return p;
}
2018-06-04 03:11:21 -07:00
#endif
2020-04-22 02:10:02 -07:00
void
proc_info_free(Proc_Info *proc)
{
Proc_Info *t;
EINA_LIST_FREE(proc->threads, t)
{
proc_info_free(t);
}
2020-04-22 02:10:02 -07:00
if (proc->command)
free(proc->command);
if (proc->arguments)
free(proc->arguments);
2020-05-15 13:17:00 -07:00
if (proc->thread_name)
free(proc->thread_name);
2020-04-22 02:10:02 -07:00
free(proc);
}
2018-06-04 03:11:21 -07:00
Eina_List *
proc_info_all_get(void)
{
Eina_List *processes;
#if defined(__linux__)
processes = _process_list_linux_get();
#elif defined(__FreeBSD__) || defined(__DragonFly__)
processes = _process_list_freebsd_get();
#elif defined(__MacOS__)
processes = _process_list_macos_get();
#elif defined(__OpenBSD__)
processes = _process_list_openbsd_get();
#else
processes = NULL;
#endif
return processes;
}