#if defined(__MACH__) && defined(__APPLE__) # define __MacOS__ #endif #if defined(__MacOS__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) # include # include # include # include #endif #if defined(__OpenBSD__) # include # include # include # include # include #endif #if defined(__MacOS__) # include # include #endif #include #include #include #include #include #include #include "process.h" #include #include #include static const char * _process_state_name(char state) { const char *statename = NULL; #if defined(__linux__) switch (state) { case 'D': statename = "dsleep"; break; case 'I': statename = "idle"; break; case 'R': statename = "run"; break; case 'S': statename = "sleep"; break; case 'T': case 't': statename = "stop"; break; case 'X': statename = "dead"; break; case 'Z': statename = "zomb"; break; } #else switch (state) { case SIDL: statename = "idle"; break; case SRUN: statename = "run"; break; case SSLEEP: statename = "sleep"; break; case SSTOP: statename = "stop"; break; #if !defined(__MacOS__) #if !defined(__OpenBSD__) case SWAIT: statename = "wait"; break; case SLOCK: statename = "lock"; break; #endif case SZOMB: statename = "zomb"; break; #endif #if defined(__OpenBSD__) case SDEAD: statename = "dead"; break; case SONPROC: statename = "onproc"; 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); } static Eina_List * _process_list_linux_get(void) { char *name; Eina_List *files, *list = NULL; FILE *f; char path[PATH_MAX], line[4096], program_name[1024], state; int pid, res, utime, stime, cutime, cstime, uid, psr, pri, nice, numthreads; unsigned int mem_size, mem_rss; int pagesize = getpagesize(); files = ecore_file_ls("/proc"); EINA_LIST_FREE(files, name) { pid = atoi(name); free(name); if (!pid) continue; snprintf(path, sizeof(path), "/proc/%d/stat", pid); f = fopen(path, "r"); if (!f) continue; if (fgets(line, sizeof(line), f)) { int dummy; char *end, *start = strchr(line, '(') + 1; end = strchr(line, ')'); strncpy(program_name, start, end - start); program_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 %u %u %u %u %u %u %u %u %d %d %d %d %u %d %d %d %d %d %d %d %d %d", &state, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &utime, &stime, &cutime, &cstime, &pri, &nice, &numthreads, &dummy, &dummy, &mem_size, &mem_rss, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &psr, &dummy, &dummy, &dummy, &dummy, &dummy); } fclose(f); if (res != 42) continue; snprintf(path, sizeof(path), "/proc/%d/status", pid); f = fopen(path, "r"); if (!f) continue; while ((fgets(line, sizeof(line), f)) != NULL) { if (!strncmp(line, "Uid:", 4)) { uid = _parse_line(line); break; } } fclose(f); Proc_Stats *p = calloc(1, sizeof(Proc_Stats)); p->pid = pid; p->uid = uid; p->cpu_id = psr; snprintf(p->command, sizeof(p->command), "%s", program_name); p->state = _process_state_name(state); p->cpu_time = utime + stime; p->mem_size = mem_size; p->mem_rss = mem_rss * pagesize; p->nice = nice; p->priority = pri; p->numthreads = numthreads; list = eina_list_append(list, p); } if (files) eina_list_free(files); return list; } Proc_Stats * proc_info_by_pid(int pid) { FILE *f; char path[PATH_MAX]; char line[4096]; char state, program_name[1024]; int res, dummy, utime, stime, cutime, cstime, uid, psr; unsigned int mem_size, mem_rss, pri, nice, numthreads; snprintf(path, sizeof(path), "/proc/%d/stat", pid); if (!ecore_file_exists(path)) return NULL; f = fopen(path, "r"); if (!f) return NULL; if (fgets(line, sizeof(line), f)) { char *end, *start = strchr(line, '(') + 1; end = strchr(line, ')'); strncpy(program_name, start, end - start); program_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 %u %u %u %u %u %u %u %u %d %d %d %d %u %d %d %d %d %d %d %d %d %d", &state, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &utime, &stime, &cutime, &cstime, &pri, &nice, &numthreads, &dummy, &dummy, &mem_size, &mem_rss, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &dummy, &psr, &dummy, &dummy, &dummy, &dummy, &dummy); } fclose(f); if (res != 42) return NULL; snprintf(path, sizeof(path), "/proc/%d/status", pid); f = fopen(path, "r"); if (!f) return NULL; while ((fgets(line, sizeof(line), f)) != NULL) { if (!strncmp(line, "Uid:", 4)) { uid = _parse_line(line); break; } } fclose(f); Proc_Stats *p = calloc(1, sizeof(Proc_Stats)); p->pid = pid; p->uid = uid; p->cpu_id = psr; snprintf(p->command, sizeof(p->command), "%s", program_name); p->state = _process_state_name(state); p->cpu_time = utime + stime; p->mem_size = mem_size; p->mem_rss = mem_rss * getpagesize(); p->priority = pri; p->nice = nice; p->numthreads = numthreads; return p; } #endif #if defined(__OpenBSD__) Proc_Stats * proc_info_by_pid(int pid) { struct kinfo_proc *kp; kvm_t *kern; char errbuf[4096]; int count, pagesize, 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; pagesize = getpagesize(); Proc_Stats *p = malloc(sizeof(Proc_Stats)); p->pid = kp->p_pid; p->uid = kp->p_uid; p->cpu_id = kp->p_cpuid; snprintf(p->command, sizeof(p->command), "%s", kp->p_comm); p->state = _process_state_name(kp->p_stat); p->cpu_time = kp->p_uticks + kp->p_sticks + kp->p_iticks; p->mem_size = (kp->p_vm_tsize * pagesize) + (kp->p_vm_dsize * pagesize) + (kp->p_vm_ssize * pagesize); p->mem_rss = kp->p_vm_rssize * pagesize; p->priority = kp->p_priority - PZERO; p->nice = kp->p_nice - NZERO; p->numthreads = -1; kp = kvm_getprocs(kern, KERN_PROC_SHOW_THREADS, 0, sizeof(*kp), &pid_count); for (int i = 0; i < pid_count; i++) { if (kp[i].p_pid == p->pid) p->numthreads++; } kvm_close(kern); return p; } static Eina_List * _process_list_openbsd_get(void) { struct kinfo_proc *kp; Proc_Stats *p; char errbuf[4096]; kvm_t *kern; int pid_count, pagesize; Eina_List *l, *list = NULL; kern = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf); if (!kern) return NULL; kp = kvm_getprocs(kern, KERN_PROC_ALL, 0, sizeof(*kp), &pid_count); if (!kp) return NULL; pagesize = getpagesize(); for (int i = 0; i < pid_count; i++) { p = malloc(sizeof(Proc_Stats)); p->pid = kp[i].p_pid; p->uid = kp[i].p_uid; p->cpu_id = kp[i].p_cpuid; snprintf(p->command, sizeof(p->command), "%s", kp[i].p_comm); p->state = _process_state_name(kp[i].p_stat); p->cpu_time = kp[i].p_uticks + kp[i].p_sticks + kp[i].p_iticks; p->mem_size = (kp[i].p_vm_tsize * pagesize) + (kp[i].p_vm_dsize * pagesize) + (kp[i].p_vm_ssize * pagesize); p->mem_rss = kp[i].p_vm_rssize * pagesize; p->priority = kp[i].p_priority - PZERO; p->nice = kp[i].p_nice - NZERO; p->numthreads = -1; list = eina_list_append(list, p); } kp = kvm_getprocs(kern, KERN_PROC_SHOW_THREADS, 0, sizeof(*kp), &pid_count); EINA_LIST_FOREACH(list, l, p) { for (int i = 0; i < pid_count; i++) { if (kp[i].p_pid == p->pid) p->numthreads++; } } kvm_close(kern); return list; } #endif #if defined(__MacOS__) static Eina_List * _process_list_macos_get(void) { Eina_List *list = NULL; for (int i = 1; i <= PID_MAX; i++) { struct proc_taskallinfo taskinfo; int size = proc_pidinfo(i, PROC_PIDTASKALLINFO, 0, &taskinfo, sizeof(taskinfo)); if (size != sizeof(taskinfo)) continue; Proc_Stats *p = calloc(1, sizeof(Proc_Stats)); p->pid = i; p->uid = taskinfo.pbsd.pbi_uid; p->cpu_id = -1; snprintf(p->command, sizeof(p->command), "%s", taskinfo.pbsd.pbi_comm); 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 = 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; list = eina_list_append(list, p); } return list; } Proc_Stats * proc_info_by_pid(int pid) { struct kinfo_proc kp; 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)) return NULL; Proc_Stats *p = calloc(1, sizeof(Proc_Stats)); p->pid = pid; p->uid = taskinfo.pbsd.pbi_uid; p->cpu_id = workqueue.pwq_nthreads; snprintf(p->command, sizeof(p->command), "%s", taskinfo.pbsd.pbi_comm); 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 = 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; return p; } #endif #if defined(__FreeBSD__) || defined(__DragonFly__) static Eina_List * _process_list_freebsd_get(void) { Eina_List *list; struct rusage *usage; struct kinfo_proc kp; int mib[4]; size_t len; int pagesize = getpagesize(); 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_SYSTEM) continue; Proc_Stats *p = calloc(1, sizeof(Proc_Stats)); p->pid = kp.ki_pid; p->uid = kp.ki_uid; snprintf(p->command, sizeof(p->command), "%s", kp.ki_comm); 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_size = kp.ki_size; p->mem_rss = kp.ki_rssize * pagesize; p->nice = kp.ki_nice - NZERO; p->priority = kp.ki_pri.pri_level - PZERO; p->numthreads = kp.ki_numthreads; list = eina_list_append(list, p); } return list; } Proc_Stats * proc_info_by_pid(int pid) { struct rusage *usage; struct kinfo_proc kp; int mib[4]; size_t len; int pagesize = getpagesize(); 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; Proc_Stats *p = calloc(1, sizeof(Proc_Stats)); p->pid = kp.ki_pid; p->uid = kp.ki_uid; snprintf(p->command, sizeof(p->command), "%s", kp.ki_comm); 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_size = kp.ki_size; p->mem_rss = kp.ki_rssize * pagesize; p->nice = kp.ki_nice = NZERO; p->priority = kp.ki_pri.pri_level - PZERO; p->numthreads = kp.ki_numthreads; return p; } #endif 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; }