亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 9541 | 回復: 2
打印 上一主題 下一主題

分享一個關于pthread線程棧在mm_struct里面的分布問題 [復制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報告]
發(fā)表于 2008-11-09 15:01 |只看該作者 |倒序瀏覽
大家好,本人被下面這個問題困擾了一段時間,最近似乎找到了答案。
這里和大家分享一下,可能對有相同困惑的同學有點幫助,同時也請各位幫忙看看錯漏的地方。

1================問題:
在使用pthread庫創(chuàng)建兩個線程時clone()被調(diào)用了兩次,可以用strace 看到:
int
main()
{
...
        err=pthread_create(&tid, NULL, job, NULL);
        err=pthread_create(&tid1, NULL, job, NULL);
...
}

strace:
clone(Thread is running.
child_stack=0xb7efb4b4, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0xb7efbbd8, {entry_number:6, base_addr:0xb7efbb90, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}, child_tidptr=0xb7efbbd = 5104

clone(child_stack=0xb76fa4b4, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0xb76fabd8, {entry_number:6, base_addr:0xb76fab90, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}, child_tidptr=0xb76fabd = 5105

大家都知道clone()可以產(chǎn)生一個所謂的“輕量級進程”,也就是有獨立的task_struct的,獨立調(diào)度的東西。
再看看flag:CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID
這里對這些flag就不多說了對于我這個問題,最為重要的是CLONE_VM(共享內(nèi)存描述符mm_struct和所有的頁表)。
這點可以在copy_mm()里面看得到(在clone()中被調(diào)用):
static int copy_mm(unsigned long clone_flags, struct task_struct * tsk)
{
...
        if (clone_flags & CLONE_VM) {
                atomic_inc(&oldmm->mm_users);
                mm = oldmm;
                goto good_mm;
        }
...
}

這樣我這里兩個pthread和原來的main進程就共享同一個mm_struct了,如圖1:

pthread線程之間的棧必定是獨立的,不然不可能被獨立調(diào)度,我的問題就在這里,3個task_struct 共用一個mm_struct,那么他們的棧應該怎么辦?難道在一個棧里面?

2======================解答:
問題主要在兩個函數(shù)上面,一個是clone()系統(tǒng)調(diào)用,一個是pthread_create()
man clone,看他的參數(shù)。參數(shù)列表中最為顯眼的就是第二個參數(shù)void *child_stack,man里面是這樣形容它的:
The  child_stack argument specifies the location of the stack used by the child process.  Since the child
and calling process may share memory, it is not possible for the child process to  execute  in  the  same
stack as the calling process.
調(diào)用clone()的時候是要自己提供子task的?臻g的,這個系統(tǒng)調(diào)用實在是太特別了。
在看看pthread的庫是怎樣給這個參數(shù)賦值的:
函數(shù)pthread_handle_create() (manager.c里面) 被調(diào)用來創(chuàng)建新線程,在這個函數(shù)里面調(diào)用了pthread_allocate_stack()
來分配棧空間:
static int pthread_allocate_stack(const pthread_attr_t *attr,
                                  pthread_descr default_new_thread,
                                  int pagesize,
                                  char ** out_new_thread,
                                  char ** out_new_thread_bottom,
                                  char ** out_guardaddr,
                                  size_t * out_guardsize,
                                  size_t * out_stacksize)
{
...
      map_addr = mmap(NULL, stacksize + guardsize,
                      PROT_READ | PROT_WRITE | PROT_EXEC,
                      MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
      if (map_addr == MAP_FAILED)
        /* No more memory available.  */
        return -1;
...
}

可以看到pthread庫是通過調(diào)用mmap()來為新的線程創(chuàng)建?臻g的,可以在細看一下它的參數(shù),它使用了flag
MAP_ANONYMOUS和MAP_PRIVATE,而且fd參數(shù)中用了-1,這樣調(diào)用的結果是在進程空間中創(chuàng)建一個匿名的
線性區(qū),這樣就有了棧空間,而且這個空間也在原來的mm_struct里面,如圖2:

光有空間不行,還要看看內(nèi)核是怎樣使用,我們來到copy_thread(),它在copy_process()中被調(diào)用(它們都在clone()里面被調(diào)用的):
static struct task_struct *copy_process(unsigned long clone_flags,
                                        unsigned long stack_start,
                                        struct pt_regs *regs,
                                        unsigned long stack_size,
                                        int __user *child_tidptr,
                                        struct pid *pid)
{
...
        retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs);
...
}

int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
        unsigned long unused,
        struct task_struct * p, struct pt_regs * regs)
{
        struct pt_regs * childregs;
        struct task_struct *tsk;
        int err;

        childregs = task_pt_regs(p);
        *childregs = *regs;
        childregs->ax = 0;
        childregs->sp = sp;
...
}

這里可以清楚的看到,內(nèi)核為這個用戶線程初始化他未來的sp寄存器值,就是剛才mmap()返回的那個地址。所以結果
如圖3:

附上pthread庫,有興趣的同學可以研究一下,好像還比較復雜。

[ 本帖最后由 pennyliang 于 2008-11-9 15:08 編輯 ]

論壇徽章:
0
2 [報告]
發(fā)表于 2008-11-10 22:02 |只看該作者
頂LZ一個。分析的很好,這種探索精神更好!

論壇徽章:
0
3 [報告]
發(fā)表于 2008-11-11 17:28 |只看該作者
呵呵,感謝zx_wing兄的鼓勵。
您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則 發(fā)表回復

  

北京盛拓優(yōu)訊信息技術有限公司. 版權所有 京ICP備16024965號-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報專區(qū)
中國互聯(lián)網(wǎng)協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP