《電子技術(shù)應(yīng)用》
您所在的位置:首頁(yè) > 可編程邏輯 > 其他 > Linux進(jìn)程是如何創(chuàng)建出來(lái)的?

Linux進(jìn)程是如何創(chuàng)建出來(lái)的?

2022-11-18
作者:張彥飛allen
來(lái)源:電子技術(shù)應(yīng)用專欄作家 一口Linux
關(guān)鍵詞: Linux進(jìn)程

  在 Linux 中,進(jìn)程是我們非常熟悉的東東了,哪怕是只寫過(guò)一天代碼的人也都用過(guò)它。但是你確定它不是你最熟悉的陌生人?我們今天通過(guò)深度剖析進(jìn)程的創(chuàng)建過(guò)程,幫助你提高對(duì)進(jìn)程的理解深度。

  在這篇文章中,我會(huì)用 Nginx 創(chuàng)建 worker 進(jìn)程的例子作為引入,然后帶大家了解一些進(jìn)程的數(shù)據(jù)結(jié)構(gòu) task_struct,最后再帶大家看一下 fork 執(zhí)行的過(guò)程。

  學(xué)習(xí)完本文,你將深度理解進(jìn)程中的那些關(guān)鍵要素,諸如進(jìn)程地址空間、當(dāng)前目錄、父子進(jìn)程關(guān)系、進(jìn)程打開的文件 fd 表、進(jìn)程命名空間等。也能學(xué)習(xí)到內(nèi)核在保存已經(jīng)使用的 pid 號(hào)時(shí)是如何優(yōu)化內(nèi)存占用的。我們展開今天的拆解!

  一、Nginx 之 fork 創(chuàng)建 worker

  在 Linux 進(jìn)程的創(chuàng)建中,最核心的就是 fork 系統(tǒng)調(diào)用。不過(guò)我們先不著急介紹它,先拿多進(jìn)程服務(wù)中的一個(gè)經(jīng)典例子 - Nginx,來(lái)看看他是如何使用 fork 來(lái)創(chuàng)建 worker 的。

  Nginx 服務(wù)采用的是多進(jìn)程方式來(lái)工作的,它啟動(dòng)的時(shí)候會(huì)創(chuàng)建若干個(gè) worker 進(jìn)程出來(lái),來(lái)響應(yīng)和處理用戶請(qǐng)求。創(chuàng)建 worker 子進(jìn)程的源碼位于 nginx 源碼的 src/os/unix/ngx_process_cycle.c 文件中。通過(guò)循環(huán)調(diào)用 ngx_spawn_process 來(lái)創(chuàng)建 n 個(gè) worker 出來(lái)。

 微信截圖_20221118145602.png

  在 ngx_spawn_process 中調(diào)用 fork 來(lái)創(chuàng)建進(jìn)程,創(chuàng)建成功后 Worker 進(jìn)程就將進(jìn)入自己的入口函數(shù)中開始工作了。

  二、Linux 中對(duì)進(jìn)程的表示

  在深入理解進(jìn)程創(chuàng)建之前,我們先來(lái)看一下進(jìn)程的數(shù)據(jù)結(jié)構(gòu)。

  在 Linux 中,是用一個(gè) task_struct 來(lái)實(shí)現(xiàn) Linux 進(jìn)程的(其實(shí) Linux 線程也同樣是用 task_struct 來(lái)表示的,這個(gè)我們以后文章單獨(dú)再說(shuō))。

  微信截圖_20221118145630.png

  我們來(lái)看看 task_struct 具體的定義,它位于 include/linux/sched.h

  微信截圖_20221118145648.png

  2.1 進(jìn)程線程狀態(tài)

  進(jìn)程線程都是有狀態(tài)的,它的狀態(tài)就保存在 state 字段中。常見的狀態(tài)中 TASK_RUNNING 表示進(jìn)程線程處于就緒狀態(tài)或者是正在執(zhí)行。TASK_INTERRUPTIBLE 表示進(jìn)程線程進(jìn)入了阻塞狀態(tài)。

  一個(gè)任務(wù)(進(jìn)程或線程)剛創(chuàng)建出來(lái)的時(shí)候是 TASK_RUNNING 就緒狀態(tài),等待調(diào)度器的調(diào)度。調(diào)度器執(zhí)行 schedule 后,任務(wù)獲得 CPU 后進(jìn)入  執(zhí)行進(jìn)行運(yùn)行。當(dāng)需要等待某個(gè)事件的時(shí)候,例如阻塞式 read 某個(gè) socket 上的數(shù)據(jù),但是數(shù)據(jù)還沒有到達(dá)的時(shí)候,任務(wù)進(jìn)入 TASK_INTERRUPTIBLE 或 TASK_UNINTERRUPTIBLE 狀態(tài),任務(wù)被阻塞掉。

  當(dāng)?shù)却氖录竭_(dá)以后,例如 socket 上的數(shù)據(jù)到達(dá)了。內(nèi)核在收到數(shù)據(jù)后會(huì)查看 socket 上阻塞的等待任務(wù)隊(duì)列,然后將之喚醒,使得任務(wù)重新進(jìn)入 TASK_RUNNING 就緒狀態(tài)。任務(wù)如此往復(fù)地在各個(gè)狀態(tài)之間循環(huán),直到退出。

  一個(gè)任務(wù)(進(jìn)程或線程)的大概狀態(tài)流轉(zhuǎn)圖如下。

  微信截圖_20221118145721.png

  全部的狀態(tài)值在 include/linux/sched.h 中進(jìn)行了定義。

  微信截圖_20221118145747.png

  2.2 進(jìn)程 ID

  我們知道,每一個(gè)進(jìn)程都有一個(gè)進(jìn)程 id 的概念。在 task_struct 中有兩個(gè)相關(guān)的字段,分別是 pid 和 tgid。

 微信截圖_20221118145836.png

  其中 pid 是 Linux 為了標(biāo)識(shí)每一個(gè)進(jìn)程而分配給它們的唯一號(hào)碼,稱做進(jìn)程 ID 號(hào),簡(jiǎn)稱 PID。對(duì)于沒有創(chuàng)建線程的進(jìn)程(只包含一個(gè)主線程)來(lái)說(shuō),這個(gè) pid 就是進(jìn)程的 PID,tgid 和 pid 是相同的。

  微信截圖_20221118145858.png

  2.3 進(jìn)程樹關(guān)系

  在 Linux 下所有的進(jìn)程都是通過(guò)一棵樹來(lái)管理的。在操作系統(tǒng)啟動(dòng)的時(shí)候,會(huì)創(chuàng)建 init 進(jìn)程,接下來(lái)所有的進(jìn)程都是由這個(gè)進(jìn)程直接或者間接創(chuàng)建的的。通過(guò) pstree 命令可以查看你當(dāng)前服務(wù)器上的進(jìn)程樹信息。

微信截圖_20221118150005.png

  那么,這棵進(jìn)程樹就是由 task_struct 下的 parent、children、sibling 等字段來(lái)表示的。這幾個(gè)字段將系統(tǒng)中的所有 task 串成了一棵樹。

  微信截圖_20221118150036.png

  2.4 進(jìn)程調(diào)度優(yōu)先級(jí)

  在 task_struct 中有幾個(gè)字段是表示進(jìn)程優(yōu)先級(jí)的,在進(jìn)程調(diào)度的時(shí)候會(huì)根據(jù)這幾個(gè)字段來(lái)決定優(yōu)先讓哪個(gè)任務(wù)(進(jìn)程或線程)開始執(zhí)行。

  static_prio: 用來(lái)保存靜態(tài)優(yōu)先級(jí),可以調(diào)用 nice 系統(tǒng)直接來(lái)修改取值范圍為 100~139

  rt_priority: 用來(lái)保存實(shí)時(shí)優(yōu)先級(jí),取值范圍為 0~99

  prio: 用來(lái)保存動(dòng)態(tài)優(yōu)先級(jí)

  normal_prio: 它的值取決于靜態(tài)優(yōu)先級(jí)和調(diào)度策略

  2.5 進(jìn)程地址空間

  對(duì)于用戶進(jìn)程來(lái)講,內(nèi)存描述符 mm_struct( mm 代表的是 memory descriptor)是非常核心的數(shù)據(jù)結(jié)構(gòu)。整個(gè)進(jìn)程的虛擬地址空間部分都是由它來(lái)表示的。

  進(jìn)程在運(yùn)行的時(shí)候,在用戶態(tài)其所需要的代碼,全局變量數(shù)據(jù),以及 mmap 內(nèi)存映射等全部都是通過(guò) mm_struct 來(lái)進(jìn)行內(nèi)存查找和尋址的。這個(gè)數(shù)據(jù)結(jié)構(gòu)的定義位于 include/linux/mm_types.h 文件下。

 微信截圖_20221118150057.png

  其中 start_code、end_code 分別指向代碼段的開始與結(jié)尾、start_data 和 end_data 共同決定數(shù)據(jù)段的區(qū)域、start_brk 和 brk 中間是堆內(nèi)存的位置、start_stack 是用戶態(tài)堆棧的起始地址。整個(gè) mm_struct 和地址空間、頁(yè)表、物理內(nèi)存的關(guān)系如下圖。

  微信截圖_20221118150126.png

  在內(nèi)核內(nèi)存區(qū)域,可以通過(guò)直接計(jì)算得出物理內(nèi)存地址,并不需要復(fù)雜的頁(yè)表計(jì)算。而且最重要的是所有內(nèi)核進(jìn)程、以及用戶進(jìn)程的內(nèi)核態(tài),這部分內(nèi)存都是共享的。

  微信截圖_20221118150145.png

  另外要注意的是,mm(mm_struct)表示的是虛擬地址空間。而對(duì)于內(nèi)核線程來(lái)說(shuō),是沒有用戶態(tài)的虛擬地址空間的。所以內(nèi)核線程的 mm 的值是 null。

  2.6 進(jìn)程文件系統(tǒng)信息(當(dāng)前目錄等)

  進(jìn)程的文件位置等信息是由 fs_struct 來(lái)描述的,它的定義位于 include/linux/fs_struct.h 文件中。

 微信截圖_20221118150200.png

  通過(guò)以上代碼可以看出,在 fs_struct 中包含了兩個(gè) path 對(duì)象,而每個(gè) path 中都指向了一個(gè) struct dentry。在 Linux 內(nèi)核中,denty 結(jié)構(gòu)是對(duì)一個(gè)目錄項(xiàng)的描述。

  微信截圖_20221118150225.png

  拿 pwd 來(lái)舉例,該指針指向的是進(jìn)程當(dāng)前目錄所處的 denty 目錄項(xiàng)。假如我們?cè)?shell 進(jìn)程中執(zhí)行 pwd,或者用戶進(jìn)程查找當(dāng)前目錄下的配置文件的時(shí)候,都是通過(guò)訪問(wèn) pwd 這個(gè)對(duì)象,進(jìn)而找到當(dāng)前目錄的 denty 的。

  2.7 進(jìn)程打開的文件信息

  每個(gè)進(jìn)程用一個(gè) files_struct 結(jié)構(gòu)來(lái)記錄文件描述符的使用情況, 這個(gè) files_struct 結(jié)構(gòu)稱為用戶打開文件表。它的定義位于 include/linux/fdtable.h。

  注意:飛哥用的內(nèi)核源碼一直是 3.10.0, 所以本文也不例外。不同版本的源碼這里稍微可能有些出入。

 微信截圖_20221118150248.png

  在 files_struct 中,最重要的是在 fdtable 中包含的 file **fd 這個(gè)數(shù)組。這個(gè)數(shù)組的下標(biāo)就是文件描述符,其中 0、1、2 三個(gè)描述符總是默認(rèn)分配給標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤。這就是你在 shell 命令中經(jīng)常看到的 2>&1 的由來(lái)。這幾個(gè)字符的含義就是把標(biāo)準(zhǔn)錯(cuò)誤也一并打到標(biāo)準(zhǔn)輸出中來(lái)。

  微信截圖_20221118150318.png

  在數(shù)組元素中記錄了當(dāng)前進(jìn)程打開的每一個(gè)文件的指針。這個(gè)文件是 Linux 中抽象的文件,可能是真的磁盤上的文件,也可能是一個(gè) socket。

  2.8 namespaces

  在 Linux 中,namespace 是用來(lái)隔離內(nèi)核資源的方式。通過(guò) namespace 可以讓一些進(jìn)程只能看到與自己相關(guān)的一部分資源,而另外一些進(jìn)程也只能看到與它們自己相關(guān)的資源,這兩撥進(jìn)程根本就感覺不到對(duì)方的存在。

  具體的實(shí)現(xiàn)方式是把一個(gè)或多個(gè)進(jìn)程的相關(guān)資源指定在同一個(gè) namespace 中,而進(jìn)程究竟是屬于哪個(gè) namespace,都是在 task_struct 中由 *nsproxy 指針表明了這個(gè)歸屬關(guān)系。

微信截圖_20221118150345.png

  命名空間包括PID命名空間、掛載點(diǎn)命名空間、網(wǎng)絡(luò)命名空間等多個(gè)。飛哥在咱們「開發(fā)內(nèi)功修煉」前面的一篇文章《動(dòng)手實(shí)驗(yàn)+源碼分析,徹底弄懂Linux網(wǎng)絡(luò)命名空間》這一文中詳細(xì)介紹過(guò)網(wǎng)絡(luò)命名空間,感興趣的同學(xué)可以詳細(xì)閱讀。

  三、解密 fork 系統(tǒng)調(diào)用

  前面我們看了 Nginx 使用 fork 來(lái)創(chuàng)建 worker 進(jìn)程,也了解了進(jìn)程的數(shù)據(jù)結(jié)構(gòu) task_struct ,我們?cè)賮?lái)看看 fork 系統(tǒng)調(diào)用的內(nèi)部邏輯。

  這個(gè) fork 在內(nèi)核中是以一個(gè)系統(tǒng)調(diào)用來(lái)實(shí)現(xiàn)的,它的內(nèi)核入口是在 kernel/fork.c 下。

 微信截圖_20221118150411.png

  這里注意下調(diào)用 do_fork 時(shí)傳入的第一個(gè)參數(shù),這個(gè)參數(shù)是一個(gè) flag 選項(xiàng)。它可以傳入的值包括 CLONE_VM、CLONE_FS 和 CLONE_FILES 等等很多,但是這里只傳了一個(gè) SIGCHLD(子進(jìn)程在終止后發(fā)送 SIGCHLD 信號(hào)通知父進(jìn)程),并沒有傳 CLONE_FS 等其它 flag。

  微信截圖_20221118150421.png

  在 do_fork 的實(shí)現(xiàn)中,核心是一個(gè) copy_process 函數(shù),它以拷貝父進(jìn)程的方式來(lái)生成一個(gè)新的 task_struct 出來(lái)。

 微信截圖_20221118150435.png

  在創(chuàng)建完畢后,調(diào)用 wake_up_new_task 將新創(chuàng)建的任務(wù)添加到就緒隊(duì)列中,等待調(diào)度器調(diào)度執(zhí)行。

  copy_process 的代碼很長(zhǎng),我對(duì)其進(jìn)行了一定程度的精簡(jiǎn),參加下面的代碼。

  微信截圖_20221118150457.png

  可見,copy_process 先是復(fù)制了一個(gè)新的 task_struct 出來(lái),然后調(diào)用 copy_xxx 系列的函數(shù)對(duì) task_struct 中的各種核心對(duì)象進(jìn)行拷貝處理,還申請(qǐng)了 pid。接下來(lái)我們分小節(jié)來(lái)查看該函數(shù)的每一個(gè)細(xì)節(jié)。

  3.1 復(fù)制進(jìn)程 task_struct 結(jié)構(gòu)體

  注意一下,上面調(diào)用 dup_task_struct 時(shí)傳入的參數(shù)是 current,它表示的是當(dāng)前進(jìn)程。在 dup_task_struct 里,會(huì)申請(qǐng)一個(gè)新的 task_struct 內(nèi)核對(duì)象,然后將當(dāng)前進(jìn)程復(fù)制給它。需要注意的是,這次拷貝只會(huì)拷貝 task_struct 結(jié)構(gòu)體本身,它內(nèi)部包含的 mm_struct 等成員只是復(fù)制了指針,仍然指向和 current 相同的對(duì)象。

微信截圖_20221118150548.png

  

  3.2 拷貝 files_struct

  由于進(jìn)程之間都是獨(dú)立的,所以創(chuàng)建出來(lái)的新進(jìn)程需要拷貝一份獨(dú)立的 files 成員出來(lái)。

微信截圖_20221118150653.png

  我們看 copy_files 是如何申請(qǐng)和拷貝 files 成員的。

  微信截圖_20221118150703.png

  看上面代碼中判斷了是否有 CLONE_FILES 標(biāo)記,如果有的話就不執(zhí)行 dup_fd 函數(shù)了,增加個(gè)引用計(jì)數(shù)就返回了。前面我們說(shuō)了,do_fork 被調(diào)用時(shí)并沒有傳這個(gè)標(biāo)記。所以還是會(huì)執(zhí)行到 dup_fd 函數(shù):

 微信截圖_20221118150725.png

  這個(gè)函數(shù)就是到內(nèi)核中申請(qǐng)一塊內(nèi)存出來(lái),保存 files_struct 使用。然后對(duì)新的 files_struct 進(jìn)行各種初始化和拷貝。至此,新進(jìn)程有了自己獨(dú)立的 files 成員了。

  3.3 拷貝 fs_struct

  同樣,新進(jìn)程也需要一份獨(dú)立的文件系統(tǒng)信息 - fs_struct 成員的。

微信截圖_20221118150753.png

  在創(chuàng)建進(jìn)程的時(shí)候,沒有傳遞 CLONE_FS 這個(gè)標(biāo)志,所會(huì)進(jìn)入到 copy_fs_struct 函數(shù)中申請(qǐng)新的 fs_struct 并進(jìn)行賦值。

  微信截圖_20221118150808.png

  3.4 拷貝 mm_struct

  前面我們說(shuō)過(guò),對(duì)于進(jìn)程來(lái)講,地址空間是一個(gè)非常重要的數(shù)據(jù)結(jié)構(gòu)。而且進(jìn)程之間地址空間也必須是要隔離的,所以還會(huì)新建一個(gè)地址空間。

 微信截圖_20221118150825.png

  do_fork 被調(diào)用時(shí)也沒有傳 CLONE_VM,所以會(huì)調(diào)用 dup_mm 申請(qǐng)一個(gè)新的地址空間出來(lái)。

  微信截圖_20221118150845.png

  在 dup_mm 中,通過(guò) allocate_mm 申請(qǐng)了新的 mm_struct,而且還將當(dāng)前進(jìn)程地址空間 current->mm 拷貝到新的 mm_struct 對(duì)象里了。

  地址空間是進(jìn)程線程最核心的東西,每個(gè)進(jìn)程都有獨(dú)立的地址空間

  3.5 拷貝進(jìn)程的命名空間 nsproxy

  在創(chuàng)建進(jìn)程或線程的時(shí)候,還可以讓內(nèi)核幫我們創(chuàng)建獨(dú)立的命名空間。在默認(rèn)情況下,創(chuàng)建進(jìn)程沒有指定命名空間相關(guān)的標(biāo)記,因此也不會(huì)創(chuàng)建。新舊進(jìn)程仍然復(fù)用同一套命名空間對(duì)象。

微信截圖_20221118150906.png

  注意下,在調(diào)用 alloc_pid 的時(shí)候,其參數(shù)傳遞的是新進(jìn)程的 pid namespace。我們來(lái)深看一下 alloc_pid 的執(zhí)行邏輯。

 微信截圖_20221118150926.png

  這里的 PID 并不是一個(gè)整數(shù),而是一個(gè)結(jié)構(gòu)體,所以先試用 kmem_cache_alloc 把它申請(qǐng)出來(lái)。接下來(lái)調(diào)用 alloc_pidmap 到 pid 命名空間中申請(qǐng)一個(gè) pid 號(hào)出來(lái),申請(qǐng)完后賦值記錄。

  回顧我們開篇提到的一個(gè)問(wèn)題:操作系統(tǒng)是如何記錄使用過(guò)的進(jìn)程號(hào)的?在 Linux 內(nèi)部,為了節(jié)約內(nèi)存,進(jìn)程號(hào)是通過(guò) bitmap 來(lái)管理的。

  微信截圖_20221118150942.png

  在每一個(gè) pid 命名空間內(nèi)部,會(huì)有一個(gè)或者多個(gè)頁(yè)面來(lái)作為 bitmap。其中每一個(gè) bit 位(注意是 bit 位,不是字節(jié))的 0 或者 1 的狀態(tài)來(lái)表示當(dāng)前序號(hào)的 pid 是否被占用。

 微信截圖_20221118150957.png

  在各種語(yǔ)言中,一般一個(gè) int 都是 4 個(gè)字節(jié),換算成 bit 就是 32 bit。而使用這種 bitmap 的思想的話,只需要一個(gè) bit 就可以表示一個(gè)整數(shù),相當(dāng)?shù)墓?jié)約內(nèi)存。所以,在很多超大規(guī)模數(shù)據(jù)處理中都會(huì)用到這種思想來(lái)進(jìn)行優(yōu)化內(nèi)存占用的。

  3.7 進(jìn)入就緒隊(duì)列

  當(dāng) copy_process 執(zhí)行完畢的時(shí)候,表示新進(jìn)程的一個(gè)新的 task_struct 對(duì)象就創(chuàng)建出來(lái)了。接下來(lái)內(nèi)核會(huì)調(diào)用 wake_up_new_task 將這個(gè)新創(chuàng)建出來(lái)的子進(jìn)程添加到就緒隊(duì)列中等待調(diào)度。

 微信截圖_20221118151021.png

  等操作系統(tǒng)真正調(diào)度開始的時(shí)候,子進(jìn)程中的代碼就可以真正開始執(zhí)行了。

  四、總結(jié)

  在這篇文章中,我用 Nginx 創(chuàng)建 worker 進(jìn)程的例子作為引入,然后帶大家了解一些進(jìn)程的數(shù)據(jù)結(jié)構(gòu) task_struct,最后又帶大家看一下 fork 執(zhí)行的過(guò)程。

  在 fork 創(chuàng)建進(jìn)程的時(shí)候,地址空間 mm_struct、掛載點(diǎn) fs_struct、打開文件列表 files_struct 都要是獨(dú)立擁有的,所以都去申請(qǐng)內(nèi)存并初始化了它們。但由于今天我們的例子父子進(jìn)程是同一個(gè)命名空間,所以 nsproxy 還仍然是共用的。

  微信截圖_20221118151037.png

  其中 mm_struct 是一個(gè)非常核心的數(shù)據(jù)結(jié)構(gòu),用戶進(jìn)程的虛擬地址空間就是用它來(lái)表示的。對(duì)于內(nèi)核線程來(lái)講,不需要虛擬地址空間,所以 mm 成員的值為 null。

  另外還學(xué)到了內(nèi)核是用 bitmap 來(lái)管理使用和為使用的 pid 號(hào)的,這樣做的好處是極大地節(jié)約了內(nèi)存開銷。而且由于數(shù)據(jù)存儲(chǔ)的足夠緊湊,遍歷起來(lái)也是非常的快。一方面原因是數(shù)據(jù)小,加載起來(lái)快。另外一方面是會(huì)加大提高 CPU 緩存的命中率,訪問(wèn)非常快。

  今天的進(jìn)程創(chuàng)建過(guò)程就學(xué)習(xí)完了。不過(guò)細(xì)心的同學(xué)可能發(fā)現(xiàn)了,我們這里只介紹了子進(jìn)程的調(diào)用。但是對(duì)于 Nginx 主進(jìn)程如何加載起來(lái)執(zhí)行的還沒有講到。我們將來(lái)還會(huì)展開敘述,敬請(qǐng)期待!

  更多信息可以來(lái)這里獲取==>>電子技術(shù)應(yīng)用-AET<<

