pthread中线程是怎么创建的(2)---glibc到内核

| 2013年4月28日

在glibc中线程创建是这个文件种来定义的:nptl/pthread_create.c

创建过程为,pthread_create 调用__pthread_create_2_0, __pthread_create_2_0调用__pthread_create_2_1, 或者pthread_create直接调用__pthread_create_2_1,在由__pthread_create_2_1调用create_thread来创建。

在create_thread中,首先是设置了很多内核clone的标志,因为对内核来说每次创建都是创建一个内核级的线程或是内核级进程。

/* We rely heavily on various flags the CLONE function understands:

CLONE_VM, CLONE_FS, CLONE_FILES
These flags select semantics with shared address space and
file descriptors according to what POSIX requires.

CLONE_SIGNAL
This flag selects the POSIX signal semantics.

CLONE_SETTLS
The sixth parameter to CLONE determines the TLS area for the
new thread.

CLONE_PARENT_SETTID
The kernels writes the thread ID of the newly created thread
into the location pointed to by the fifth parameters to CLONE.

Note that it would be semantically equivalent to use
CLONE_CHILD_SETTID but it is be more expensive in the kernel.

CLONE_CHILD_CLEARTID
The kernels clears the thread ID of a thread that has called
sys_exit() in the location pointed to by the seventh parameter
to CLONE.

The termination signal is chosen to be zero which means no signal
is sent. */
int clone_flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL
| CLONE_SETTLS | CLONE_PARENT_SETTID
| CLONE_CHILD_CLEARTID | CLONE_SYSVSEM
| 0);

然后调用线程函数种的do_clone函数来发起系统调用,进行线程的创建。

int rc = ARCH_CLONE (fct, STACK_VARIABLES_ARGS, clone_flags,
pd, &pd->tid, TLS_VALUE, &pd->tid);

#ifndef ARCH_CLONE
# define ARCH_CLONE __clone
#endif

__clone 在这个文件中,是一个汇编程序

./sysdeps/unix/sysv/linux/i386/clone.S

ENTRY (BP_SYM (__clone))

在__clone函数中会调用__NR_clone

movl    $SYS_ify(clone),%eax

#define SYS_ify(syscall_name)__NR_##syscall_name

__NR_clone 在这个clone会变文件中也做了定义:

#define __NR_clone 120
#define SYS_clone 120

从这里开始便发起了系统调用走向了内核了,在内核系统调用表中可以看到120对应的系统调用函数,arch/x86/kernel/syscall_table_32.S

.long ptregs_sigreturn
.long ptregs_clone /* 120 */
.long sys_setdomainname

在这个文件中可以看到ptregs_clone的定义,arch/x86/kernel/entry_32.S

#define PTREGSCALL(name) \
ALIGN; \
ptregs_##name: \
leal 4(%esp),%eax; \
jmp sys_##name;

PTREGSCALL(clone)

./arch/x86/kernel/process_32.c 中定义了 sys_clone

int sys_clone(struct pt_regs *regs)

看看sys_clone其实还是调用do_fork函数,所以创建的也就是内核种的进程,这样也就和前几分析的gettid和[thread_self的区别联系到了一起

看完本文有收获?请分享给更多人

关注「黑光技术」,关注大数据+微服务