arm linux 线程堆栈,多线程:ARM linux平台上线程栈信息的建立流程

一联合体thread_union:表示一个进程的线程描述符和内核栈大小定义

unionthread_union {

struct thread_info thread_info;

unsigned long stack[THREAD_SIZE/sizeof(long)];根据联合体的定义和作用,一个thread_info的大小也就是栈的大小

};

线程描述符:----也可以理解成线程的”逻辑栈信息“,注意不是与cpu栈信息,这里仅仅是软件层面上线程的“栈信息”

struct thread_info {

unsigned long                flags;                /* low level flags */

int                        preempt_count;        /* 0 => preemptable, <0 => bug */

mm_segment_t                addr_limit;        /* address limit */

struct task_struct        *task;                /* main task structure */

struct exec_domain        *exec_domain;        /* execution domain */

__u32                        cpu;                /* cpu */

__u32                        cpu_domain;        /* cpu domain */

struct cpu_context_save        cpu_context;        /* cpu context */-----cpu的寄存器层面栈的信息

__u32                        syscall;        /* syscall number */

__u8                        used_cp[16];        /* thread used copro */

unsigned long                tp_value;

struct crunch_state        crunchstate;

union fp_state                fpstate __attribute__((aligned(8)));

union vfp_state                vfpstate;

#ifdef CONFIG_ARM_THUMBEE

unsigned long                thumbee_state;        /* ThumbEE Handler Base register */

#endif

struct restart_block        restart_block;

int                        cpu_excp;

void                         *regs_on_excp;

};

小结:thread_union与thread_info是一样的作用,只是thread_union做了一个stack大小的定义。

二线程栈信息的建立流程

概述:首先系统启动的时候,init线程首先分配了一个thread_union;以后其他的线程创建的时候,都是copy该init线程的thread_union结构,复制出一个线程副本出来。

下面分析:

1)init_task相关栈和task信息的建立

这里关注栈信息(线程描述信息)

1.1)初始化设置栈信息:参考”内核栈的初始化设置过程“

什么意思呢?就是建立第一个init线程的对应cpu体系的栈信息结构的起始位置SP指针,与后面系统建立其他线程的栈无关,其他线程自己会分配自己的空间,初始化两个数据结构:一个是thread_info,另一个就是task_struct;

:thread_info的定义,

0号线程是通过联合体thread_union定义对象:”init_thread_union“:

init_thread_union定义和初始化在哪里呢?如下:

unionthread_unioninit_thread_union__init_task_data=

{ INIT_THREAD_INFO(init_task) };

__init_task_data只是一个宏,来自:

Init_task.h (zaw809aa_lava\kernel\include\linux):#define __init_task_data __attribute__((__section__(".data..init_task"))):

#define__init_task_data__attribute__((__section__(".data.init_task")))

那么,上面的内容就展开成了:

union thread_unioninit_thread_union__attribute__((__section__(".data.init_task"))) ={INIT_THREAD_INFO(init_task)};并且把数据放进指定的数据段.data.init_task

那么如何完成init_thread_union赋值呢?

Step1 )先执行宏:

#define INIT_THREAD_INFO(tsk)                                                \

{                                                                        \

.task                = &tsk,                                                \

.exec_domain        = &default_exec_domain,                                \

.flags                = 0,                                                \

.preempt_count        = INIT_PREEMPT_COUNT,                                \

.addr_limit        = KERNEL_DS,                                        \

.cpu_domain        = domain_val(DOMAIN_USER, DOMAIN_MANAGER) |        \

domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) |        \

domain_val(DOMAIN_IO, DOMAIN_CLIENT),                \

.restart_block        = {                                                \

.fn        = do_no_restart_syscall,                        \

},                                                                \

}

所以unionthread_unioninit_thread_union__attribute__((__section__(".data.init_task"))) ={INIT_THREAD_INFO(init_task)};展开就是:

unionthread_unioninit_thread_union__attribute__((__section__(".data.init_task"))) ={

.task                = &tsk,                                                \

.exec_domain        = &default_exec_domain,                                \

.flags                = 0,                                                \

.preempt_count        = INIT_PREEMPT_COUNT,                                \

.addr_limit        = KERNEL_DS,                                        \

.cpu_domain        = domain_val(DOMAIN_USER, DOMAIN_MANAGER) |        \

domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) |        \

domain_val(DOMAIN_IO, DOMAIN_CLIENT),                \

.restart_block        = {                                                \

.fn        = do_no_restart_syscall,                        \

},                                                                \

};

可以看到在初始化thread_info的成员(task,exec_domain,flags,preempt_count        ,addr_limit等);

Step2)然后执行struct task_structinit_task=INIT_TASK(init_task);

Step3)最后执行完INIT_TASK(tsk)这个宏以后,init_thread_union就被初始化成以上内容了,至此,0号进程的task_struct和thread_info就初始化完毕了:

/*

* Initial task structure.

*

* All other task structs will be allocated on slabs in fork.c

*/

structtask_structinit_task= INIT_TASK(init_task);每一个线程对应一个task_struct任务调度的基本单位的初始化。

#defineINIT_TASK(tsk)        \

{                                                                        \

.state                = 0,                                                \

.stack                = &init_thread_info,                                \init线程的描述符(也就是栈信息)指向栈空间

.usage                = ATOMIC_INIT(2),                                \

.flags                = PF_KTHREAD,                                        \

….

}

===============================================================

2)其他线程的创建的时候,copy当前线程(init线程是一切线程的鼻祖)的task_struct信息和栈内存空间:

copy_process()---->p = dup_task_struct(current);

static struct task_struct *dup_task_struct(struct task_struct *orig)

{

struct task_struct *tsk;

struct thread_info *ti;//创建thread_info也就是栈

unsigned long *stackend;

int node = tsk_fork_get_node(orig);

int err;

prepare_to_copy(orig);

tsk = alloc_task_struct_node(node);//在当前线程的node上分配和复制该task信息

if (!tsk){

printk("[%d:%s] fork fail at alloc_tsk_node, please check kmem_cache_alloc_node()\n", current->pid, current->comm);

return NULL;

}

ti = alloc_thread_info_node(tsk, node);在当前线程的node上分配和复制该task的stack信息(栈)

if (!ti) {

printk("[%d:%s] fork fail at alloc_t_info_node, please check alloc_pages_node()\n", current->pid, current->comm);

free_task_struct(tsk);

return NULL;

}

err = arch_dup_task_struct(tsk, orig);

if (err){

printk("[%d:%s] fork fail at arch_dup_task_struct, err:%d \n", current->pid, current->comm, err);

goto out;

}

tsk->stack = ti;

setup_thread_stack(tsk, orig);//把当前task的stack成员,数据类型转化成栈信息结构:thread_info

clear_user_return_notifier(tsk);

clear_tsk_need_resched(tsk);

stackend = end_of_stack(tsk);

*stackend = STACK_END_MAGIC;        /* for overflow detection */

…...

}

#definetask_thread_info(task)        ((structthread_info*)(task)->stack)//把(task)->stack数据类型格式化成栈信息结构thread_info,

#define task_stack_page(task)        ((task)->stack)

static inline void setup_thread_stack(struct task_struct *p, struct task_struct *org)

{

*task_thread_info(p) = *task_thread_info(org);

task_thread_info(p)->task = p;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值