Skip to content
Navigation Menu
Toggle navigation
Sign in
In this repository
All GitHub Enterprise
↵
Jump to
↵
No suggested jump to results
In this repository
All GitHub Enterprise
↵
Jump to
↵
In this organization
All GitHub Enterprise
↵
Jump to
↵
In this repository
All GitHub Enterprise
↵
Jump to
↵
Sign in
Reseting focus
You signed in with another tab or window.
Reload
to refresh your session.
You signed out in another tab or window.
Reload
to refresh your session.
You switched accounts on another tab or window.
Reload
to refresh your session.
Dismiss alert
{{ message }}
mariux64
/
mxq
Public
Notifications
You must be signed in to change notification settings
Fork
3
Star
3
Code
Issues
20
Pull requests
3
Actions
Projects
0
Wiki
Security
Insights
Additional navigation options
Code
Issues
Pull requests
Actions
Projects
Wiki
Security
Insights
Files
add-gpu-alloc-debug
helper
manpages
mysql
web
.gitignore
.vimrc
Doxyfile
LICENSE
Makefile
README.md
keywordset.c
keywordset.h
mx_flock.c
mx_flock.h
mx_getopt.c
mx_getopt.h
mx_log.c
mx_log.h
mx_mysql.c
mx_mysql.h
mx_proc.c
mx_proc.h
mx_util.c
mx_util.h
mxq.h
mxq_daemon.c
mxq_daemon.h
mxq_group.c
mxq_group.h
mxq_job.c
mxq_job.h
mxq_log.c
mxq_reaper.c
mxqadmin.c
mxqd.c
mxqd.h
mxqd_control.c
mxqd_control.h
mxqdctl-hostconfig.sh
mxqdump.c
mxqkill.c
mxqps.c
mxqset.c
mxqsub.c
os-release
parser.y
ppidcache.c
ppidcache.h
test_keywordset.c
test_mx_log.c
test_mx_mysql.c
test_mx_util.c
test_mxqd_control.c
test_parser.c
xmalloc.h
Breadcrumbs
mxq
/
mx_proc.c
Blame
Blame
Latest commit
History
History
520 lines (418 loc) · 12.9 KB
Breadcrumbs
mxq
/
mx_proc.c
Top
File metadata and controls
Code
Blame
520 lines (418 loc) · 12.9 KB
Raw
#include <sys/types.h> #include <stdio.h> #include <errno.h> #include <assert.h> #include <dirent.h> #include <ctype.h> #include <limits.h> #include "mx_util.h" #include "mx_proc.h" static long long int get_rss_anon(pid_t pid) { _mx_cleanup_free_ char *fname = mx_asprintf_forever("/proc/%d/status", pid); _mx_cleanup_fclose_ FILE *file = fopen(fname, "r"); if (file == NULL) return -errno; _mx_cleanup_free_ char *buf = NULL; size_t n = 0; while(1) { ssize_t len = getline(&buf, &n, file); if (len == -1) break; if (strncmp(buf, "RssAnon:", 8) == 0) { unsigned long long int anon_rss_kb = strtoull(buf+8, NULL, 10); if (anon_rss_kb == ULLONG_MAX) return -errno; if (anon_rss_kb > LLONG_MAX/1024) { // anon_rss > 8 EiB return -ERANGE; } return anon_rss_kb*1024; } } if (feof(file)) return 0; /* kernel thread */ return -errno; } static int _mx_proc_pid_stat_strscan(char *str, struct mx_proc_pid_stat *pps) { size_t res = 0; char *p; char *s; pps->comm = NULL; s = str; res += mx_strscan_ll(&s, &(pps->pid)); p = strrchr(s, ')'); if (!p) return -(errno=EINVAL); *p = 0; s++; pps->comm = mx_strdup_forever(s); s = p + 2; pps->state = *s; res += !(*(s+1) == ' '); s += 2; res += mx_strscan_ll(&s, &(pps->ppid)); res += mx_strscan_ll(&s, &(pps->pgrp)); res += mx_strscan_ll(&s, &(pps->session)); res += mx_strscan_ll(&s, &(pps->tty_nr)); res += mx_strscan_ll(&s, &(pps->tpgid)); res += mx_strscan_ull(&s, &(pps->flags)); res += mx_strscan_ull(&s, &(pps->minflt)); res += mx_strscan_ull(&s, &(pps->cminflt)); res += mx_strscan_ull(&s, &(pps->majflt)); res += mx_strscan_ull(&s, &(pps->cmajflt)); res += mx_strscan_ull(&s, &(pps->utime)); res += mx_strscan_ull(&s, &(pps->stime)); res += mx_strscan_ll(&s, &(pps->cutime)); res += mx_strscan_ll(&s, &(pps->cstime)); res += mx_strscan_ll(&s, &(pps->priority)); res += mx_strscan_ll(&s, &(pps->nice)); res += mx_strscan_ll(&s, &(pps->num_threads)); res += mx_strscan_ll(&s, &(pps->itrealvalue)); res += mx_strscan_ull(&s, &(pps->starttime)); res += mx_strscan_ull(&s, &(pps->vsize)); res += mx_strscan_ll(&s, &(pps->rss)); res += mx_strscan_ull(&s, &(pps->rsslim)); res += mx_strscan_ull(&s, &(pps->startcode)); res += mx_strscan_ull(&s, &(pps->endcode)); res += mx_strscan_ull(&s, &(pps->startstack)); res += mx_strscan_ull(&s, &(pps->kstkesp)); res += mx_strscan_ull(&s, &(pps->kstkeip)); res += mx_strscan_ull(&s, &(pps->signal)); res += mx_strscan_ull(&s, &(pps->blocked)); res += mx_strscan_ull(&s, &(pps->sigignore)); res += mx_strscan_ull(&s, &(pps->sigcatch)); res += mx_strscan_ull(&s, &(pps->wchan)); res += mx_strscan_ull(&s, &(pps->nswap)); res += mx_strscan_ull(&s, &(pps->cnswap)); res += mx_strscan_ll(&s, &(pps->exit_signal)); res += mx_strscan_ll(&s, &(pps->processor)); res += mx_strscan_ull(&s, &(pps->rt_priority)); res += mx_strscan_ull(&s, &(pps->policy)); res += mx_strscan_ull(&s, &(pps->delayacct_blkio_ticks)); res += mx_strscan_ull(&s, &(pps->guest_time)); res += mx_strscan_ll(&s, &(pps->cguest_time)); if (res != 0) return -(errno=EINVAL); return 0; } int mx_proc_pid_stat(struct mx_proc_pid_stat **pps, pid_t pid) { struct mx_proc_pid_stat *pstat; int res; pstat = *pps; if (!pstat) *pps = pstat = mx_calloc_forever(1, sizeof(*pstat)); res = mx_proc_pid_stat_read(pstat, "/proc/%d/stat", pid); if (res < 0) return res; long long int rss_anon = get_rss_anon(pid); if (rss_anon < 0) return rss_anon; pstat->rss_anon = rss_anon; return 0; } int mx_proc_pid_stat_read(struct mx_proc_pid_stat *pps, char *fmt, ...) { _mx_cleanup_free_ char *line = NULL; va_list ap; int res; assert(pps); va_start(ap, fmt); _mx_cleanup_free_ char *fname = fname = mx_vasprintf_forever(fmt, ap); va_end(ap); res = mx_read_first_line_from_file(fname, &line); if (res < 0) return res; res = _mx_proc_pid_stat_strscan(line, pps); if (res < 0) return res; return 0; } void mx_proc_pid_stat_free_content(struct mx_proc_pid_stat *pps) { if (!pps) return; mx_free_null(pps->comm); } static void mx_proc_tree_update_parent_pinfo(struct mx_proc_tree_node *this, struct mx_proc_info *pinfo) { if (!this) return; this->pinfo.sum_rss_anon += pinfo->sum_rss_anon; mx_proc_tree_update_parent_pinfo(this->parent, pinfo); } static void mx_proc_tree_add_to_list_sorted(struct mx_proc_tree_node **ptn_ptr, struct mx_proc_tree_node *new) { struct mx_proc_tree_node *current; assert(new); assert(new->pinfo.pstat); assert(!new->next); assert(new->pinfo.pstat->pid > 0); current = *ptn_ptr; /* update stats */ if (new->parent) { new->parent->nchilds++; mx_proc_tree_update_parent_pinfo(new->parent, &(new->pinfo)); } /* empty list? -> start new list */ if (!current) { *ptn_ptr = new; return; } /* new is first entry */ if (new->pinfo.pstat->pid < current->pinfo.pstat->pid) { new->next = current; *ptn_ptr = new; return; } /* find position */ while (1) { assert(new->pinfo.pstat->pid > current->pinfo.pstat->pid); /* new is last entry */ if (!current->next) { current->next = new; break; } assert(current->next->pinfo.pstat->pid > current->pinfo.pstat->pid); /* add new between current and current->next */ if (new->pinfo.pstat->pid < current->next->pinfo.pstat->pid) { new->next = current->next; current->next = new; break; } current = current->next; } return; } static struct mx_proc_tree_node *mx_proc_tree_find_by_pid(struct mx_proc_tree_node *ptn, long long int pid) { assert(ptn); assert(pid >= 0); struct mx_proc_tree_node *current; struct mx_proc_tree_node *node; if (pid == 0) return NULL; for (current = ptn; current; current=current->next) { if (current->pinfo.pstat->pid == pid) return current; if (!current->childs) continue; node = mx_proc_tree_find_by_pid(current->childs, pid); if (node) return node; } return NULL; } #define ppid_or_pgrp(x) (((x)->ppid != 1 || (x)->pid == (x)->pgrp) ? (x)->ppid : (x)->pgrp) static struct mx_proc_tree_node *mx_proc_tree_add(struct mx_proc_tree *pt, struct mx_proc_pid_stat *pps) { assert(pps); assert(pt); struct mx_proc_tree_node *new; struct mx_proc_tree_node *current; struct mx_proc_tree_node *next; struct mx_proc_tree_node *parent; new = mx_calloc_forever(1, sizeof(*new)); pt->nentries++; new->pinfo.pstat = pps; new->pinfo.sum_rss_anon = pps->rss_anon; if (!(pt->root)) { pt->root = new; return new; } assert(pt->root); /* new is second to last roots parent? -> collect */ current = pt->root; while (current->next) { if (ppid_or_pgrp(current->next->pinfo.pstat) != new->pinfo.pstat->pid) { current = current->next; continue; } assert(ppid_or_pgrp(current->next->pinfo.pstat) == new->pinfo.pstat->pid); /* disconnect next */ next = current->next; current->next = current->next->next; next->next = NULL; /* add as child of new */ next->parent = new; mx_proc_tree_add_to_list_sorted(&new->childs, next); } /* new is first roots parent? -> new is new root */ if (ppid_or_pgrp(pt->root->pinfo.pstat)== new->pinfo.pstat->pid) { assert(!new->next); current = pt->root; pt->root = pt->root->next; current->next = NULL; current->parent = new; mx_proc_tree_add_to_list_sorted(&new->childs, current); if (!(pt->root)) { pt->root = new; return new; } } parent = mx_proc_tree_find_by_pid(pt->root, ppid_or_pgrp(new->pinfo.pstat)); if (parent) { new->parent = parent; mx_proc_tree_add_to_list_sorted(&parent->childs, new); } else { mx_proc_tree_add_to_list_sorted(&pt->root, new); } return new; } static void mx_proc_tree_reorder_roots(struct mx_proc_tree *pt) { struct mx_proc_tree_node *current; struct mx_proc_tree_node *pid1 = NULL; struct mx_proc_tree_node *last = NULL; struct mx_proc_tree_node *next = NULL; for (current = pt->root; current; current = current->next) { if (current->pinfo.pstat->pid == 1) { pid1 = current; break; } } if (!pid1) return; for (current = pt->root; current; current = next) { next = current->next; if (current->pinfo.pstat->ppid != 1) { last = current; continue; } if (!last) { if (!current->next) return; pt->root = current->next; } else { last->next = current->next; } current->next = NULL; current->parent = pid1; mx_proc_tree_add_to_list_sorted(&pid1->childs, current); } } static int _mx_filter_numbers(const struct dirent *d) { if (!isdigit(d->d_name[0])) return 0; return 1; } int mx_proc_tree(struct mx_proc_tree **newtree) { struct mx_proc_tree *pt; struct dirent **namelist = NULL; struct mx_proc_pid_stat *pps; int n; int i; int res; unsigned long long int pid; assert(*newtree == NULL); pt = mx_calloc_forever(1, sizeof(*pt)); n = scandir("/proc", &namelist, _mx_filter_numbers, NULL); if (n < 0) return -errno; if (n == 0) return -(errno=ENOENT); for (i=0; i < n; i++) { res = mx_strtoull(namelist[i]->d_name, &pid); free(namelist[i]); if (res < 0) continue; pps = NULL; res = mx_proc_pid_stat(&pps, pid); if (res < 0) { free(pps); continue; } mx_proc_tree_add(pt, pps); } free(namelist); mx_proc_tree_reorder_roots(pt); *newtree = pt; return 0; } static void _mx_proc_tree_node_free_recursive(struct mx_proc_tree_node *ptn) { assert(ptn); struct mx_proc_tree_node *current; struct mx_proc_tree_node *next; for (current = ptn; current; current=next) { if (current->childs) _mx_proc_tree_node_free_recursive(current->childs); next = current->next; mx_proc_pid_stat_free_content(current->pinfo.pstat); mx_free_null(current->pinfo.pstat); mx_free_null(current); } return; } int mx_proc_tree_free(struct mx_proc_tree **tree) { struct mx_proc_tree *pt; pt = *tree; _mx_proc_tree_node_free_recursive(pt->root); mx_free_null(*tree); return 0; } struct mx_proc_info *mx_proc_tree_proc_info(struct mx_proc_tree *tree, pid_t pid) { struct mx_proc_tree_node *ptn; assert(tree); ptn = mx_proc_tree_find_by_pid(tree->root, pid); if (!ptn) return NULL; return &(ptn->pinfo); } /* * get parent pid of pid * return -1 if pid is not found */ pid_t mx_proc_get_parent(pid_t pid) { char statfilename[32]; // "/proc/2147483647/stat" = 22 FILE *statfile; pid_t parent; int n; char linebuf[256]; // "2147483647 (max128chars) X 2147483647 " = 156 if (pid == 0) // no need to try /proc/0/stat return -1; snprintf(statfilename, sizeof(statfilename), "/proc/%d/stat", pid); statfile = fopen(statfilename, "r"); if (statfile==NULL) return -1; /* * we can't just scanf(statfile, "%*d %*s %*c %d", &parent) because the comm might contain whitespace * e.g. "579 (UVM global queu) S 2 0 0 0 -1 2129984...." * all later fields are integer, so position at the last ")" */ fgets(linebuf, sizeof(linebuf), statfile); fclose(statfile); char *c = strrchr(linebuf, ')'); if (c == NULL) return -1; n = sscanf(c, ") %*c %d", &parent); if (n != 1) return -1; return parent; } /* * get "comm" value of a process. * buf MUST point to char[16] array * return NULL on any error, otherwise pointer to buf */ char *mx_proc_get_comm(pid_t pid, char *buf) { char commfilename[32]; // "/proc/2147483647/comm" = 22 FILE *commfile; char *p; snprintf(commfilename, sizeof(commfilename), "/proc/%d/comm", pid); commfile = fopen(commfilename, "r"); if (commfile == NULL) return NULL; p = fgets(buf, 16, commfile); fclose(commfile); if (p == NULL) return NULL; p = strrchr(buf, '\n'); if (p != NULL) *p = '\0'; return (char *)buf; }
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
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
You can’t perform that action at this time.