導航:首頁 > 操作系統 > linux用戶棧內核棧

linux用戶棧內核棧

發布時間:2022-05-18 17:30:02

linux程序存儲結構與進程結構 堆和棧的區別

linux下的cpu有兩個狀態:內核態和用戶態,內核態的cpu的許可權高於用戶態下的cpu。linux下的內存分為用戶態內存和內核態內存,一般4個G內存,3個G的分給用戶態,1個G分給內核態。linux進程有時需要調用內核資源時,如讀寫文件,io讀寫等,這時候是通過系統調用實現對內核資源的訪問的,在訪問內核資源前是用戶棧,經過系統調用進入到內核態時,cpu的狀態也由用戶態變為內核態,訪問的內存就是內核態下管理的內存了-內核棧,對內核里的資源訪問完返回,內存又回到了用戶棧,cpu也回到用戶態。

⑵ 怎麼理解linux內核棧

您好,很高興為您解答。 1.進程的堆棧 內核在創建進程的時候,在創建task_struct的同事,會為進程創建相應的堆棧。每個進程會有兩個棧,一個用戶棧,存在於用戶空間,一個內核棧,存在於內核空間。當進程在用戶空間運行時,cpu堆棧指針寄存器里...

⑶ linux進程為什麼有用戶棧和內核棧,

linux下的cpu有兩個狀態:內核態和用戶態,內核態的cpu的許可權高於用戶態下的cpu。
linux下的內存分為用戶態內存和內核態內存,一般4個G內存,3個G的分給用戶態,1個G分給內核態。
linux進程有時需要調用內核資源時,如讀寫文件,io讀寫等,這時候是通過系統調用實現對內核資源的訪問的,在訪問內核資源前是用戶棧,經過系統調用進入到內核態時,cpu的狀態也由用戶態變為內核態,訪問的內存就是內核態下管理的內存了-內核棧,對內核里的資源訪問完返回,內存又回到了用戶棧,cpu也回到用戶態。

⑷ 進程內核棧,用戶棧及 Linux 進程棧和線程棧的區別

內核棧、用戶棧

32位Linux系統上,進程的地址空間為4G,包括1G的內核地址空間-----內核棧,和3G的用戶地址空間-----用戶棧。

內核棧,是各個進程在剛開始建立的時候通過內存映射共享的,但是每個進程擁有獨立的4G的虛擬內存空間從這一點看又是獨立的,互不幹擾的(只是剛開始大家都是映射的同一份內存拷貝)
用戶棧就是大家所熟悉的內存四區,包括:代碼區、全局數據區、堆區、棧區
用戶棧中的堆區、棧區即為進程堆、進程棧

進程堆、進程棧與線程棧

1.線程棧的空間開辟在所屬進程的堆區與共享內存區之間,線程與其所屬的進程共享進程的用戶空間,所以線程棧之間可以互訪。線程棧的起始地址和大小存放在pthread_attr_t 中,棧的大小並不是用來判斷棧是否越界,而是用來初始化避免棧溢出的緩沖區的大小(或者說安全間隙的大小)

2.進程初始化的時候,系統會在進程的地址空間中創建一個堆,叫進程默認堆。進程中所有的線程共用這一個堆。當然,可以增加1個或幾個堆,給不同的線程共同使用或單獨使用。----一個進程可以多個堆
3、創建線程的時候,系統會在進程的地址空間中分配1塊內存給線程棧,通常是1MB或4MB或8MB。線程棧是獨立的,但是還是可以互訪,因為線程共享內存空間

4.堆的分配:從操作系統角度來看,進程分配內存有兩種方式,分別由兩個系統調用完成:brk()和mmap(),glibc中malloc封裝了
5.線程棧位置-內存分布測試代碼

[cpp] view plain
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <malloc.h>
#include <sys/syscall.h>

void* func(void* arg)
{
long int tid = (long int)syscall(SYS_gettid);
printf("The ID of this thread is: %ld\n", tid );
static int a=10;
int b=11;
int* c=(int *)malloc(sizeof(int));
printf("in thread id:%u a:%p b:%p c:%p\n",tid,&a,&b,c);
printf("leave thread id:%ld\n",tid);
sleep(20);
free((void *)c);
}

void main()
{
pthread_t th1,th2;
printf("pid=%u\n",(int)getpid());
func(NULL);
int ret=pthread_create(&th1,NULL,func,NULL);
if(ret!=0)
{
printf("thread1[%d]:%s\n",th1,strerror(errno));
}
ret=pthread_create(&th2,NULL,func,NULL);
if(ret!=0)
{
printf("thread2[%d]:%s\n",th2,strerror(errno));
}
pthread_join(th1,NULL);
pthread_join(th2,NULL);
}
輸出:

[le@localhost threadStack]$ ./threadStack_main pid=16433
The ID of this thread is: 16433
in thread id:16433 a:0x60107c b:0x7fffc89ce7ac c:0x1b54010
leave thread id:16433
The ID of this thread is: 16461
The ID of this thread is: 16460
in thread id:16461 a:0x60107c b:0x7f6abb096efc c:0x7f6ab40008c0
leave thread id:16461
in thread id:16460 a:0x60107c b:0x7f6abb897efc c:0x7f6aac0008c0
leave thread id:16460
主線程調用func後
[le@localhost threadStack]$ sudo cat /proc/16433/maps
00400000-00401000 r-xp 00000000 fd:02 11666 /home/le/code/threadStack/threadStack_main
00600000-00601000 r--p 00000000 fd:02 11666 /home/le/code/threadStack/threadStack_main
00601000-00602000 rw-p 00001000 fd:02 11666 /home/le/code/threadStack/threadStack_main
01b54000-01b75000 rw-p 00000000 00:00 0 [heap]
7f6abb899000-7f6abba4f000 r-xp 00000000 fd:00 100678959 /usr/lib64/libc-2.17.so
7f6abba4f000-7f6abbc4f000 ---p 001b6000 fd:00 100678959 /usr/lib64/libc-2.17.so
7f6abbc4f000-7f6abbc53000 r--p 001b6000 fd:00 100678959 /usr/lib64/libc-2.17.so
7f6abbc53000-7f6abbc55000 rw-p 001ba000 fd:00 100678959 /usr/lib64/libc-2.17.so
7f6abbc55000-7f6abbc5a000 rw-p 00000000 00:00 0
7f6abbc5a000-7f6abbc70000 r-xp 00000000 fd:00 105796566 /usr/lib64/libpthread-2.17.so
7f6abbc70000-7f6abbe70000 ---p 00016000 fd:00 105796566 /usr/lib64/libpthread-2.17.so
7f6abbe70000-7f6abbe71000 r--p 00016000 fd:00 105796566 /usr/lib64/libpthread-2.17.so
7f6abbe71000-7f6abbe72000 rw-p 00017000 fd:00 105796566 /usr/lib64/libpthread-2.17.so
7f6abbe72000-7f6abbe76000 rw-p 00000000 00:00 0
7f6abbe76000-7f6abbe97000 r-xp 00000000 fd:00 105796545 /usr/lib64/ld-2.17.so
7f6abc073000-7f6abc076000 rw-p 00000000 00:00 0
7f6abc095000-7f6abc097000 rw-p 00000000 00:00 0
7f6abc097000-7f6abc098000 r--p 00021000 fd:00 105796545 /usr/lib64/ld-2.17.so
7f6abc098000-7f6abc099000 rw-p 00022000 fd:00 105796545 /usr/lib64/ld-2.17.so
7f6abc099000-7f6abc09a000 rw-p 00000000 00:00 0
7fffc89b0000-7fffc89d1000 rw-p 00000000 00:00 0 [stack]
7fffc89fe000-7fffc8a00000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]

