在Linux的top和ps命令中,专断认同看到最多的是pid (process
ID),或许你也能看到lwp (thread ID)和tgid (thread group ID for the thread
group leader)等等,而在Linux库函数和系统调用里恐怕你放在心上到了pthread
id和tid等等。还有越来越多的ID,比如pgrp (process group ID), sid (session ID
for the session leader)和 tpgid (tty process group ID for the process
group
leader)。概念太多恐怕很晕,可是一旦对Linux的历程和线程的基本概念有确切的精晓,那一个ID的含义都消除。上面将介绍进度和线程的基本概念,并以一个演示程序来表明那个ID之间的涉及。

add by zhj: 上面是自个儿对pid,tgid,ppid的私家了然

Java 系统品质分析 命令

转自:

 

对此ubuntu14.04操作系统,可以在/usr/src/linux-headers-4.4.0-31/include/linux/sched.h文本中旁观进程控制块的结构体,如下

  1. cpu分析
    top , pidstat(sysstat)
    pid -p PID -t 1 10
    vmstat 1 CPU上下文切换、运行队列、利用率
    ps Hh -eo tid
    pcpu 查看具体线程的CPU消耗
    sar 来查看一定世界范围内以及历史的cpu消耗意况消息

那篇博客,想集中在signal
与线程的关系上,顺带介绍内核signal相关的布局。怎么着协会自己骨子里并没想好,想到哪就写到哪个地方吗。大旨一定会落在signal之内而不跑题。
   
提到signal与thread的关联,就得先提POSIX标准。POSIX标准控制了Linux为啥将signal如此达成:
   1
信号处理函数必须在多线程应用的持有线程之间共享,不过,各个线程要有投机的挂起信号掩码和鸿沟信号掩码。
   2 POSIX
函数kill/sigqueue必须面向所有的多线程应用而不是某个特殊的线程。
   3
每种发给三十二线程应用的信号仅传送给1个线程,那几个线程是由基本从不会堵塞该信号的线程中随机选出。
   4
如若发送一个沉重信号到二十四线程,那么内核将杀死该应用的所无线程,而不只是收取信号的丰富线程。

Linux的长河和线程

Linux的经过和线程有不胜枚举异同点,能够谷歌(Google)下。但万一能分晓地领悟一下几点,则充足领悟Linux中各类ID的含义。

  • Linux下怎么着查看高CPU占用率线程,那一个事情。进度是资源分配的主干单位,线程是调度的主题单位
  • 经过是资源的成团,这个资源包含内存地址空间,文件描述符等等,一个历程中的七个线程共享这么些资源。
  • CPU对职务拓展调度时,可调度的大旨单位
    (dispatchable
    entity)是线程。倘使一个进度中从不任何线程,可以知道成这一个历程中唯有一个主线程,那么些主进程独享进度中的所有资源。
  • 进程的私有间是全然独立的,而线程间是互相依存,并且共享资源。多进度环境中,任何一个经过的停下,不会影响到任何非子进度。而多线程环境中,父线程终止,全体子线程被迫截至(没有了资源)。

上述第一点表明是最基础的,也是最主要的。

 

开班通晓各个ID。基本上依据重点程度从高到低,在分割线下方的IDs不太重大。

  • pid: 进程ID。
  • lwp:
    线程ID。在用户态的通令(比如ps)中常用的突显方式。
  • tid:
    线程ID,等于lwp。tid在系统提供的接口函数中更常用,比如syscall(SYS_gettid)和syscall(__NR_gettid)。
  • tgid:
    线程组ID,约等于线程组leader的长河ID,等于pid。
  • ——分割线——
  • pgid: 进度组ID,也等于经过组leader的经过ID。
  • pthread id: pthread库提供的ID,生效范围不在系统级别,可以忽略。
  • sid: session ID for the session leader。
  • tpgid: tty process group ID for the process group leader。

 从上面的列表看出,各个ID最终都总结到pid和lwp(tid)上。所以了解各个ID,最毕竟结为精通pid和lwp(tid)的联系和差异。

 

上边的图是一张讲述父子进度,线程之间关系的图。

澳门金沙国际 1

上图很好地描述了用户意见(user view)和水源视角(kernel
view)看到线程的不同:

  • 从用户意见出发,在pid 42中发出的tid
    44线程,属于tgid(线程组leader的经过ID)
    42。甚至用ps和top的暗中同意参数,你都无法见到tid 44线程。
  • 从根本视角出发,tid 42和tid
    44是单独的调度单元,能够把她们就是”pid 42″和”pid 44″。

必要提议的是,有时候在Linux中经过和线程的分歧也是还是不是尤其残酷的。即使线程和经过混用,pid和tid混用,依照上下文,依旧得以知晓地区分对方想要表明的意味。上图中,从基本视角出发看到了pid
44,是从调度单元的角度出发,不过在top或ps命令中,你是纯属找不到一个pid为44的历程的,只可以看看一个lwp(tid)为44的线程。

 

