• /proc/<pid>/status简要分析


    关键词:status、virtual memory、signal、capability、context switch等等。

    每个进程/线程都有自己私有状态,在/proc/<pid>status中体现。

    了解status中每项的含义,有助于问题定位时发现问题。

    下面结合status在内中函数proc_pid_status()对每一项进行简单的了解,然后结合一个示例进行分析。

    1. status在内核中的解释

    status当前进程/线程的名称、运行状态、pid、信号、权限、cpu使用范围、进程切换等等信息。

    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:	%#04o
    ", 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:	%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, "
    Tgid:	", tgid);----------------------------------线程组ID,也就是线程组leader的进程id,等于pid。
        seq_put_decimal_ull(m, "
    Ngid:	", ngid);----------------------------------进程所属的NUMA id。
        seq_put_decimal_ull(m, "
    Pid:	", pid_nr_ns(pid, ns));---------------------进程pid。
        seq_put_decimal_ull(m, "
    PPid:	", ppid);----------------------------------进程的父进程pid。
        seq_put_decimal_ull(m, "
    TracerPid:	", tpid);-----------------------------ptrace对应的进程id。
        seq_put_decimal_ull(m, "
    Uid:	", from_kuid_munged(user_ns, cred->uid));---实际用户id,指的是进程执行者是谁。
        seq_put_decimal_ull(m, "	", from_kuid_munged(user_ns, cred->euid));--------有效用户id,指进程执行时对系统资源的访问权限。
        seq_put_decimal_ull(m, "	", from_kuid_munged(user_ns, cred->suid));--------保存设置用户id,是进程刚开始执行时euid的副本。在执行exec调用之后能重新恢复原来的euid。
        seq_put_decimal_ull(m, "	", from_kuid_munged(user_ns, cred->fsuid));-------通常等于euid,用于访问文件时检查访问权限。
        seq_put_decimal_ull(m, "
    Gid:	", from_kgid_munged(user_ns, cred->gid));
        seq_put_decimal_ull(m, "	", from_kgid_munged(user_ns, cred->egid));
        seq_put_decimal_ull(m, "	", from_kgid_munged(user_ns, cred->sgid));
        seq_put_decimal_ull(m, "	", from_kgid_munged(user_ns, cred->fsgid));
        seq_put_decimal_ull(m, "
    FDSize:	", max_fds);-----------------------------进程已打开最大文件描述符数。这个值不是文件描述符的上限,也不是实际使用中的文件描述符数量。以32递增。
    
        seq_puts(m, "
    Groups:	");-------------------------------------------------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, '
    ');
    }
    
    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:	%8lu kB
    "------------------------------------虚拟内存使用量的峰值,取mm->total_vm和mm->hiwater_vm的大值。
            "VmSize:	%8lu kB
    "------------------------------------当前虚拟内存的实际使用量。
            "VmLck:	%8lu kB
    "-------------------------------------PG_mlocked属性的页面总量,常被mlock()置位。
            "VmPin:	%8lu kB
    "-------------------------------------不可被移动的Pined Memory内存大小。
            "VmHWM:	%8lu kB
    "-------------------------------------HWM是High Water Mark的意思,表示rss的峰值。
            "VmRSS:	%8lu kB
    "-------------------------------------应用程序实际占用的物理内存大小,这里和VmSize有区别。VmRss要小于等于VmSize。
            "RssAnon:	%8lu kB
    "-----------------------------------匿名RSS内存大小。
            "RssFile:	%8lu kB
    "-----------------------------------文件RSS内存大小。
            "RssShmem:	%8lu kB
    "----------------------------------共享内存RSS内存大小。
            "VmData:	%8lu kB
    "------------------------------------程序数据段的所占虚拟内存大小,存放了初始化了的数据。
            "VmStk:	%8lu kB
    "-------------------------------------进程在用户态的栈大小。
            "VmExe:	%8lu kB
    "-------------------------------------进程主程序代码段内存使用量,即text段大小。
            "VmLib:	%8lu kB
    "-------------------------------------进程共享库内存使用量。
            "VmPTE:	%8lu kB
    "-------------------------------------进程页表项Page Table Entries内存使用量。
            "VmPMD:	%8lu kB
    "-------------------------------------进程PMD内存使用量。
            "VmSwap:	%8lu kB
    ",-----------------------------------进程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:	", num_threads);----------当前进程下总的线程数。
        seq_put_decimal_ull(m, "
    SigQ:	", qsize);
        seq_put_decimal_ull(m, "/", qlim);--------------------------<qsize>/<qlim>分别表示当前进程的信号队列大小和系统对信号队列的阈值。
    
        /* render them all */
        render_sigset_t(m, "
    SigPnd:	", &pending);----------------信号队列中处于pending状态的位图。
        render_sigset_t(m, "ShdPnd:	", &shpending);----------------线程组中处于pending状态的位图。
        render_sigset_t(m, "SigBlk:	", &blocked);------------------处于阻塞blocked状态的信号位图。
        render_sigset_t(m, "SigIgn:	", &ignored);------------------被忽略的信号位图,产生这些信号不进行处理。
        render_sigset_t(m, "SigCgt:	", &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:	", &cap_inheritable);----------------表示能被子进程继承的能力。
        render_cap_t(m, "CapPrm:	", &cap_permitted);------------------进程被允许使用的能力。
        render_cap_t(m, "CapEff:	", &cap_effective);------------------进程要使用某个特权时,系统会检查cap_effective对应为是否有效。cap_effective是cap_permitted子集。
        render_cap_t(m, "CapBnd:	", &cap_bset);-----------------------表示进程能获得的最大能力。
        render_cap_t(m, "CapAmb:	", &cap_ambient);
    }
    
    static void task_cpus_allowed(struct seq_file *m, struct task_struct *task)
    {
        seq_printf(m, "Cpus_allowed:	%*pb
    ",
               cpumask_pr_args(&task->cpus_allowed));--------------进程可运行CPU列表。
        seq_printf(m, "Cpus_allowed_list:	%*pbl
    ",
               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:	%*pb
    ",
               nodemask_pr_args(&task->mems_allowed));------------进程可使用的内存节点。
        seq_printf(m, "Mems_allowed_list:	%*pbl
    ",
               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:	", p->nvcsw);-----------线程主动切换次数。
        seq_put_decimal_ull(m, "
    nonvoluntary_ctxt_switches:	", p->nivcsw);-----线程被动切换次数。
        seq_putc(m, '
    ');
    }

    信号位图和信号值对应关系:位图bit=信号值-1。

    #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。

    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------------------已经产生的信号位图,对应信号为SIGUSR2、以及实时信号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: 5

  • 相关阅读:
    字符串常量
    二维数组中的查找
    Codeforces 156B Suspects——————【逻辑判断】
    Codeforces 156 A——Message——————【思维题】
    Codeforces 639B——Bear and Forgotten Tree 3——————【构造、树】
    Codeforces 671 A——Recycling Bottles——————【思维题】
    Codeforces 550D —— Regular Bridge——————【构造】
    Codeforces 550C —— Divisibility by Eight——————【枚举 || dp】
    codeforces 638B—— Making Genome in Berland——————【类似拓扑排序】
    codeforces 675 C ——Money Transfers——————【思维题】
  • 原文地址:https://www.cnblogs.com/arnoldlu/p/12162860.html
Copyright © 2020-2023  润新知