兩個子線程啟動後
[le@localhost threadStack]$ sudo cat /proc/16433/maps
00400000-00401000 r-xp 00000000 fd:02 11666 /home/le/code/threadStack/threadStack_main
00600000-00601000 r--p 00000000 fd:02 11666 /home/le/code/threadStack/threadStack_main
00601000-00602000 rw-p 00001000 fd:02 11666 /home/le/code/threadStack/threadStack_main
01b54000-01b75000 rw-p 00000000 00:00 0 [heap]
7f6aac000000-7f6aac021000 rw-p 00000000 00:00 0
7f6aac021000-7f6ab0000000 ---p 00000000 00:00 0
7f6ab4000000-7f6ab4021000 rw-p 00000000 00:00 0
7f6ab4021000-7f6ab8000000 ---p 00000000 00:00 0
7f6aba897000-7f6aba898000 ---p 00000000 00:00 0
7f6aba898000-7f6abb098000 rw-p 00000000 00:00 0 [stack:16461]
7f6abb098000-7f6abb099000 ---p 00000000 00:00 0
7f6abb099000-7f6abb899000 rw-p 00000000 00:00 0 [stack:16460]
7f6abb899000-7f6abba4f000 r-xp 00000000 fd:00 100678959 /usr/lib64/libc-2.17.so
7f6abba4f000-7f6abbc4f000 ---p 001b6000 fd:00 100678959 /usr/lib64/libc-2.17.so
7f6abbc4f000-7f6abbc53000 r--p 001b6000 fd:00 100678959 /usr/lib64/libc-2.17.so
7f6abbc53000-7f6abbc55000 rw-p 001ba000 fd:00 100678959 /usr/lib64/libc-2.17.so
7f6abbc55000-7f6abbc5a000 rw-p 00000000 00:00 0
7f6abbc5a000-7f6abbc70000 r-xp 00000000 fd:00 105796566 /usr/lib64/libpthread-2.17.so
7f6abbc70000-7f6abbe70000 ---p 00016000 fd:00 105796566 /usr/lib64/libpthread-2.17.so
7f6abbe70000-7f6abbe71000 r--p 00016000 fd:00 105796566 /usr/lib64/libpthread-2.17.so
7f6abbe71000-7f6abbe72000 rw-p 00017000 fd:00 105796566 /usr/lib64/libpthread-2.17.so
7f6abbe72000-7f6abbe76000 rw-p 00000000 00:00 0
7f6abbe76000-7f6abbe97000 r-xp 00000000 fd:00 105796545 /usr/lib64/ld-2.17.so
7f6abc073000-7f6abc076000 rw-p 00000000 00:00 0
7f6abc095000-7f6abc097000 rw-p 00000000 00:00 0
7f6abc097000-7f6abc098000 r--p 00021000 fd:00 105796545 /usr/lib64/ld-2.17.so
7f6abc098000-7f6abc099000 rw-p 00022000 fd:00 105796545 /usr/lib64/ld-2.17.so
7f6abc099000-7f6abc09a000 rw-p 00000000 00:00 0
7fffc89b0000-7fffc89d1000 rw-p 00000000 00:00 0 [stack]
7fffc89fe000-7fffc8a00000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]

⑸ linux中斷處理程序使用的堆棧是內核的堆棧嗎,在哪裡

當然是,進程生成時,會被分配一個task_struct 結構(常說的進程式控制制塊),2.4內核中,在task_struct 結構體上面的7KB空間就是。加上task_struct結構本身(1KB),進程內核棧共8KB(兩個頁面 ),不會動態擴展,所以非常有限(你會見到內核代碼用"大塊"內存都會kmalloc申請的,就是這個原因)。2.6內核的沒注意,不知一樣否。詳見:《Linux內核源代碼情景分析(上)》267頁。
為什麼會在內核的原因是CPU的保護機制,中斷處理需要更高的許可權(可能執行硬體相關的操作),故要在0級,不會在用戶區的。

⑹ linux 線程間共享內核棧嗎

