日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

uclinux内核线程的创建(转)

發布時間:2023/12/15 linux 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 uclinux内核线程的创建(转) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
原地址:http://blog.csdn.net/lights_joy/archive/2009/04/23/4102575.aspx
創建內核線程可以使用kernel_thread函數:

/*

?* Create a kernel thread.

?*/

pid_t kernel_thread(int?(*fn) (void?*),?void?*arg,?unsigned?long?flags)

{

?????struct?pt_regs regs;

?

?????memset(&regs, 0,?sizeof(regs));

?

?????regs.r1 = (unsigned?long)arg;

?????regs.p1 = (unsigned?long)fn;

?????regs.pc = (unsigned?long)kernel_thread_helper;

?????regs.orig_p0 = -1;

?????/* Set bit 2 to tell ret_from_fork we should be returning to kernel

????????mode.??*/

?????regs.ipend = 0x8002;

?????__asm__ __volatile__("%0 = syscfg;":"=d"(regs.syscfg):);

?????return?do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL,

????????????????NULL);

}

注意這里的pc值的設置,它指向了kernel_thread_help,這將是這個內核線程要執行的第一行語句:

/*

?* This gets run with P1 containing the

?* function to call, and R1 containing

?* the "args".??Note P0 is clobbered on the way here.

?*/

void?kernel_thread_helper(void);

__asm__(".section .text\n"

?????".align 4\n"

?????"_kernel_thread_helper:\n\t"

?????"\tsp += -12;\n\t"

?????"\tr0 = r1;\n\t"?"\tcall (p1);\n\t"?"\tcall _do_exit;\n"?".previous;");

在這段代碼中,將跳轉到用戶指定的函數,然后調用do_exit進行一些清理工作。

具體的創建工作由do_fork完成,此時傳遞進去的stack_startstack_size的值都為0

1.1.1???do_fork

這個函數完成線程的創建,它的關鍵代碼如下:

/*

?*??Ok, this is the main fork-routine.

?*

?* It copies the process, and if successful kick-starts

?* it and waits for it to finish using the VM if required.

?*/

long?do_fork(unsigned?long?clone_flags,

???????????unsigned?long?stack_start,

???????????struct?pt_regs *regs,

???????????unsigned?long?stack_size,

???????????int?__user *parent_tidptr,

???????????int?__user *child_tidptr)

{

?????struct?task_struct *p;

?????int?trace = 0;

?????struct?pid *pid = alloc_pid();

?????long?nr;

……………………

?

?????p = copy_process(clone_flags, stack_start, regs, stack_size, parent_tidptr, child_tidptr, pid);

?

?????/*

??????* Do this prior waking up the new thread - the thread pointer

??????* might get invalid after that point, if the thread exits quickly.

??????*/

?????if?(!IS_ERR(p)) {

?????????struct?completion vfork;

…………………….

?

?????????if?(!(clone_flags & CLONE_STOPPED))

??????????????wake_up_new_task(p, clone_flags);

?????????else

??????????????p->state = TASK_STOPPED;

……………………….

?????}?else?{

?????????free_pid(pid);

?????????nr = PTR_ERR(p);

?????}

?????return?nr;

}

它首先為此線程分配一個pid號,然后復制出一個新的task_struct,最后喚醒此線程,當然此時還不會進入執行狀態。

1.1.2???copy_process

這個函數用于從當前線程復制一個task_struct出來。

/*

?* This creates a new process as a copy of the old one,

?* but does not actually start it yet.

?*

?* It copies the registers, and all the appropriate

?* parts of the process environment (as per the clone

?* flags). The actual kick-off is left to the caller.

?*/

static?struct?task_struct *copy_process(unsigned?long?clone_flags,

???????????????????????unsigned?long?stack_start,

???????????????????????struct?pt_regs *regs,

???????????????????????unsigned?long?stack_size,

???????????????????????int?__user *parent_tidptr,

???????????????????????int?__user *child_tidptr,

???????????????????????struct?pid *pid)

{

?????int?retval;

?????struct?task_struct *p = NULL;

……………………….

?????retval = -ENOMEM;

?????p = dup_task_struct(current);

?????if?(!p)

?????????goto?fork_out;

………………………..

?????retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs);

?????if?(retval)

?????????goto?bad_fork_cleanup_namespaces;

…………………………

?????return?p;

}

它首先調用dup_task_struct得到一個task_struct,同時也給這個新的線程分配了一個thread_info的結構體,這也是這個新線程的棧,使用BUDDY算法分配,保證以8K對齊。

接著調用copy_thread進行線程的復制。

int

copy_thread(int?nr,?unsigned?long?clone_flags,

?????????unsigned?long?usp,?unsigned?long?topstk,

?????????struct?task_struct *p,?struct?pt_regs *regs)

{

?????struct?pt_regs *childregs;

?

?????childregs = (struct?pt_regs *) (task_stack_page(p) + THREAD_SIZE) - 1;

?????*childregs = *regs;

?????childregs->r0 = 0;

?

?????p->thread.usp = usp;

?????p->thread.ksp = (unsigned?long)childregs;

?????p->thread.pc = (unsigned?long)ret_from_fork;

?

?????return?0;

}

注意這里在新線程的棧的底端復制了一份pt_regs,而這份pt_regsPC指針是指向kernel_thread_helper的。且新線程的PC指針是指向ret_from_fork函數。

1.1.3???wake_up_new_task

這個函數用于把線程放到一個CPU核的任務隊列中。

/*

?* wake_up_new_task - wake up a newly created task for the first time.

?*

?* This function will do some initial scheduler statistics housekeeping

?* that must be done for every newly created context, then puts the task

?* on the runqueue and wakes it.

?*/

void?fastcall wake_up_new_task(struct?task_struct *p,?unsigned?long?clone_flags)

{

?????struct?rq *rq, *this_rq;

?????unsigned?long?flags;

?????int?this_cpu, cpu;

?

?????rq = task_rq_lock(p, &flags);

?????BUG_ON(p->state != TASK_RUNNING);

?????this_cpu = smp_processor_id();

?????cpu = task_cpu(p);

?

?????/*

??????* We decrease the sleep average of forking parents

??????* and children as well, to keep max-interactive tasks

??????* from forking tasks that are max-interactive. The parent

??????* (current) is done further down, under its lock.

??????*/

?????p->sleep_avg = JIFFIES_TO_NS(CURRENT_BONUS(p) *

?????????CHILD_PENALTY / 100 * MAX_SLEEP_AVG / MAX_BONUS);

?

?????p->prio = effective_prio(p);

?

?????if?(likely(cpu == this_cpu)) {

?????????if?(!(clone_flags & CLONE_VM)) {

??????????????/*

???????????????* The VM isn't cloned, so we're in a good position to

???????????????* do child-runs-first in anticipation of an exec. This

???????????????* usually avoids a lot of COW overhead.

???????????????*/

??????????????if?(unlikely(!current->array))

???????????????????__activate_task(p, rq);

??????????????else?{

???????????????????p->prio = current->prio;

???????????????????p->normal_prio = current->normal_prio;

???????????????????list_add_tail(&p->run_list, &current->run_list);

???????????????????p->array?= current->array;

???????????????????p->array->nr_active++;

???????????????????inc_nr_running(p, rq);

??????????????}

??????????????set_need_resched();

?????????}?else

??????????????/* Run child last */

??????????????__activate_task(p, rq);

?????????/*

??????????* We skip the following code due to cpu == this_cpu

???????????*

??????????*???task_rq_unlock(rq, &flags);

??????????*???this_rq = task_rq_lock(current, &flags);

??????????*/

?????????this_rq = rq;

?????}?else?{

?????????this_rq = (struct?rq *)cpu_rq(this_cpu);

?

?????????/*

??????????* Not the local CPU - must adjust timestamp. This should

??????????* get optimised away in the !CONFIG_SMP case.

??????????*/

?????????p->timestamp = (p->timestamp - this_rq->most_recent_timestamp)

???????????????????????+ rq->most_recent_timestamp;

?????????__activate_task(p, rq);

?????????if?(TASK_PREEMPTS_CURR(p, rq))

??????????????resched_task(rq->curr);

?

?????????/*

??????????* Parent and child are on different CPUs, now get the

??????????* parent runqueue to update the parent's ->sleep_avg:

??????????*/

?????????task_rq_unlock(rq, &flags);

?????????this_rq = task_rq_lock(current, &flags);

?????}

?????current->sleep_avg = JIFFIES_TO_NS(CURRENT_BONUS(current) *

?????????PARENT_PENALTY / 100 * MAX_SLEEP_AVG / MAX_BONUS);

?????task_rq_unlock(this_rq, &flags);

}

這個函數挺長的,但實際上將新線程加入隊列的工作是由__activate_task這個函數完成的:

/*

?* __activate_task - move a task to the runqueue.

?*/

static?void?__activate_task(struct?task_struct *p,?struct?rq *rq)

{

?????struct?prio_array *target = rq->active;

?

?????if?(batch_task(p))

?????????target = rq->expired;

?????enqueue_task(p, target);

?????inc_nr_running(p, rq);

}

再看enqueue_task

static?void?enqueue_task(struct?task_struct *p,?struct?prio_array *array)

{

?????sched_info_queued(p);

?????list_add_tail(&p->run_list,?array->queue + p->prio);

?????__set_bit(p->prio,?array->bitmap);

?????array->nr_active++;

?????p->array?=?array;

}


快樂蝦

http://blog.csdn.net/lights_joy/

lights@hb165.com

??

本文適用于

ADSP-BF561

uclinux-2008r1.5-RC3(移植到vdsp5)

Visual DSP++ 5.0(update 5)

??

歡迎轉載,但請保留作者信息

總結

以上是生活随笔為你收集整理的uclinux内核线程的创建(转)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。