struct task_struct {
        volatile long state;    /* -1 unrunnable, 0 runnable, >0 stopped */
        void *stack;
        atomic_t usage;
        unsigned int flags;     /* per process flags, defined below */
        unsigned int ptrace;

#ifdef CONFIG_SMP
        struct llist_node wake_entry;
        int on_cpu;
        unsigned int wakee_flips;
        unsigned long wakee_flip_decay_ts;
        struct task_struct *last_wakee;

        int wake_cpu;
#endif
        ......
        ......
        pid_t pid;
        pid_t tgid;
        ......
        ......
}

查阅java线程消息
jstack pid | grep ‘nid=0x9999’

   
上边是POSIX标准,相当于指出来的必要,Linux要根据POSIX标准,那Linux是怎么办到的呢?
   
到了那里,大家需求清理一些基本的概念:

略知一二pid和lwp(tid)的示范程序

上边选用一个演示程序来更为通晓pid和lwp(tid),以及选拔格式化的ps命令打印出各样ID。上面的程序在main函数中开创了2个子线程,加上main函数那几个主线程,一共有3个线程。在3个线程中分头打印pthread
id, pid和lwp(tid),来验证pid和lwp(tid)的涉嫌。

 1 #include <unistd.h>
 2 #include <sys/syscall.h>
 3 #include <stdio.h>
 4 #include <pthread.h>
 5 
 6 #define gettidv1() syscall(__NR_gettid) // new form
 7 #define gettidv2() syscall(SYS_gettid)  // traditional form
 8 
 9 void *ThreadFunc1()
10 {
11         printf("the pthread_1 id is %ld\n", pthread_self());
12         printf("the thread_1's Pid is %d\n", getpid());
13         printf("The LWPID/tid of thread_1 is: %ld\n", (long int)gettidv1());
14         pause();
15 
16         return 0;
17 }
18 
19 void *ThreadFunc2()
20 {
21         printf("the pthread_2 id is %ld\n", pthread_self());
22         printf("the thread_2's Pid is %d\n", getpid());
23         printf("The LWPID/tid of thread_2 is: %ld\n", (long int)gettidv1());
24         pause();
25 
26         return 0;
27 }
28 
29 int main(int argc, char *argv[])
30 {
31         pid_t tid;
32         pthread_t pthread_id;
33 
34         printf("the master thread's pthread id is %ld\n", pthread_self());
35         printf("the master thread's Pid is %d\n", getpid());
36         printf("The LWPID of master thread is: %ld\n", (long int)gettidv1());
37 
38         // 创建2个线程
39         pthread_create(&pthread_id, NULL, ThreadFunc2, NULL);
40         pthread_create(&pthread_id, NULL, ThreadFunc1, NULL);
41         pause();
42 
43         return 0;
44 }

专注编译的时候要选用-l指定library参数。

# gcc threadTest.c -o threadTest -l pthread

 

举行顺序,结果如下:

# ./threadTest
the master thread's pthread id is 140154481125184
the master thread's Pid is 20992
The LWPID of master thread is: 20992
the pthread_1 id is 140154464352000
the thread_1's Pid is 20992
The LWPID/tid of thread_1 is: 20994
the pthread_2 id is 140154472744704
the thread_2's Pid is 20992
The LWPID/tid of thread_2 is: 20993

上述结果申明pthread
id是pthread库提供的ID,在系统级别没有意思。pid都以线程组leader的进度ID,即20992。而lwp(tid)则是线程ID,分别是20993和20994。

 

并且接纳ps来查看结果,注意ps暗中同意只打印进度级别消息,须求用-L选项来查看线程基本信息。

# ps -eo pid,tid,lwp,tgid,pgrp,sid,tpgid,args -L | awk '{if(NR==1) print $0; if($8~/threadTest/) print $0}'
  PID   TID   LWP  TGID  PGRP   SID TPGID COMMAND
20992 20992 20992 20992 20992 30481 20992 ./threadTest
20992 20993 20993 20992 20992 30481 20992 ./threadTest
20992 20994 20994 20992 20992 30481 20992 ./threadTest

从上述结果中可以看出:

  • PID=TGID: 20992
  • TID=LWP: 20993 or 20994
  • 至于SID,30481是bash shell的进程ID。

 

可以见见,里面定义了五个字段,pid和tgid,其中pid就是其一轻量级进度lwp的id,而tgid是轻量级过程组的id,当创建进度时,我们得以为祥和指定

  1. cs sy消耗比较高
    上下文切换质量偏高, jstack -l pid, 查看on object monitor

  2. io消耗
    pidstat -d -t -p pid 1 100
    iostat

  3. 网络io消耗
    cat /proc/interruptes
    sar -n FULL 1 2
    tcpdump

  1. struct task_struct {

  2.     pid_t pid;

  3.     pid_t tgid

  4.       …..

  5.     struct task_struct *group_leader;    /* threadgroup leader */

  6.       ……

  7.     struct list_head thread_group;

  8.         ….

  9. }

        从字面意思上看 pid,是process
    id,其则不然,pid是thread id。从字面意思上看,tgid是thread group
    id,其则是的确的pid。
       
    有点绕是否?对于一个二十二十四线程的程序,无论是哪个线程执行getpid,结果皆以千篇一律的,最后回到的同一个值
    tgid。如果我们贯彻了gettid(很沮丧的是glibc没有那几个函数,所以大家要用syscall),我们就会发现,各类线程重回的值不一致,此时,重回的值是内核task_struct中的pid。对于三十二线程应用/proc/pid/task可以看出的,就是线程的thread
    id,相当于task_struct中的pid。
     
     澳门金沙国际 2
        我在自我的博文Linux线程之线程 线程组
    进程轻量级进度(LWP)关联了这几个难点。我不想多浪费笔墨赘述。
        group
    leader字段,指向线程组的首先个线程。对于大家协调的次第而言,main函数所在的线程,约等于线程组的第二个线程,所以group
    leader就会他本身。一旦用pthread_create创立了线程,那么main所在的线程,还有创建出来的线程,隶属于同一个线程组,线程的group
    leader如故main函数所在的线程id。
       
    thread_group,同一线程组的具备线程的行列。对于group_leader,那是一个队列头,对于同一线程组的其他线程,通过那几个字段挂入队列。可以依照这些行列,遍历线程组的具有线程。
       
     是时候看看内核代码了,上边的代码属于do_fork函数及copy_process函数的局部代码。     
     

Linux用户态命令查看线程

经过的tgid字段,貌似可以任由指定,只要存在就行,此外在父进度中,可以为子过程设置进程组id,如果没有点名,它会继续父进程的进度组id。

  1.     p->pid = pid_nr(pid);

  2.     p->tgid =
    p->pid;

  3.     if (clone_flags & CLONE_THREAD)//创造线程,tgid等于当前线程的

  4.         p->tgid =
    current->tgid;

  5.     p->group_leader = p;

  6.     INIT_LIST_HEAD(&p->thread_group);

  7.     if (clone_flags & CLONE_THREAD)
    { //线程处理部分,group_leader都以首先个线程。同时挂入队列

  8.         current->signal->nr_threads++;

  9.         atomic_inc(&current->signal->live);

  10.         atomic_inc(&current->signal->sigcnt);

  11.         p->group_leader = current->group_leader;

  12.         list_add_tail_rcu(&p->thread_group, &p->group_leader->thread_group);

  13.     }

       
    代码阐明,第四个线程呢,pid和tgid相同,都以分配的卓殊pid,group_leader也是团结。前边第三个线程,pid是自身的,但是tgid
    等于制造者的tgid,group_leader指向第四个线程的task_struct.
    后边创设的富有的线程,都会挂入队列,方便遍线程组的具备线程。
       
    有了线程组的概念,大家就可以进一步分解signal相关的情节了。 

top

暗中认同top突显的是task数量,即经过。

澳门金沙国际 3

可以运用敲”H”,来切换成线程。如下,可以见到实际有96个线程。也可以从来利用top
-H命令来一直打印线程景况。

澳门金沙国际 4

 

还有一个概念ppid,我没在这一个结构体中找到,但操作系统肯定是会记录的,在Python中,通过os.get_ppid()就足以拿走当前进程的父进度。tgid与ppid,

 

  1.    
    /* signal handlers */

  2.     struct signal_struct *signal;

  3.     struct sighand_struct *sighand;

  4.     sigset_t blocked,
    real_blocked;

  5.     sigset_t saved_sigmask;    /* restored
    if set_restore_sigmask() was used
    */

  6. 澳门金沙国际 ,    struct sigpending pending;

        澳门金沙国际 5
       
    线程组里面的具备成员共享一个signal_struct类型结构,同一线程组的四线程的task_struct
    中的signal指针都以指向同一个signal_struct。sighand成员变量也是这么,统一个线程组的多个线程指向同一个signalhand_struct结构。  

ps

ps的-L选项可以看来线程,经常能打印出LWP和NLWP相关音讯。如下命令即可查看线程音讯:

ps -eLf

 

那两者其实远非任何涉及,因为tgid是足以友善来指定的,日常主导不用,不用管它。