首先,我們知道所有線程共享主線程的虛擬地址空間(current->mm指向同一個地址),且都有自己的用戶態堆棧(共享父進程的地址空間,再在裡面分配自己的獨立棧,默認2M)。這是毫無疑問的,但還有一點我沒搞明白,內核棧是共享還是獨立的?猜測:獨立的。理由:要不然內核棧對應的thread_info中的tast_struct沒有辦法與每個線程對應起來,因為現在已經有多個task_struct了,但保存內核棧的thread_info(其實是thread_union聯合體)中只能保存一個task_struct。所以理論上分析,雖然可以共享地址空間,但每個線程還是需要一個單獨的內核棧的。看代碼:分析創建線程最終肯定會走到內核函數do_fork()中來的,所以從此函數看起。do_fork()->_process()->p_task_struct()fork.c中p_task_struct()的實現:static struct task_struct *p_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_p_task_struct(tsk, orig);/*這里分配task_struct結構*/if (err)goto free_ti;tsk->stack = ti; ...}

⑺ 在unix/linux系統中,什麼是用戶態,什麼是內核態

用戶態和內核態

內核棧:Linux中每個進程有兩個棧,分別用於用戶態和內核態的進程執行,其中的內核棧就是用於內核態的堆棧,它和進程的task_struct結構,更具體的是thread_info結構一起放在兩個連續的頁框大小的空間內。
現在我們從特權級的調度來理解用戶態和內核態就比較好理解了,當程序運行在3級特權級上時,就可以稱之為運行在用戶態,因為這是最低特權級,是普通的用戶進程運行的特權級,大部分用戶直接面對的程序都是運行在用戶態;反之,當程序運行在0級特權級上時,就可以稱之為運行在內核態。
雖然用戶態下和內核態下工作的程序有很多差別,但最重要的差別就在於特權級的不同,即權力的不同。運行在用戶態的程序不能訪問操作系統內核數據結構合程序。 當我們在系統中執行一個程序時,大部分時間是運行在用戶態下的。在其需要操作系統幫助完成某些它沒有權力和能力完成的工作時就會切換到內核態。
Linux進程的4GB地址空間,3G-4G部分大家是共享的,是內核態的地址空間,這里存放在整個內核的代碼和所有的內核模塊,以及內核所維護的數據。用戶運行一個程序,該程序所創建的進程開始是運行在用戶態的,如果要執行文件操作,網路數據發送等操作,必須通過write,send等系統調用,這些系統調用會調用內核中的代碼來完成操作,這時,必須切換到Ring0,然後進入3GB-4GB中的內核地址空間去執行這些代碼完成操作,完成後,切換回Ring3,回到用戶態。這樣,用戶態的程序就不能隨意操作內核地址空間,具有一定的安全保護作用。
保護模式,通過內存頁表操作等機制,保證進程間的地址空間不會互相沖突,一個進程的操作不會修改另一個進程的地址空間中的數據。在內核態下,CPU可執行任何指令,在用戶態下CPU只能執行非特權指令。當CPU處於內核態,可以隨意進入用戶態;而當CPU處於用戶態,只能通過中斷的方式進入內核態。一般程序一開始都是運行於用戶態,當程序需要使用系統資源時,就必須通過調用軟中斷進入內核態.

⑻ Linux內核中用戶空間棧和內核棧的區別

您好,很高興為您解答。
1.進程的堆棧

內核在創建進程的時候,在創建task_struct的同事,會為進程創建相應的堆棧。每個進程會有兩個棧,一個用戶棧,存在於用戶空間,一個內核棧,存在於內核空間。當進程在用戶空間運行時,cpu堆棧指針寄存器裡面的內容是用戶堆棧地址,使用用戶棧;當進程在內核空間時,cpu堆棧指針寄存器裡面的內容是內核棧空間地址,使用內核棧。
2.進程用戶棧和內核棧的切換

當進程因為中斷或者系統調用而陷入內核態之行時,進程所使用的堆棧也要從用戶棧轉到內核棧。

進程陷入內核態後,先把用戶態堆棧的地址保存在內核棧之中,然後設置堆棧指針寄存器的內容為內核棧的地址,這樣就完成了用戶棧向內核棧的轉換;當進程從內核態恢復到用戶態之行時,在內核態之行的最後將保存在內核棧裡面的用戶棧的地址恢復到堆棧指針寄存器即可。這樣就實現了內核棧和用戶棧的互轉。

