您的位置:首页 > 运维架构 > Linux

linux syscall系统调用获取线程PID

2017-10-10 21:49 357 查看

linux syscall系统调用获取线程PID

线程id

Linux中,每个进程有一个pid,类型pid_t,由getpid()取得。Linux下的POSIX线程也有一个id,类型 pthread_t,由pthread_self()取得,该id由线程库维护,其id空间是各个进程独立的(即不同进程中的线程可能有相同的id)。Linux中的POSIX线程库实现的线程其实也是一个进程(LWP),只是该进程与主进程(启动线程的进程)共享一些资源而已,比如代码段,数据段等。

通过pthread_self()取得的线程id实际上是当前线程的descriptor地址,其实现:

# define THREAD_SELF \
({ struct pthread *__self;         \
asm ("movl %%gs:%c1,%0" : "=r" (__self)      \
: "i" (offsetof (struct pthread, header.self)));        \
__self;})
1
2
3
4
5



但有时候我们可能需要知道线程的真实pid。比如进程P1要向另外一个进程P2中的某个线程发送信号时,既不能使用P2的pid,更不能使用线程的pthread id,而只能使用该线程的真实pid,称为tid。

有一个函数gettid()可以得到tid,但glibc并没有实现该函数,只能通过Linux的系统调用syscall来获取。

syscall 系统调用获取pid

linux 2.6.18版本之前的内核,在include/asm-i386/unistd.h文件中定义有7个_syscall宏,分别是:

_syscall0(type,name)
_syscall1(type,name,type1,arg1)
_syscall2(type,name,type1,arg1,type2,arg2)
_syscall3(type,name,type1,arg1,type2,arg2,type3,arg3)
_syscall4(type,name,type1,arg1,type2,arg2,type3,
arg3,type4,arg4)
_syscall5(type,name,type1,arg1,type2,arg2,type3,
arg3,type4,arg4,type5,arg5)
_syscall6(type,name,type1,arg1,type2,arg2,type3,
arg3,type4,arg4,type5,arg5,type6,arg6)
1
2
3
4
5
6
7
8
9
10



其中,type表示所生成系统调用的返回值类型,name表示该系统调用的名称,typeN、argN分别表示第N个参数的类型和名称,它们的数目和_syscall后面的数字一样大。这些宏的作用是创建名为name的函数,_syscall后面跟的数字指明了该函数的参数的个数。

比如gettid系统调用用于获取线程的pid,使用_syscall宏定义为:

_syscall0(pid_t,gettid)
1



这样就定义了pid_d gettid()的函数,可以通过gettid来获得线程pid。

但是自2.6.19版本开始,_syscall宏被废除,我们需要使用syscall函数,通过指定系统调用号和一组参数来调用系统调用。

syscall函数原型为:

int syscall(int number, ...);
1



其中number是系统调用号,number后面应顺序接上该系统调用的所有参数。下面是gettid系统调用的调用实例。

代码清单5.2 gettid系统调用使用实例

1. #include <unistd.h>
2. #include <sys/syscall.h>
3. #include <sys/types.h>
4.
5. #define __NR_gettid      224
6.
7. int main(int argc, char *argv[])
8. {
9.      pid_t tid;
10.
11.    tid = syscall(__NR_gettid);
12. }
1
2
3
4
5
6
7
8
9
10
11
12



大部分系统调用都包括了一个SYS_符号常量来指定自己到系统调用号的映射,因此上面第10行可重写为:

tid = syscall(SYS_gettid);
1



在内部为方便调用可以自己定义

pid_t gettid() { return static_cast<pid_t>(syscall(__NR_gettid));}
1



为了兼容各个内核版本可以定义

#ifdef _syscall0
_syscall0(pid_t,gettid)
#else
pid_t gettid() { return static_cast<pid_t>(syscall(__NR_gettid));}
#endif
1
2
3
4
5



参考

[1]http://blog.chinaunix.net/uid-28458801-id-4630215.html

[2]http://blog.csdn.net/b02042236/article/details/6136598

参考2对syscall系统调用解释很详细,还介绍的如何添加新的系统调用,感兴趣的可以作为参考学习。对于系统调用参考2的开头可能说的不是太准确,系统调用不仅syscall方式,还有int $0x80, sysenter指令方式。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: