需要考證
考證結果:
其內核棧是獨立的
206 static struct task_struct *dup_task_struct(struct task_struct *orig)
207 {
208 struct task_struct *tsk;
209 struct thread_info *ti;
210 int err;
211
212 prepare_to_copy(orig);
213
214 tsk = alloc_task_struct();
215 if (!tsk)
216 return NULL;
217
218 ti = alloc_thread_info(tsk);
219 if (!ti) {
220 free_task_struct(tsk);
221 return NULL;
222 }
223
224 err = arch_dup_task_struct(tsk, orig);
225 if (err)
226 goto out;
227
228 tsk->stack = ti;
229
230 err = prop_local_init_single(&tsk->dirties);
231 if (err)
232 goto out;
233
234 setup_thread_stack(tsk, orig);
。。。。。。。、
98 #ifndef __HAVE_ARCH_THREAD_INFO_ALLOCATOR
99 static inline struct thread_info *alloc_thread_info(struct task_struct *tsk)
100 {
101 #ifdef CONFIG_DEBUG_STACK_USAGE
102 gfp_t mask = GFP_KERNEL | __GFP_ZERO;
103 #else
104 gfp_t mask = GFP_KERNEL;
105 #endif
106 return (struct thread_info *)__get_free_pages(mask, THREAD_SIZE_ORDER);
107 }
108
。。。。。。
Breakpoint 2, __get_free_pages (gfp_mask=208, order=1) at mm/page_alloc.c:1670
1670 page = alloc_pages(gfp_mask, order);
(cskygdb) bt
#0 __get_free_pages (gfp_mask=208, order=1) at mm/page_alloc.c:1670
#1 0x9000f5d6 in alloc_thread_info (clone_flags=4001536, stack_start=7, regs=0x0, stack_size=715825152, child_tidptr=0x0, pid=0x0, trace=0)
at kernel/fork.c:106
#2 dup_task_struct (clone_flags=4001536, stack_start=7, regs=0x0, stack_size=715825152, child_tidptr=0x0, pid=0x0, trace=0)
at kernel/fork.c:218
#3 copy_process (clone_flags=4001536, stack_start=7, regs=0x0, stack_size=715825152, child_tidptr=0x0, pid=0x0, trace=0)
at kernel/fork.c:922
#4 0x90010a7e in do_fork (clone_flags=4001536, stack_start=715921168, regs=0x90847fb8, stack_size=0, parent_tidptr=0x2aac1be8,
child_tidptr=0x2aac1be8) at kernel/fork.c:1348
#5 0x90005c4e in csky_clone (clone_flags=<value optimized out>, newsp=<value optimized out>, parent_tidptr=<value optimized out>,
child_tidptr=0x90005c4e, tls_val=<value optimized out>, regs=<value optimized out>) at arch/csky/kernel/process.c:237
#6 0x900009d2 in system_call ()
網上的介紹:
http://www.360doc.com/content/13/0527/00/12499915_288433220.shtml
linux 線程有自己獨立的內核棧嗎?
首先,我們知道所有線程共享主線程的虛擬地址空間(current->mm指向同一個地址),且都有自己的用戶態堆棧(共享父進程的地址空間,再在里面分配自己的獨立棧,默認2M)。這是毫無疑問的,但還有一點我沒搞明白,內核棧是共享還是獨立的?
猜測:獨立的。理由:要不然內核棧對應的thread_info中的tast_struct沒有辦法與每個線程對應起來,因為現在已經有多個task_struct了,但保存內核棧的thread_info(其實是thread_union聯合體)中只能保存一個task_struct。所以理論上分析,雖然可以共享地址空間,但每個線程還是需要一個單獨的內核棧的。看代碼:
分析創建線程最終肯定會走到內核函數do_fork()中來的,所以從此函數看起。
do_fork()->copy_process()->dup_task_struct()
fork.c中dup_task_struct()的實現:
static struct task_struct *dup_task_struct(struct task_struct *orig)
{
struct task_struct *tsk;
struct thread_info *ti;
unsigned long *stackend;
int node = tsk_fork_get_node(orig);
int err;
tsk = alloc_task_struct_node(node);
if (!tsk)
return NULL;
ti = alloc_thread_info_node(tsk, node);/*就是這里,果然分配內核棧了*/
if (!ti)
goto free_tsk;
err = arch_dup_task_struct(tsk, orig);/*這里分配task_struct結構*/
if (err)
goto free_ti;
tsk->stack = ti;
...
}
線程在Linux中的實現
3.3 線程在Linux中的實現
線程機制是現代編程技術中常用的一種抽象。該機制提供了在同一程序內共享內存地址空間運行的一組線程。這些線程還可以共享打開的文件和其他資源。線 程機制支持並發程序設計技術(concurrent programming),在多處理器系統上,它也能保證真正的並行處理(parallelism)。
Linux實現線程的機制非常獨特。從內核的角度來說,它並沒有線程這個概念。Linux把所有的線程都當作進程來實現。內核並沒有准備特別的調度 算法或是定義特別的數據結構來表征線程。相反,線程僅僅被視為一個與其他進程共享某些資源的進程。每個線程都擁有惟一隸屬於自己的 task_struct,所以在內核中,它看起來就像是一個普通的進程(只是該進程和其他一些進程共享某些資源,如地址空間)。
上述線程機制的實現與Microsoft Windows或是Sun Solaris等操作系統的實現差異非常大。這些系統都在內核中提供了專門支持線程的機制(這些系統常常把線程稱作輕量級進程,lightweight process)。“輕量級進程”這種叫法本身就概括了Linux在此處與其他系統的差異。在其他的系統中,相較於重量級的進程,線程被抽象成一種耗費較 少資源,運行迅速的執行單元。而對於Linux來說,它只是一種進程間共享資源的手段(Linux的進程本身就夠輕了)。舉個例子來說,假如我們有一個包 含四個線程的進程,在提供專門線程支持的系統中,通常會有一個包含指向四個不同線程的指針的進程描述符。該描述符負責描述像地址空間、打開的文件這樣的共 享資源。線程本身再去描述它獨占的資源。相反,Linux僅僅創建四個進程並分配四個普通的task_sturct結構。建立這四個進程時指定它們共享某 些資源就行了。
線程的創建和普通進程的創建類似,只不過在調用clone()的時候需要傳遞一些參數標志來指明需要共享的資源:
- clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, 0);
上面的代碼產生的結果和調用fork()差不多,只是父子倆共享地址空間、文件系統資源、文件描述符和信號處理程序。換個說法就是,新建的進程和它的父進程就是流行的所謂線程。
對比一下,一個普通的fork()的實現是:
- clone(SIGCHLD, 0);
而vfork()的實現是:
- clone(CLONE_VFORK | CLONE_VM | SIGCHLD, 0);
傳遞給clone()的參數標志決定了新創建進程的行為方式和父子進程之間共享的資源種類。表3-1列舉了這些clone()用到的參數標志以及它們的作用,這些是在<linux/sched.h>中定義的。