那麼,我們知道從內核轉到用戶態時用戶棧的地址是在陷入內核的時候保存在內核棧裡面的,但是在陷入內核的時候,我們是如何知道內核棧的地址的呢?

關鍵在進程從用戶態轉到內核態的時候,進程的內核棧總是空的。這是因為,當進程在用戶態運行時,使用的是用戶棧,當進程陷入到內核態時,內核棧保存進程在內核態運行的相關信心,但是一旦進程返回到用戶態後,內核棧中保存的信息無效,會全部恢復,因此每次進程從用戶態陷入內核的時候得到的內核棧都是空的。所以在進程陷入內核的時候,直接把內核棧的棧頂地址給堆棧指針寄存器就可以了。
3.內核棧的實現

內核棧在kernel-2.4和kernel-2.6裡面的實現方式是不一樣的。
在kernel-2.4內核裡面,內核棧的實現是:
union task_union {
struct task_struct task;
unsigned long stack[init_stack_size/sizeof(long)];
}; 其中,init_stack_size的大小隻能是8k。

內核為每個進程分配task_struct結構體的時候,實際上分配兩個連續的物理頁面,底部用作task_struct結構體,結構上面的用作堆棧。使用current()宏能夠訪問當前正在運行的進程描述符。
注意:這個時候task_struct結構是在內核棧裡面的,內核棧的實際能用大小大概有7k。

內核棧在kernel-2.6裡面的實現是(kernel-2.6.32):

union thread_union {
struct thread_info thread_info;
unsigned long stack[thread_size/sizeof(long)];
}; 其中thread_size的大小可以是4k,也可以是8k,thread_info佔52bytes。

當內核棧為8k時,thread_info在這塊內存的起始地址,內核棧從堆棧末端向下增長。所以此時,kernel-2.6中的current宏是需要更改的。要通過thread_info結構體中的task_struct域來獲得於thread_info相關聯的task。更詳細的參考相應的current宏的實現。
struct thread_info {
struct task_struct *task;
struct exec_domain *exec_domain;
__u32 flags;
__u32 status;
__u32 cpu;
… ..
}; 注意:此時的task_struct結構體已經不在內核棧空間裡面了。
如若滿意,請點擊右側【採納答案】,如若還有問題,請點擊【追問】
希望我的回答對您有所幫助,望採納!

~
o(∩_∩)o~

⑼ 內核棧和用戶棧的區別

內核棧和用戶棧區別:
intel的cpu分為四個運行級別ring0~ring3
內核創建進程,創建進程的同時創建進程式控制制塊,創建進程自己的堆棧
一個進程有兩個堆棧,用戶棧和系統棧
用戶堆棧的空間指向用戶地址空間,內核堆棧的空間指向內核地址空間。
有個CPU堆棧指針寄存器,進程運行的狀態有用戶態和內核態,當進程運行在用戶態時。CPU堆棧指針寄存器指向的是用戶堆棧地址,使用的是用戶堆棧;當進程運行在內核態時,CPU堆棧指針寄存器指向的是內核堆棧地址,使用的是內核堆棧。
堆棧切換
當系統因為系統調用(軟中斷)或硬體中斷,CPU切換到特權工作模式,進程陷入內核態,進程使用的棧也要從用戶棧轉向系統棧。
從用戶態到內核態要兩步驟,首先是將用戶堆棧地址保存到內核堆棧中,然後將CPU堆棧指針寄存器指向內核堆棧。
當由內核態轉向用戶態,步驟首先是將內核堆棧中得用戶堆棧地址恢復到CPU堆棧指針寄存器中。
內核棧和用戶棧區別
1.
棧是系統運行在內核態的時候使用的棧,用戶棧是系統運行在用戶態時候使用的棧。
當進程由於中斷進入內核態時,系統會把一些用戶態的數據信息保存到內核棧中,當返回到用戶態時,取出內核棧中得信息恢復出來,返回到程序原來執行的地方。
用戶棧就是進程在用戶空間時創建的棧,比如一般的函數調用,將會用到用戶棧。
2.
內核棧是屬於操作系統空間的一塊固定區域,可以用於保存中斷現場、保存操作系統子程序間相互調用的參數、返回值等。
用戶棧是屬於用戶進程空間的一塊區域,用戶保存用戶進程子程序間的相互調用的參數、返回值等。
3.
每個Windows 都有4g的進程空間,系統棧使用進程空間的地段部分,用戶棧是高端部分如果用戶要直接訪問系統棧部分,需要有特殊的方式。
為何要設置兩個不同的棧?
共享原因:
內核的代碼和數據是為所有的進程共享的,如果不為每一個進程設置對應的內核棧,那麼就不能實現不同的進程執行不同的代碼。
安全原因:
如果只有一個棧,那麼用戶就可以修改棧內容來突破內核安全保護。