近年java应用,CPU使用率平素很高,平日达到100%,通过以下步骤完美消除,分享一下。

  1. static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)

  2. {

  3.     struct signal_struct *sig;

  4.     if (clone_flags & CLONE_THREAD) //线程,间接回到,注脚同一线程组共享

  5.         return 0;

  6.     sig = kmem_cache_zalloc(signal_cachep, GFP_KERNEL);

  7.     tsk->signal =
    sig;

  8.     if (!sig)

  9.         return -ENOMEM;

  10.     sig->nr_threads = 1;

  11.     atomic_set(&sig->live,
    1);

  12.     atomic_set(&sig->sigcnt,
    1);

  13.     init_waitqueue_head(&sig->wait_chldexit);

  14.     sig->curr_target = tsk;

  15.         。。。。

  16. }

  17. static int copy_sighand(unsigned long clone_flags, struct task_struct *tsk)

  18. {

  19.     struct sighand_struct *sig;

  20.     if (clone_flags & CLONE_SIGHAND) {

  21.         atomic_inc(&current->sighand->count);
    //若是发现是线程,直接讲引用计数++,无需分配sighand_struct结构

  22.    
        return 0;

  23.     }

  24.     sig = kmem_cache_alloc(sighand_cachep, GFP_KERNEL);

  25.     rcu_assign_pointer(tsk->sighand,
    sig);

  26.     if (!sig)

  27.         return -ENOMEM;

  28.     atomic_set(&sig->count,
    1);

  29.     memcpy(sig->action,
    current->sighand->action,
    sizeof(sig->action));

  30.     return 0;

  31. }

       
    那就主旨落成了二十四线程应用中,信号处理程序是共享的,因为她俩共用一个signalhand_struct。
       
    上一篇博文提到,signal->shared_pending
    和pending多个挂起信号有关的数据结构,此处大家可以切切实实讲解了。signal是线程组共享的布局,自然下属的shared_pending也是线程组共享的。如同POSIX提到的,kill/sigqueue发送信号,发送的对象并不是线程组某个特定的线程,而是所无线程组。自然,假若kernel会将信号记录在全线程组共享的signal->shared_pending,表示,线程组收到信号X一枚。
       
    有筒子说了,我快要给某个特定的线程发信号,有没有措施,内核怎么办?那是个好题材。 
     

pidstat

pidstat -t [-p pid号] 可以打印出线程之间的涉嫌。

 

 

方法一:

  1.   int
    tkill(int tid, int sig);

  2.   int tgkill(int tgid, int tid, int sig)

htop

要在htop中启用线程查看,开启htop,然后按<F2>来进入htop的设置菜单。接纳“设置”栏上面的“显示选项”,然后打开“树状视图”和“显示自定义线程名”选项。按<F10>退出设置。
注:MAC的F2按fn+F2。

 

 

转载:

   
那多个API是给线程组特定线程发信号的,毫不奇怪,内核会将信号记录在线程本人的协会pending中。

参考

Linux进程与线程的区分

原文:

1.jps 获取Java进程的PID。
2.jstack pid >> java.txt 导出CPU占用高进度的线程栈。
3.top -H -p
PID
查算命应进程的哪位线程占用CPU过高。
4.echo “obase=16; PID” | bc 将线程的PID转换为16进制,大写转换为小写。
5.在第二步导出的Java.txt中寻觅转换成为16进制的线程PID。找到相应的线程栈。
6.分析负载高的线程栈都以何许业务操作。优化程序并拍卖难点。

  1. pending = group ?
    &t->signal->shared_pending : &t->pending;

1、pid,tid,真实pid的使用

进程pid: getpid()                // 相当于os.getpid() 
线程tid: pthread_self()          //进程内唯一,但是在不同进程则不唯一。相当于thread.get_ident()
线程pid: syscall(SYS_gettid)     //系统内是唯一的。python中没有现成的方法,需要手动调用动态链接库ctypes.CDLL('libc.so.6').syscall(xx)

#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/syscall.h>

struct message
{
    int i;
    int j;
};

void *hello(struct message *str)
{
    printf("child, the tid=%lu, pid=%d\n",pthread_self(),syscall(SYS_gettid));
    printf("the arg.i is %d, arg.j is %d\n",str->i,str->j);
    printf("child, getpid()=%d\n",getpid());
    while(1);
}

int main(int argc, char *argv[])
{
    struct message test;
    pthread_t thread_id;
    test.i=10;
    test.j=20;
    pthread_create(&thread_id,NULL,hello,&test);
    printf("parent, the tid=%lu, pid=%d\n",pthread_self(),syscall(SYS_gettid));
    printf("parent, getpid()=%d\n",getpid());
    pthread_join(thread_id,NULL);
    return 0;
}

澳门金沙国际 6

getpid()得到的是进度的pid,在基本中,每种线程都有和好的PID,要拿到线程的PID,必须用syscall(SYS_gettid);

pthread_self函数获取的是线程ID,线程ID在某进程中是唯一的,在不一样的进度中创立的线程或许出现ID值相同的动静。

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>

void *thread_one()
{
    printf("thread_one:int %d main process, the tid=%lu,pid=%ld\n",getpid(),pthread_self(),syscall(SYS_gettid));
}

void *thread_two()
{
    printf("thread two:int %d main process, the tid=%lu,pid=%ld\n",getpid(),pthread_self(),syscall(SYS_gettid));
}

int main(int argc, char *argv[])
{
    pid_t pid;
    pthread_t tid_one,tid_two;
    if((pid=fork())==-1)
    {
        perror("fork");
        exit(EXIT_FAILURE);
    }
    else if(pid==0)
    {
        pthread_create(&tid_one,NULL,(void *)thread_one,NULL);
        pthread_join(tid_one,NULL);
    }
    else
    {
        pthread_create(&tid_two,NULL,(void *)thread_two,NULL);
        pthread_join(tid_two,NULL);
    }
    wait(NULL);
    return 0;
}

澳门金沙国际 7

方法二:

   
对于kill/sigqueue,__send_signal传进来的是group是true,对于tkill/tgkill传进来的是false。会将信号写入相应的挂起信号位图。

2、pid与tid的用途

Linux中,每一种进程有一个pid,类型pid_t,由getpid()取得。Linux下的POSIX线程也有一个id,类型pthread_t,由pthread_self()取得,该id由线程维护,其id空间是逐一进度独立的(即不一样进度中的线程或许有雷同的id)。你只怕知道,Linux中的POSIX线程库完毕的线程其实也是一个历程(LWP),只是该进程与主进度(启动线程的长河)共享一些资源而已,比如代码段,数据段等。
  有时候大家大概须要知道线程的实际pid。比如进度P1要向其余一个经过P2中的某个线程发送信号时,既不大概应用P2的pid,更不能利用线程的pthread
id,而不得不接纳该线程的真人真事pid,称为tid。
  有一个函数gettid()可以拿走tid,但glibc并从未落到实处该函数,只可以通过Linux的连串调用syscall来获取。使用syscall得到tid只需一行代码,但为了深化各位看官的回忆,简单提供上边场景。
  有一簇进度,其中一个进程中其余启了一个线程。各进度共享一个数据结构,由shared_ptr指明,其中保存有线程的tid。在逐一进度的履行进度中,须求判定线程是不是存在,若不设有则(重新)创造。
  首先,在线程函数的初阶,需求将协调的tid保存至共享内存,

点击(此处)折叠或打开

  1. #include <sys/syscall.h>
  2. #include <sys/types.h>
  3. void*
  4. thread_func(void *args)
  5. {
  6.     //~ lock shared memory
  7.     shared_ptr->tid = syscall(SYS_gettid); //~ gettid()
  8.     //~ unlock shared memory
  9.     //~ other stuff
  10. }

  在各进度中判断进度是或不是留存,

点击(此处)折叠或打开

  1. //~ lock shared memory
  2. pthread_t id;
  3. if (shared_ptr->tid == 0) { //~ tid is initialized to 0
  4.     pthread_create(&id, NULL, thread_func, NULL);
  5. } else if (shared_ptr->tid > 0) {
  6.     int ret = kill(shared_ptr->tid, 0); //~ send signal
    0 to thread
  7.     if (ret != 0) { //~ thread already died
  8.         pthread_create(&id, NULL, thread_func, NULL);
  9.     }
  10. }
  11. //~ unlock shared memory

1.选用top 定位到占用CPU高的长河PID
top
通过ps aux | grep PID命令

  1. static int __send_signal(int sig, struct siginfo *info, struct
    task_struct *t,

  2.             int group, int
    from_ancestor_ns)

  3. {

  4.     struct sigpending *pending;

  5.     struct sigqueue *q;

  6.     int override_rlimit;

  7.     int ret = 0,
    result;

  8.     assert_spin_locked(&t->sighand->siglock);

  9.     result =
    TRACE_SIGNAL_IGNORED;

  10.     if (!prepare_signal(sig, t,

  11.             from_ancestor_ns || (info ==
    SEND_SIG_FORCED)))

  12.         goto ret;

  13.     pending = group ? &t->signal->shared_pending : &t->pending;  
    // tkill用的协调的pending,

  14.                                                                  
    // kill/sigqueue用的线程组共享的signal->shared_pending

  15.     /*

  16.      * Short-circuit ignored signals and support queuing

  17.      * exactly one non-rt signal, so
    that we can get more

  18.      * detailed information about the
    cause of the signal.

  19.      */

  20.     result =
    TRACE_SIGNAL_ALREADY_PENDING;

  21.     if (legacy_queue(pending,
    sig))

  22.         goto ret;

  23.     result =
    TRACE_SIGNAL_DELIVERED;

  24.     /*

  25.      * fast-pathed signals for kernel-internal things like SIGSTOP

  26.      * or SIGKILL.

  27.      */

  28.     if (info == SEND_SIG_FORCED)

  29.         goto out_set;

  30.     /*

  31.      * Real-time signals
    must be queued if sent by
    sigqueue, or

  32.      * some other real-time
    mechanism. It is implementation

  33.      * defined whether kill() does
    so. We attempt to do so, on

  34.      * the principle of least
    surprise, but since kill is not

  35.      * allowed to fail with EAGAIN when low on memory we just

  36.      * make sure at least one signal
    gets delivered and don’t

  37.      * pass on the info struct.

  38.      */

  39.     if (sig <
    SIGRTMIN)

  40.         override_rlimit = (is_si_special(info) || info->si_code
    >=
    0);

  41.     else

  42.         override_rlimit = 0;

  43.     q = __sigqueue_alloc(sig, t, GFP_ATOMIC | __GFP_NOTRACK_FALSE_POSITIVE,

  44.         override_rlimit);

  45.     if (q) {

  46.         list_add_tail(&q->list,
    &pending->list);

  47.         switch ((unsigned long) info) {

  48.         case (unsigned long) SEND_SIG_NOINFO:

  49.             q->info.si_signo =
    sig;

  50.             q->info.si_errno =
    0;

  51.             q->info.si_code =
    SI_USER;

  52.             q->info.si_pid =
    task_tgid_nr_ns(current,

  53.                             task_active_pid_ns(t));

  54.             q->info.si_uid =
    from_kuid_munged(current_user_ns(), current_uid());

  55.             break;

  56.         case (unsigned long) SEND_SIG_PRIV:

  57.             q->info.si_signo =
    sig;

  58.             q->info.si_errno =
    0;

  59.             q->info.si_code =
    SI_KERNEL;

  60.             q->info.si_pid =
    0;

  61.             q->info.si_uid =
    0;

  62.             break;

  63.         default:

  64.             copy_siginfo(&q->info,
    info);

  65.             if (from_ancestor_ns)

  66.                 q->info.si_pid =
    0;

  67.             break;

  68.         }

  69.         userns_fixup_signal_uid(&q->info, t);

  70.     } else if (!is_si_special(info)) {

  71.         if (sig >= SIGRTMIN && info->si_code
    !=
    SI_USER) {

  72.             /*

  73.              * Queue overflow, abort. We
    may abort if the

  74.              * signal was rt and sent by user using something

  75.              * other than kill().

  76.              */

  77.             result =
    TRACE_SIGNAL_OVERFLOW_FAIL;

  78.             ret = -EAGAIN;

  79.             goto ret;

  80.         } else {

  81.             /*

  82.              * This is a silent loss of information. We still

  83.              * send the signal, but the *info bits are lost.

  84.              */

  85.             result =
    TRACE_SIGNAL_LOSE_INFO;

  86.         }

  87.     }

  88. out_set:

  89.     signalfd_notify(t, sig);

  90.     sigaddset(&pending->signal,
    sig);//修改位图,注明该信号存在挂起信号。

  91.     complete_signal(sig, t,
    group);

  92. ret:

  93.     trace_signal_generate(sig, info, t, group,
    result);

  94.     return ret;

  95. }

       
    线程存在一个很令人迷惑的题材,如何让线程组的有着线程一起退出。大家都晓得,三三十二线程的主次有一个线程访问了地下地址,引发段错误,会导致所有线程一起退出。那也是十六线程程序脆弱的地点。但是如何是好到的啊?
       
    do_signal—>get_signal_to_deliver中,会拔取信号,若是发现要求退出,会举行do_group_exit。那几个名字顾名思义了,线程组退出。 
     

3、linux 系统中查看pid,tid的办法

线程进度都会有和好的ID,从操作系统来讲,那几个ID就叫做PID

澳门金沙国际 8

 

 澳门金沙国际 9

 

2.得到线程音讯,并找到占用CPU高的线程
ps -mp pid -o
THREAD,tid,time
| sort -rn
譬如:

  1. void

  2. do_group_exit(int exit_code)

  3. {

  4.     struct signal_struct *sig = current->signal;

  5.     BUG_ON(exit_code & 0x80); /* core dumps don’t get here
    */

  6.     if (signal_group_exit(sig))

  7.         exit_code = sig->group_exit_code;

  8.     else if (!thread_group_empty(current)) {

  9.         struct sighand_struct *const sighand = current->sighand;

  10.         spin_lock_irq(&sighand->siglock);

  11.         if (signal_group_exit(sig))

  12.             /* Another thread got here before we took
    the lock. */

  13.             exit_code = sig->group_exit_code;

  14.         else {

  15.             sig->group_exit_code = exit_code;

  16.             sig->flags =
    SIGNAL_GROUP_EXIT;

  17.             zap_other_threads(current);

  18.         }

  19.         spin_unlock_irq(&sighand->siglock);

  20.     }

  21.     do_exit(exit_code);

  22.     /*
    NOTREACHED */

  23. }

       
    即使是三三十二线程,会走入到else中,主要的操作都在zap_other_threads函数中:

ps -mp 10073 -o THREAD,tid,time | sort -rn
  1. /*

  2.  * Nuke all other threads in the group.

  3.  */

  4. int zap_other_threads(struct task_struct *p)

  5. {

  6.     struct task_struct *t = p;

  7.     int count = 0;

  8.     p->signal->group_stop_count = 0;

  9.     while_each_thread(p, t) {

  10.         task_clear_jobctl_pending(t,
    JOBCTL_PENDING_MASK);

  11.         count++;

  12.         /* Don’t
    bother with already dead threads */

  13.         if (t->exit_state)

  14.             continue;

  15.         sigaddset(&t->pending.signal,
    SIGKILL);

  16.         signal_wake_up(t, 1);

  17.     }

  18.     return count;

  19. }

       
    不多说了,就是给每个线程都挂上一个SIGKILL的信号,当CPU采用线程执行时候的时候,自然会处理这几个信号,而对SIGKILL的拍卖,会重复调用do_group_exit。那四次会调用do_exit退出。当线程组所有进程都执行过之后,整个线程组就熄灭了。
        
       
    讲完那个,要求讲block了。我先是篇就讲到,我们有时候必要阻塞某些信号。POSIX说了三十二线程中每一个线程要有和好的鸿沟信号。不必说,task_struct中的blocked就是阻塞信号位图。大家的glibc的sigprocmask函数,就是设置进程的blocked。
       
    那么些block的信号为啥不可以传递,内核是怎么形成的?
          
     澳门金沙国际 10

澳门金沙国际 11

  1. int
    next_signal(struct sigpending *pending,
    sigset_t *mask)

  2. {

  3.     unsigned long i, *s, *m, x;

  4.     int sig = 0;

  5.     s = pending->signal.sig;

  6.     m = mask->sig;

  7.     /*

  8.      * Handle the first word
    specially: it contains the

  9.      * synchronous signals that need
    to be dequeued first.

  10.      */

  11.     x = *s &~ *m;

  12.     if (x) {

  13.         if (x &
    SYNCHRONOUS_MASK)

  14.             x &= SYNCHRONOUS_MASK;

  15.         sig = ffz(~x) + 1;

  16.         return sig;

  17.     }

  18.     switch (_NSIG_WORDS) {

  19.     default:

  20.         for (i = 1; i <
    _NSIG_WORDS; ++i) {

  21.             x = *++s &~ *++m;

  22.             if (!x)

  23.                 continue;

  24.             sig = ffz(~x) + i*_NSIG_BPW + 1;

  25.             break;

  26.         }

  27.         break;

  28.     case 2:

  29.         x = s[1] &~ m[1];

  30.         if (!x)

  31.             break;

  32.         sig = ffz(~x) +
    _NSIG_BPW + 1;

  33.         break;

  34.     case 1:

  35.         /* Nothing
    to do
    */

  36.         break;

  37.     }

  38.     return sig;

  39. }

       
    m就是task_struct中的blocked,阻塞的信号就不会不会被取出传递了。很有意思的一些是信号传递的相继。在Linux
    programming
    interface一书中涉及小signo优先的政策,比如SIGINT(2)和SIGQUIT(3)同时设有,SIGINT(2) 先deliver,然后才是SIGQUIT(3).大家看代码,很风趣的是有伙同信号:

 

  1. #define SYNCHRONOUS_MASK \

  2.     (sigmask(SIGSEGV)
    | sigmask(SIGBUS) | sigmask(SIGILL) | \

  3.      sigmask(SIGTRAP) |
    sigmask(SIGFPE) |
    sigmask(SIGSYS))

3.将急需的线程ID转换为16进制格式
printf “%x\n” tid

    有SIGSEGV SIGBUS SIGILL SIGTRAP SIGFPE
SIGSYS,那么那多少个信号优先。没有那多少个信号,根据小信号优先。当然了,这一个是Linux
kernel的落到实处,毕竟不是POSIX标准,不可重视这种顺序。
 
 别的,dequeue很有意思,先去task_struct中的pending中取,取不到再去整个线程组共享的shered_pending位图去取。    

