作者 [email protected]
Bionic的线程机制是Dalvik线程的机制的基础。其实现是通过Linux的Fork机制来实现的。线程的运行轨迹是栈,
Android代码注释里已经给出了的bionic线程的栈结构:
* +---------------------------+
* | pthread_internal_t |
* +---------------------------+
* | |
* | TLS area |
* | |
* +---------------------------+
* | |
* . .
* . stack area .
* . .
* | |
* +---------------------------+
* | guard page |
* +---------------------------+
由此可见,线程栈结构是最低层存放该线程的管理结构pthread_internal_t;接着是线程局部存储区域;再接着是运行时产生的堆栈数据。
/* 线程的创建实现遵循pthread API。实现如下:*/
int pthread_create(pthread_t *thread_out, pthread_attr_t const * attr,
void *(*start_routine)(void *), void * arg)
{
…
//若未准备堆栈,则分配堆栈,栈是线程的人生轨迹
if (!attr->stack_base) {
stack = mkstack(stackSize, attr->guard_size);
…
} else {
stack = attr->stack_base;
}
//预留线程局部存储
tls = (void**)(stack + stackSize - BIONIC_TLS_SLOTS*sizeof(void*));
…
//调用__pthread_clone,见下文
tid = __pthread_clone((int(*)(void*))start_routine, tls,
CLONE_FILES | CLONE_FS | CLONE_VM | CLONE_SIGHAND
| CLONE_THREAD | CLONE_SYSVSEM | CLONE_DETACHED,
arg);
…
}
//r1是堆栈地址
ENTRY(__pthread_clone)
.cantunwind
/*把新线程入口地址填入堆栈,在新线程从内核退出时会从这里找到其实执行地址。*/
str r0, [r1, #-4]
//系统调用需要的参数信息
str r3, [r1, #-8]
// CLONE_VM等信息放在r0,遵循内核调用规范
mov r0, r2
@ new sp is already in r1
#if __ARM_EABI__
//保存下来r4-r7
stmfd sp!, {r4, r7}
//系统调用clone
ldr r7, =__NR_clone
swi #0
#else
swi #__NR_clone
#endif
//新线程的r0为“0”,参见内核部分
movs r0, r0
…
blt __error
//创建线程冲这里返回
bxne lr
//新线程继续执行
//取出存放在新线程堆栈里起始地址和参数
ldr r0, [sp, #-4]
ldr r1, [sp, #-8]
//新线程的堆栈指针指向TLS区域,参见上文堆栈结构
mov r2, sp
@ __thread_entry needs the TLS pointer
sub lr, lr
//新线程继续调用“__thread_entry”
b __thread_entry
…
END(__pthread_clone)
//新线程的trampoline
void __thread_entry(int (*func)(void*), void *arg, void **tls)
{
int retValue;
pthread_internal_t * thrInfo;
…
thrInfo = (pthread_internal_t *) tls[TLS_SLOT_THREAD_ID];
//初始化新线程的线程局部存储
__init_tls( tls, thrInfo );
//跳转到新线程的起始地址
pthread_exit( (void*)func(arg) );
}