⑽ linux內核態和用戶態的通信機制包括哪些

究竟什麼是用戶態,什麼是內核態,這兩個基本概念以前一直理解得不是很清楚,根本原因個人覺得是在於因為大部分時候我們在寫程序時關注的重點和著眼的角度放在了實現的功能和代碼的邏輯性上,先看一個例子:

1)例子

C代碼
1. void testfork(){
2. if(0 = = fork()){
3. printf(「create new process success!\n」);
4. }
5. printf(「testfork ok\n」);
6. }

這段代碼很簡單,從功能的角度來看,就是實際執行了一個fork(),生成一個新的進程,從邏輯的角度看,就是判斷了如果fork()返回的是則列印相關語句,然後函數最後再列印一句表示執行完整個testfork()函數。代碼的執行邏輯和功能上看就是如此簡單,一共四行代碼,從上到下一句一句執行而已,完全看不出來哪裡有體現出用戶態和進程態的概念。

如果說前面兩種是靜態觀察的角度看的話,我們還可以從動態的角度來看這段代碼,即它被轉換成CPU執行的指令後載入執行的過程,這時這段程序就是一個動態執行的指令序列。而究竟載入了哪些代碼,如何載入就是和操作系統密切相關了。

2)特權級

熟悉Unix/Linux系統的人都知道,fork的工作實際上是以系統調用的方式完成相應功能的,具體的工作是由sys_fork負責實施。其實無論是不是Unix或者Linux,對於任何操作系統來說,創建一個新的進程都是屬於核心功能,因為它要做很多底層細致地工作,消耗系統的物理資源,比如分配物理內存,從父進程拷貝相關信息,拷貝設置頁目錄頁表等等,這些顯然不能隨便讓哪個程序就能去做,於是就自然引出特權級別的概念,顯然,最關鍵性的權力必須由高特權級的程序來執行,這樣才可以做到集中管理,減少有限資源的訪問和使用沖突。

特權級顯然是非常有效的管理和控製程序執行的手段,因此在硬體上對特權級做了很多支持,就Intel x86架構的CPU來說一共有0~3四個特權級,0級最高,3級最低,硬體上在執行每條指令時都會對指令所具有的特權級做相應的檢查,相關的概念有 CPL、DPL和RPL,這里不再過多闡述。硬體已經提供了一套特權級使用的相關機制,軟體自然就是好好利用的問題,這屬於操作系統要做的事情,對於 Unix/Linux來說,只使用了0級特權級和3級特權級。也就是說在Unix/Linux系統中,一條工作在級特權級的指令具有了CPU能提供的最高權力,而一條工作在3級特權級的指令具有CPU提供的最低或者說最基本權力。

3)用戶態和內核態

現在我們從特權級的調度來理解用戶態和內核態就比較好理解了,當程序運行在3級特權級上時,就可以稱之為運行在用戶態,因為這是最低特權級,是普通的用戶進程運行的特權級,大部分用戶直接面對的程序都是運行在用戶態;反之,當程序運行在級特權級上時,就可以稱之為運行在內核態。

雖然用戶態下和內核態下工作的程序有很多差別,但最重要的差別就在於特權級的不同,即權力的不同。運行在用戶態下的程序不能直接訪問操作系統內核數據結構和程序,比如上面例子中的testfork()就不能直接調用 sys_fork(),因為前者是工作在用戶態,屬於用戶態程序,而sys_fork()是工作在內核態,屬於內核態程序。

當我們在系統中執行一個程序時,大部分時間是運行在用戶態下的,在其需要操作系統幫助完成某些它沒有權力和能力完成的工作時就會切換到內核態,比如testfork()最初運行在用戶態進程下,當它調用fork()最終觸發 sys_fork()的執行時,就切換到了內核態。

2. 用戶態和內核態的轉換

1)用戶態切換到內核態的3種方式

a. 系統調用

這是用戶態進程主動要求切換到內核態的一種方式,用戶態進程通過系統調用申請使用操作系統提供的服務程序完成工作,比如前例中fork()實際上就是執行了一個創建新進程的系統調用。而系統調用的機制其核心還是使用了操作系統為用戶特別開放的一個中斷來實現,例如Linux的int 80h中斷。

b. 異常

當CPU在執行運行在用戶態下的程序時,發生了某些事先不可知的異常,這時會觸發由當前運行進程切換到處理此異常的內核相關程序中,也就轉到了內核態,比如缺頁異常。

c. 外圍設備的中斷

當外圍設備完成用戶請求的操作後,會向CPU發出相應的中斷信號,這時CPU會暫停執行下一條即將要執行的指令轉而去執行與中斷信號對應的處理程序,如果先前執行的指令是用戶態下的程序,那麼這個轉換的過程自然也就發生了由用戶態到內核態的切換。比如硬碟讀寫操作完成,系統會切換到硬碟讀寫的中斷處理程序中執行後續操作等。

這3種方式是系統在運行時由用戶態轉到內核態的最主要方式,其中系統調用可以認為是用戶進程主動發起的,異常和外圍設備中斷則是被動的。

2)具體的切換操作

從觸發方式上看,可以認為存在前述3種不同的類型,但是從最終實際完成由用戶態到內核態的切換操作上來說,涉及的關鍵步驟是完全一致的,沒有任何區別,都相當於執行了一個中斷響應的過程,因為系統調用實際上最終是中斷機制實現的,而異常和中斷的處理機制基本上也是一致的,關於它們的具體區別這里不再贅述。關於中斷處理機制的細節和步驟這里也不做過多分析,涉及到由用戶態切換到內核態的步驟主要包括:

[1] 從當前進程的描述符中提取其內核棧的ss0及esp0信息。

[2] 使用ss0和esp0指向的內核棧將當前進程的cs,eip,eflags,ss,esp信息保存起來,這個

過程也完成了由用戶棧到內核棧的切換過程,同時保存了被暫停執行的程序的下一

條指令。

[3] 將先前由中斷向量檢索得到的中斷處理程序的cs,eip信息裝入相應的寄存器,開始

執行中斷處理程序,這時就轉到了內核態的程序執行了。

閱讀全文

與linux用戶棧內核棧相關的資料

熱點內容
解壓小熊手機殼 瀏覽:342
成都市區建成面積演算法 瀏覽:658
智能家居單片機 瀏覽:95
買男裝用什麼app好 瀏覽:853
文件夾合並了怎麼拆開 瀏覽:257
波段副圖源碼無未來函數 瀏覽:86
livecn伺服器地址 瀏覽:257
程序員這個工作真的很吃香嗎 瀏覽:844
程序員和數學分析師待遇 瀏覽:678
壓縮氣彈簧怎麼拆 瀏覽:321
華為公有雲伺服器添加虛擬ip 瀏覽:209
程序員和運營哪個累 瀏覽:24
抖音安卓信息提示音怎麼設置 瀏覽:454
光速虛擬機的共享文件夾 瀏覽:248
程序員培訓機構發的朋友圈真實性 瀏覽:744
天乾地支簡單演算法 瀏覽:299
下載個壓縮文件 瀏覽:300
普通人電腦關機vs程序員關機 瀏覽:630
米酷建站源碼 瀏覽:115
氫氣app怎麼搜搭配 瀏覽:619