4.打印线程的堆栈信息
jstack pid |grep tid -A 30

  1. int
    dequeue_signal(struct task_struct
    *tsk,
    sigset_t *mask, siginfo_t *info)

  2. {

  3.     int signr;

  4.     /*
    We only dequeue private signals from
    ourselves, we don’t let

  5.      * signalfd steal them

  6.      */

  7.     signr = __dequeue_signal(&tsk->pending,
    mask, info);

  8.     if (!signr) {

  9.         signr =
    __dequeue_signal(&tsk->signal->shared_pending,

  10.                      mask, info);

     
 。。。。
}

 

参考文献:
1 Linux2.6内核中的线程组初探 2 Linux kernel 3.8.0

一、计算sleep状态的进度.

c233 plugins # ps -elf|head -1
F S UID     PID   PPID C PRI   NI       ADDR   SZ    WCHAN
   STIME TTY TIME     CMD

root 28149  4204    0 80     0             –       16283   
poll_s       Jul05 ? 00:00:00   sshd: root

c233 plugins # ps -efl|awk ‘$2~/S/{print $0}’|wc -l                  
  //-l              long format. 

73

解释===>

(1)F列.

PROCESS FLAGS
The sum of these values is displayed in the “F” column, which is
provided by the flags output specifier.
1 forked but didn’t exec
4 used super-user privileges

(1)S列.

D Uninterruptible sleep (usually IO)
R Running or runnable (on run queue)
S Interruptible sleep (waiting for an event to complete)
T Stopped, either by a job control signal or because it is being
traced.
W paging (not valid since the 2.6.xx kernel)
X dead (should never be seen)
Z Defunct (“zombie”) process, terminated but not reaped by its parent.

(3)C列.C     pcpu         cpu utilization

(4)

command    COMMAND  see args. (alias args, cmd).

sz                    SZ       size in physical pages of the
core image of the process.
 This
includes text, data, and stack space. Device mappings are
currently
excluded; this is subject to change. See vsz and rss.

(5)WCHAN列.

wchan           WCHAN     name of the kernel function in which the
process is sleeping,
a “-” if the process is running, or a “*” if the process is
multi-threaded and ps is not displaying threads.

 

二、计算当前运行的线程总数.”-L”

c233 plugins # ps -eLf|grep -v $$|wc -l                            
     //-L              Show threads, possibly
with LWP and NLWP columns

646

c233 plugins # ps -eLf|grep -v $$|tail

UID        PID    PPID    LWP    C   NLWP   STIME TTY
  TIME     CMD

root   23678    1    688    0    36      Jul01 ? 00:00:06
  /usr/sbin/nscd
root   23678    1    689    0    36      Jul01 ? 00:00:06
  /usr/sbin/nscd
root   23678    1    690    0    36      Jul01 ? 00:00:06
  /usr/sbin/nscd
root   23678    1    691    0    36      Jul01 ? 00:00:06
    /usr/sbin/nscd
root   23678    1    692    0    36      Jul01 ? 00:00:06
    /usr/sbin/nscd
root   23678    1    693    0    36      Jul01 ? 00:00:06
    /usr/sbin/nscd
root   23678    1    694    0    36      Jul01 ? 00:00:06
    /usr/sbin/nscd
root   23678    1    695    0    36      Jul01 ? 00:00:06
    /usr/sbin/nscd
root   23678    1    696    0    36    Jul01 ? 00:00:06
    /usr/sbin/nscd
root   28149    4204 28149   0    1        Jul05 ? 00:00:00    
sshd: root

NLWP (number of threads)

LWP (thread ID)

c233 plugins # ps -ef|grep nscd
root 23678 1 0 Jun30 ? 00:15:32 /usr/sbin/nscd

三、Linux下查看某个进程的线程数量.

1.依据进度号进行询问:

# pstree -p 进程号      //-p pid

# top -Hp 进程号        //-H : Threads toggle

2.依据进度名字进行询问:

# pstree -p `ps -e | grep sshd | awk ‘{print $1}’`

# pstree -p `ps -e | grep sshd | awk ‘{print $1}’` | wc -l

003_监测域名证书过期时间
鉴于因为线上证书过期,出过相比较大的事故,所以就有了如下的监测证书过期的本子

#!/bin/sh
### SSL Certificate Expire Day Check Script ###
if [ "$1" = '' ];then
    echo "Need URL."
    exit
1;fi
TARGET_URL=$1
EXP_DAY=`openssl s_client -connect ${TARGET_URL}:443 < /dev/null 2> /dev/null | openssl x509 -text 2> /dev/null | grep "Not After" | sed -e 's/^ *//g' | cut -d " " -f 4,5,6,7,8`
NOW_TIME=`date +%s`
EXP_TIME=`date +%s -d "${EXP_DAY}"`
if [ "${EXP_DAY}" != '' -a ${NOW_TIME} -lt ${EXP_TIME} ]; then
    echo $(((EXP_TIME-NOW_TIME)/(60*60*24)))
else
    echo "ERROR"
    exit 1;
fi

 

相关文章