微信圖片_20210517164139.jpg

本站內(nèi)容除特別聲明的原創(chuàng)文章之外,轉(zhuǎn)載內(nèi)容只為傳遞更多信息,并不代表本網(wǎng)站贊同其觀點(diǎn)。轉(zhuǎn)載的所有的文章、圖片、音/視頻文件等資料的版權(quán)歸版權(quán)所有權(quán)人所有。本站采用的非本站原創(chuàng)文章及圖片等內(nèi)容無(wú)法一一聯(lián)系確認(rèn)版權(quán)者。如涉及作品內(nèi)容、版權(quán)和其它問(wèn)題,請(qǐng)及時(shí)通過(guò)電子郵件或電話通知我們,以便迅速采取適當(dāng)措施,避免給雙方造成不必要的經(jīng)濟(jì)損失。聯(lián)系電話:010-82306118;郵箱:[email protected]
主站蜘蛛池模板: chinese农村野战videos | 日本vs欧美一区二区三区 | 久久一区二区精品综合 | 精品国产91在线网 | 国产区久久 | 久久福利青草精品资源 | 天干天干天啪啪夜爽爽色 | 美国三级视频 | 国产在线精品一区二区三区 | 国产精品自在线天天看片 | 美女视频永久黄网站免费观看韩国 | 手机亚洲第一页 | 宅男69免费永久网站 | 性生活视频网 | 亚洲欧美另类日本久久影院 | 九九精品视频一区二区三区 | 国产精选莉莉私人影院 | 久久亚洲国产成人影院 | 亚洲免费在线视频 | 欧美黑寡妇特a级做爰 | 国内精品久久久久影院免费 | 国产精品吹潮在线播放 | 欧美片欧美日韩国产综合片 | 91精品一区国产高清在线 | 精品国产日韩亚洲一区在线 | 美女免费毛片 | 国产成人精品日本亚洲专区6 | 泰国情欲片寂寞的寡妇在线观看 | 免费看一级欧美激情毛片 | 亚洲成人精品久久 | 欧美精品久久久久久久影视 | 中文字幕视频在线观看 | 亚洲免费视频一区二区三区 | 国产成人精品午夜 | 一级毛片在线不卡直接观看 | 一色屋成人免费精品网 | 久久久精品久久久久三级 | 国产精品一区伦免视频播放 | 手机看片久久国产免费不卡 | 精品在线视频观看 | 亚洲精品一区二三区在线观看 |