/proc//status簡要分析

關鍵詞:status、virtual memory、signal、capability、context switch等等。node

 

每一個進程/線程都有本身私有狀態,在/proc/<pid>status中體現。函數

瞭解status中每項的含義,有助於問題定位時發現問題。ui

下面結合status在內中函數proc_pid_status()對每一項進行簡單的瞭解,而後結合一個示例進行分析。this

1. status在內核中的解釋

status當前進程/線程的名稱、運行狀態、pid、信號、權限、cpu使用範圍、進程切換等等信息。atom

int proc_pid_status(struct seq_file *m, struct pid_namespace *ns, struct pid *pid, struct task_struct *task) { struct mm_struct *mm = get_task_mm(task); task_name(m, task); task_state(m, ns, pid, task); if (mm) { task_mem(m, mm); mmput(mm); } task_sig(m, task); task_cap(m, task); task_seccomp(m, task); task_cpus_allowed(m, task); cpuset_task_status_allowed(m, task); task_context_switch_counts(m, task); return 0; } static inline void task_state(struct seq_file *m, struct pid_namespace *ns, struct pid *pid, struct task_struct *p) { struct user_namespace *user_ns = seq_user_ns(m); struct group_info *group_info; int g, umask; struct task_struct *tracer; const struct cred *cred; pid_t ppid, tpid = 0, tgid, ngid; unsigned int max_fds = 0; rcu_read_lock(); ppid = pid_alive(p) ? task_tgid_nr_ns(rcu_dereference(p->real_parent), ns) : 0; tracer = ptrace_parent(p); if (tracer) tpid = task_pid_nr_ns(tracer, ns); tgid = task_tgid_nr_ns(p, ns); ngid = task_numa_group_id(p); cred = get_task_cred(p); umask = get_task_umask(p); if (umask >= 0) seq_printf(m, "Umask:\t%#04o\n", umask); task_lock(p); if (p->files) max_fds = files_fdtable(p->files)->max_fds; task_unlock(p); rcu_read_unlock(); seq_printf(m, "State:\t%s", get_task_state(p));-----------------------------"R (running)"/"S (sleeping)"/"D (disk sleep)"/"T (stopped)"/"t (tracing stop)"/"X (dead)"/"Z (zombie)"
D is sleeping in an uninterruptible wait.
 seq_put_decimal_ull(m, "\nTgid:\t", tgid);----------------------------------線程組ID,也就是線程組leader的進程id,等於pid。 seq_put_decimal_ull(m, "\nNgid:\t", ngid);----------------------------------進程所屬的NUMA id。 seq_put_decimal_ull(m, "\nPid:\t", pid_nr_ns(pid, ns));---------------------進程pid。 seq_put_decimal_ull(m, "\nPPid:\t", ppid);----------------------------------進程的父進程pid。 seq_put_decimal_ull(m, "\nTracerPid:\t", tpid);-----------------------------ptrace對應的進程id。 seq_put_decimal_ull(m, "\nUid:\t", from_kuid_munged(user_ns, cred->uid));---實際用戶id,指的是進程執行者是誰。 seq_put_decimal_ull(m, "\t", from_kuid_munged(user_ns, cred->euid));--------有效用戶id,指進程執行時對系統資源的訪問權限。 seq_put_decimal_ull(m, "\t", from_kuid_munged(user_ns, cred->suid));--------保存設置用戶id,是進程剛開始執行時euid的副本。在執行exec調用以後能從新恢復原來的euid。 seq_put_decimal_ull(m, "\t", from_kuid_munged(user_ns, cred->fsuid));-------一般等於euid,用於訪問文件時檢查訪問權限。 seq_put_decimal_ull(m, "\nGid:\t", from_kgid_munged(user_ns, cred->gid)); seq_put_decimal_ull(m, "\t", from_kgid_munged(user_ns, cred->egid)); seq_put_decimal_ull(m, "\t", from_kgid_munged(user_ns, cred->sgid)); seq_put_decimal_ull(m, "\t", from_kgid_munged(user_ns, cred->fsgid)); seq_put_decimal_ull(m, "\nFDSize:\t", max_fds);-----------------------------進程已打開最大文件描述符數。這個值不是文件描述符的上限,也不是實際使用中的文件描述符數量。以32遞增。 seq_puts(m, "\nGroups:\t");-------------------------------------------------Supplementary group list. group_info = cred->group_info; for (g = 0; g < group_info->ngroups; g++) seq_put_decimal_ull(m, g ? " " : "", from_kgid_munged(user_ns, group_info->gid[g])); put_cred(cred); /* Trailing space shouldn't have been added in the first place. */ seq_putc(m, ' '); ... seq_putc(m, '\n'); } void task_mem(struct seq_file *m, struct mm_struct *mm) { unsigned long text, lib, swap, ptes, pmds, anon, file, shmem; unsigned long hiwater_vm, total_vm, hiwater_rss, total_rss; anon = get_mm_counter(mm, MM_ANONPAGES); file = get_mm_counter(mm, MM_FILEPAGES); shmem = get_mm_counter(mm, MM_SHMEMPAGES);  hiwater_vm = total_vm = mm->total_vm; if (hiwater_vm < mm->hiwater_vm) hiwater_vm = mm->hiwater_vm; hiwater_rss = total_rss = anon + file + shmem; if (hiwater_rss < mm->hiwater_rss) hiwater_rss = mm->hiwater_rss; text = (PAGE_ALIGN(mm->end_code) - (mm->start_code & PAGE_MASK)) >> 10; lib = (mm->exec_vm << (PAGE_SHIFT-10)) - text; swap = get_mm_counter(mm, MM_SWAPENTS); ptes = PTRS_PER_PTE * sizeof(pte_t) * atomic_long_read(&mm->nr_ptes); pmds = PTRS_PER_PMD * sizeof(pmd_t) * mm_nr_pmds(mm); seq_printf(m, "VmPeak:\t%8lu kB\n"------------------------------------虛擬內存使用量的峯值,取mm->total_vm和mm->hiwater_vm的大值。
        "VmSize:\t%8lu kB\n"------------------------------------當前虛擬內存的實際使用量。
        "VmLck:\t%8lu kB\n"-------------------------------------PG_mlocked屬性的頁面總量,常被mlock()置位。
        "VmPin:\t%8lu kB\n"-------------------------------------不可被移動的Pined Memory內存大小。
        "VmHWM:\t%8lu kB\n"-------------------------------------HWM是High Water Mark的意思,表示rss的峯值。
        "VmRSS:\t%8lu kB\n"-------------------------------------應用程序實際佔用的物理內存大小,這裏和VmSize有區別。VmRss要小於等於VmSize。
        "RssAnon:\t%8lu kB\n"-----------------------------------匿名RSS內存大小。
        "RssFile:\t%8lu kB\n"-----------------------------------文件RSS內存大小。
        "RssShmem:\t%8lu kB\n"----------------------------------共享內存RSS內存大小。
        "VmData:\t%8lu kB\n"------------------------------------程序數據段的所佔虛擬內存大小,存放了初始化了的數據。
        "VmStk:\t%8lu kB\n"-------------------------------------進程在用戶態的棧大小。
        "VmExe:\t%8lu kB\n"-------------------------------------進程主程序代碼段內存使用量,即text段大小。
        "VmLib:\t%8lu kB\n"-------------------------------------進程共享庫內存使用量。
        "VmPTE:\t%8lu kB\n"-------------------------------------進程頁表項Page Table Entries內存使用量。
        "VmPMD:\t%8lu kB\n"-------------------------------------進程PMD內存使用量。
        "VmSwap:\t%8lu kB\n",-----------------------------------進程swap使用量。 hiwater_vm << (PAGE_SHIFT-10), total_vm << (PAGE_SHIFT-10), mm->locked_vm << (PAGE_SHIFT-10), mm->pinned_vm << (PAGE_SHIFT-10), hiwater_rss << (PAGE_SHIFT-10), total_rss << (PAGE_SHIFT-10), anon << (PAGE_SHIFT-10), file << (PAGE_SHIFT-10), shmem << (PAGE_SHIFT-10), mm->data_vm << (PAGE_SHIFT-10), mm->stack_vm << (PAGE_SHIFT-10), text, lib, ptes >> 10, pmds >> 10, swap << (PAGE_SHIFT-10)); hugetlb_report_usage(m, mm); } static inline void task_sig(struct seq_file *m, struct task_struct *p) { unsigned long flags; sigset_t pending, shpending, blocked, ignored, caught; int num_threads = 0; unsigned long qsize = 0; unsigned long qlim = 0; sigemptyset(&pending); sigemptyset(&shpending); sigemptyset(&blocked); sigemptyset(&ignored); sigemptyset(&caught); if (lock_task_sighand(p, &flags)) { pending = p->pending.signal; shpending = p->signal->shared_pending.signal; blocked = p->blocked; collect_sigign_sigcatch(p, &ignored, &caught); num_threads = get_nr_threads(p); rcu_read_lock(); /* FIXME: is this correct? */ qsize = atomic_read(&__task_cred(p)->user->sigpending); rcu_read_unlock(); qlim = task_rlimit(p, RLIMIT_SIGPENDING); unlock_task_sighand(p, &flags); } seq_put_decimal_ull(m, "Threads:\t", num_threads);----------當前進程下總的線程數。 seq_put_decimal_ull(m, "\nSigQ:\t", qsize); seq_put_decimal_ull(m, "/", qlim);--------------------------<qsize>/<qlim>分別表示當前進程的信號隊列大小和系統對信號隊列的閾值。 /* render them all */ render_sigset_t(m, "\nSigPnd:\t", &pending);----------------信號隊列中處於pending狀態的位圖。 render_sigset_t(m, "ShdPnd:\t", &shpending);----------------線程組中處於pending狀態的位圖。 render_sigset_t(m, "SigBlk:\t", &blocked);------------------處於阻塞blocked狀態的信號位圖。 render_sigset_t(m, "SigIgn:\t", &ignored);------------------被忽略的信號位圖,產生這些信號不進行處理。 render_sigset_t(m, "SigCgt:\t", &caught);-------------------已經捕獲到的信號位圖。 } static inline void task_cap(struct seq_file *m, struct task_struct *p) { const struct cred *cred; kernel_cap_t cap_inheritable, cap_permitted, cap_effective, cap_bset, cap_ambient; rcu_read_lock(); cred = __task_cred(p); cap_inheritable = cred->cap_inheritable; cap_permitted = cred->cap_permitted; cap_effective = cred->cap_effective; cap_bset = cred->cap_bset; cap_ambient = cred->cap_ambient; rcu_read_unlock(); render_cap_t(m, "CapInh:\t", &cap_inheritable);----------------表示能被子進程繼承的能力。 render_cap_t(m, "CapPrm:\t", &cap_permitted);------------------進程被容許使用的能力。 render_cap_t(m, "CapEff:\t", &cap_effective);------------------進程要使用某個特權時,系統會檢查cap_effective對應爲是否有效。cap_effective是cap_permitted子集。 render_cap_t(m, "CapBnd:\t", &cap_bset);-----------------------表示進程能得到的最大能力。 render_cap_t(m, "CapAmb:\t", &cap_ambient); } static void task_cpus_allowed(struct seq_file *m, struct task_struct *task) { seq_printf(m, "Cpus_allowed:\t%*pb\n", cpumask_pr_args(&task->cpus_allowed));--------------進程可運行CPU列表。 seq_printf(m, "Cpus_allowed_list:\t%*pbl\n", cpumask_pr_args(&task->cpus_allowed)); } /* Display task mems_allowed in /proc/<pid>/status file. */
void cpuset_task_status_allowed(struct seq_file *m, struct task_struct *task) { seq_printf(m, "Mems_allowed:\t%*pb\n", nodemask_pr_args(&task->mems_allowed));------------進程可以使用的內存節點。 seq_printf(m, "Mems_allowed_list:\t%*pbl\n", nodemask_pr_args(&task->mems_allowed)); } static inline void task_context_switch_counts(struct seq_file *m, struct task_struct *p) { seq_put_decimal_ull(m, "voluntary_ctxt_switches:\t", p->nvcsw);-----------線程主動切換次數。 seq_put_decimal_ull(m, "\nnonvoluntary_ctxt_switches:\t", p->nivcsw);-----線程被動切換次數。 seq_putc(m, '\n'); }

信號位圖和信號值對應關係:位圖bit=信號值-1。spa

#define SIGHUP         1
#define SIGINT         2
#define SIGQUIT         3
#define SIGILL         4
#define SIGTRAP         5
#define SIGABRT         6
#define SIGIOT         6
#define SIGBUS         7
#define SIGFPE         8
#define SIGKILL         9
#define SIGUSR1        10
#define SIGSEGV        11
#define SIGUSR2        12
#define SIGPIPE        13
#define SIGALRM        14
#define SIGTERM        15
#define SIGSTKFLT    16
#define SIGCHLD        17
#define SIGCONT        18
#define SIGSTOP        19
#define SIGTSTP        20
#define SIGTTIN        21
#define SIGTTOU        22
#define SIGURG        23
#define SIGXCPU        24
#define SIGXFSZ        25
#define SIGVTALRM    26
#define SIGPROF        27
#define SIGWINCH    28
#define SIGIO        29
#define SIGPOLL        SIGIO
#define SIGPWR        30
#define SIGSYS        31
#define    SIGUNUSED    31

#define SIGRTMIN    32 #ifndef SIGRTMAX #define SIGRTMAX    _NSIG
#endif

2. 一個進程status實例解析

 下面結合一個實例,解析一下status。線程

Name: Log2Hostflush
Umask: 0022
State: D (disk sleep)-----------------------表示此時線程處於sleeping,而且是uninterruptible狀態的wait。code

Tgid: 157-----------------------------------線程組的主pid爲157。
Ngid: 0
Pid: 159------------------------------------線程自身的pid爲159。
PPid: 1-------------------------------------線程組是由init進程建立的。
TracerPid: 0
Uid: 0 0 0 0
Gid: 0 0 0 0
FDSize: 256---------------------------------表示到目前爲止進程使用過的描述符總數。
Groups: 0 10
VmPeak: 1393220 kB--------------------------虛擬內存峯值大小。
VmSize: 1390372 kB--------------------------當前使用中的虛擬內存,小於VmPeak。
VmLck: 0 kB
VmPin: 0 kB
VmHWM: 47940 kB-----------------------------RSS峯值。
VmRSS: 47940 kB-----------------------------RSS實際使用量=RSSAnon+RssFile+RssShmem。
RssAnon: 38700 kB
RssFile: 9240 kB
RssShmem: 0 kB
VmData: 366648 kB--------------------------進程數據段共366648KB。
VmStk: 132 kB------------------------------進程棧一共132KB。
VmExe: 84 kB-------------------------------進程text段大小84KB。
VmLib: 11488 kB----------------------------進程lib佔用11488KB內存。
VmPTE: 1220 kB
VmPMD: 0 kB
VmSwap: 0 kB
Threads: 40-------------------------------進程中一個40個線程。
SigQ: 0/3142------------------------------進程信號隊列最大3142,當前沒有pending狀態的信號。
SigPnd: 0000000000000000------------------沒有進程pending,因此位圖爲0。
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000000006------------------被忽略的信號,對應信號爲SIGINT和SIGQUIT,這兩個信號產生也不會進行處理。
SigCgt: 0000000180000800------------------已經產生的信號位圖,對應信號爲SIGUSR二、以及實時信號32和33。
CapInh: 0000000000000000
CapPrm: 0000003fffffffff
CapEff: 0000003fffffffff
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
Cpus_allowed: 1---------------------------僅在第1個cpu上執行。
Cpus_allowed_list: 0
voluntary_ctxt_switches: 2377-------------線程主動切換2377次,被動切換5次。
nonvoluntary_ctxt_switches: 5blog

相關文章
相關標籤/搜索