青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

   C++ 技術中心

   :: 首頁 :: 聯系 ::  :: 管理
  160 Posts :: 0 Stories :: 87 Comments :: 0 Trackbacks

公告

鄭重聲明:本BLOG所發表的原創文章,作者保留一切權利。必須經過作者本人同意后方可轉載,并注名作者(天空)和出處(CppBlog.com)。作者Email:coder@luckcoder.com

留言簿(27)

搜索

  •  

最新隨筆

最新評論

評論排行榜

簡介: 本文詳細論述 UNIX 環境上的進程異常退出,將導致進程異常退出的各種情景歸納為兩類,對每類情況詳細分析了問題出現的根本原因,同時添加了相應的實例以易于您更好地進行了解。在此基礎上,文章最后論述了應該如何避免和調試進程異常退出問題。希望讀者閱讀此文后,對進程異常退出問題有更深層的認識,有更系統的梳理,對調試此類進程崩潰問題時也能有所幫助,寫出更穩定、更可靠的軟件。


進程異常退出

進程退出意味著進程生命期的結束,系統資源被回收,進程從操作系統環境中銷毀。進程異常退出是進程在運行過程中被意外終止,從而導致進程本來應該繼續執行的任務無法完成。

進程異常退出可能給軟件用戶造成如下負面影響:

  • 軟件喪失部分或者全部功能性,無法完成既定任務。
  • 如果進程正在處理數據,可能造成數據損壞。
  • 如果是關鍵軟件服務,必然導致服務異常中止 , 造成無法預計的損失。
  • 進程異常退出或者進程崩潰 , 也會給軟件用戶造成恐慌和困惑。

進程異常退出是生產環境中經常遇到的問題,它會給軟件用戶造成很多負面影響,所以軟件開發者應當避免這種問題的出現。但是導致進程異常退出的場景和原因是多種多樣的,甚至令人琢磨不透。

本文將所有可能造成進程異常退出的原因歸結為兩類。系統地將其分類,使讀者對此類問題能有清晰的認識。對每類情況詳細論述,分析根本原因,然后分析了這兩類情況之間的聯系,也就是信號與進程異常退出的緊密關系。希望您讀完此文后,能對此類問題有更加全面、深入的理解,對調試此類問題也能有所幫助,寫出更加可靠、更加穩定性、更加健壯的軟件。

首先我們來看導致進程異常退出的這兩類情況:

  • 第一類:向進程發送信號導致進程異常退出;
  • 第二類:代碼錯誤導致進程運行時異常退出。

回頁首

第一類:向進程發送信號導致進程異常退出

信號

UNIX 系統中的信號是系統響應某些狀況而產生的事件,是進程間通信的一種方式。信號可以由一個進程發送給另外進程,也可以由核發送給進程。

信號處理程序:

信號處理程序是進程在接收到信號后,系統對信號的響應。根據具體信號的涵義,相應的默認信號處理程序會采取不同的信號處理方式:

  • 終止進程運行,并且產生 core dump 文件。
  • 終止進程運行。
  • 忽略信號,進程繼續執行。
  • 暫停進程運行。
  • 如果進程已被暫停,重新調度進程繼續執行。

前兩種方式會導致進程異常退出,是本文討論的范圍。實際上,大多數默認信號處理程序都會終止進程的運行。

在進程接收到信號后,如果進程已經綁定自定義的信號處理程序,進程會在用戶態執行自定義的信號處理程序;反之,內核會執行默認信號程序終止進程運行,導致進程異常退出。


圖 1. 默認信號處理程序終止進程運行
圖 1. 默認信號處理程序終止進程運行 

所以,通過向進程發送信號可以觸發默認信號處理程序,默認信號處理程序終止進程運行。在 UNIX 環境中我們有三種方式將信號發送給目標進程,導致進程異常退出。

方式一:調用函數 kill() 發送信號

我們可以調用函數 kill(pid_t pid, int sig) 向進程 ID 為 pid 的進程發送信號 sig。這個函數的原型是:

 #include <sys/types.h>   #include <signal.h>   int kill(pid_t pid, int sig);  

調用函數 kill() 后,進程進入內核態向目標進程發送指定信號;目標進程在接收到信號后,默認信號處理程序被調用,進程異常退出。


清單 1. 調用 kill() 函數發送信號
				  /* sendSignal.c, send the signal ‘ SIGSEGV ’ to specific process*/        1 #include <sys/types.h>        2 #include <signal.h>        3        4 int main(int argc, char* argv[])        5 {        6     char* pid = argv[1];        7     int PID = atoi(pid);        8        9     kill(PID, SIGSEGV);       10     return 0;       11 }  

上面的代碼片段演示了如何調用 kill() 函數向指定進程發送 SIGSEGV 信號。編譯并且運行程序:

 [root@machine ~]# gcc -o sendSignal sendSignal.c   [root@machine ~]# top &   [1] 22055   [root@machine ~]# ./sendSignal 22055   [1]+  Stopped                 top   [root@machine ~]# fg %1   top   Segmentation fault (core dumped)  

上面的操作中,我們在后臺運行 top,進程 ID 是 22055,然后運行 sendSignal 向它發送 SIGSEGV 信號,導致 top 進程異常退出,產生 core dump 文件。

方式二:運行 kill 命令發送信號

用戶可以在命令模式下運行 kill 命令向目標進程發送信號,格式為:

kill SIG*** PID

在運行 kill 命令發送信號后,目標進程會異常退出。這也是系統管理員終結某個進程的最常用方法,類似于在 Windows 平臺通過任務管理器殺死某個進程。

在實現上,kill 命令也是調用 kill 系統調用函數來發送信號。所以本質上,方式一和方式二是一樣的。

操作演示如下:

 [root@machine ~]# top &   [1] 22810   [root@machine ~]# kill -SIGSEGV 22810   [1]+  Stopped                 top   [root@machine ~]# fg %1   top   Segmentation fault (core dumped)  

方式三:在終端使用鍵盤發送信號

用戶還可以在終端用鍵盤輸入特定的字符(比如 control-C 或 control-\)向前臺進程發送信號,終止前臺進程運行。常見的中斷字符組合是,使用 control-C 發送 SIGINT 信號,使用 control-\ 發送 SIGQUIT 信號,使用 control-z 發送 SIGTSTP 信號。

在實現上,當用戶輸入中斷字符組合時,比如 control-C,終端驅動程序響應鍵盤輸入,并且識別 control-C 是信號 SIGINT 的產生符號,然后向前臺進程發送 SIGINT 信號。當前臺進程再次被調用時就會接收到 SIGINT 信號。

使用鍵盤中斷組合符號發送信號演示如下:

 [root@machine ~]# ./loop.sh  ( 注釋:運行一個前臺進程,任務是每秒鐘打印一次字符串 )   i'm looping ...   i'm looping ...   i'm looping ...                 ( 注釋:此時,用戶輸入 control-C)   [root@machine ~]#               ( 注釋:接收到信號后,進程退出 )  

對這類情況的思考

這類情況導致的進程異常退出,并不是軟件編程錯誤所導致,而是進程外部的異步信號所致。但是我們可以在代碼編寫中做的更好,通過調用 signal 函數綁定信號處理程序來應對信號的到來,以提高軟件的健壯性。

signal 函數的原型:

 #include <signal.h>   void (*signal(int sig, void (*func)(int)))(int);  

signal 函數將信號 sig 和自定義信號處理程序綁定,即當進程收到信號 sig 時自定義函數 func 被調用。如果我們希望軟件在運行時屏蔽某個信號,插入下面的代碼,以達到屏蔽信號 SIGINT 的效果:

(void)signal(SIGINT, SIG_IGN);

執行這一行代碼后,當進程收到信號 SIGINT 后,進程就不會異常退出,而是會忽視這個信號繼續運行。

更重要的場景是,進程在運行過程中可能會創建一些臨時文件,我們希望進程在清理這些文件后再退出,避免遺留垃圾文件,這種情況下我們也可以調用 signal 函數實現,自定義一個信號處理程序來清理臨時文件,當外部發送信號要求進程終止運行時,這個自定義信號處理程序被調用做清理工作。代碼清單 2 是具體實現。


清單 2. 調用 signal 函數綁定自定義信號處理程序
				       /*  bindSignal.c  */        1 #include <signal.h>        2 #include <stdio.h>        3 #include <unistd.h>        4 void cleanTask(int sig) {        5     printf( "Got the signal, deleting the tmp file\n" );        6     if( access( "/tmp/temp.lock", F_OK ) != -1 ) {        7           if( remove( "/tmp/temp.lock" ) != 0 )        8               perror( "Error deleting file" );        9           else       10               printf( "File successfully deleted\n" );       11     }       12       13     printf( "Process existing...\n" );       14     exit(0);       15 }       16       17 int main() {       18     (void) signal( SIGINT, cleanTask );       19     FILE* tmp = fopen ( "/tmp/temp.lock", "w" );       20     while(1) {       21         printf( "Process running happily\n" );       22         sleep(1);       23     }       24       25     if( tmp )       26         remove( "/tmp/temp.lock" );       27 }  運行程序:  [root@machine ~]# ./bindSignal   Process running happily   Process running happily   Process running happily                       ( 注釋:此時,用戶輸入 control-C)   Got the signal, deleting the tmp file      ( 注釋:接收到信號后,cleanTask 被調用 )   File successfully deleted                    ( 注釋:cleanTask 刪除臨時文件 )   Process existing...                           ( 注釋:進程退出 )  

回頁首

第二類:編程錯誤導致進程運行時異常退出

相比于第一類情況,第二類情況在軟件開發過程中是常客,是編程錯誤,進程運行過程中非法操作引起的。

操作系統和計算機硬件為應用程序的運行提供了硬件平臺和軟件支持,為應用程序提供了平臺虛擬化,使進程運行在自己的進程空間。在進程看來,它自身獨占整臺系統,任何其它進程都無法干預,也無法進入它的進程空間。

但是操作系統和計算機硬件又約束每個進程的行為,使進程運行在用戶態空間,控制權限,確保進程不會破壞系統資源,不會干涉進入其它進程的空間,確保進程合法訪問內存。當進程嘗試突破禁區做非法操作時,系統會立刻覺察,并且終止進程運行。

所以,第二類情況導致的進程異常退出,起源于進程自身的編程錯誤,錯誤的編碼執行非法操作,操作系統和硬件制止它的非法操作,并且讓進程異常退出。

在實現上,操作系統和計算機硬件通過異常和異常處理函數來阻止進程做非法操作。

異常和異常處理函數

當進程執行非法操作時,計算機會拋出處理器異常,系統執行異常處理函數以響應處理器異常,異常處理函數往往會終止進程運行。

廣義的異常包括軟中斷 (soft interrupts) 和外設中斷 (I/O interrupts) 。外設中斷是系統外圍設備發送給處理器的中斷,它通知處理器 I/O 操作的狀態,這種異常是外設的異步異常,與具體進程無關,所以它們不會造成進程的異常退出。本文討論的異常是指 soft interrupts,是進程非法操作所導致的處理器異常,這類異常是進程執行非法操作所產生的同步異常,比如內存保護異常,除 0 異常,缺頁異常等等。

處理器異常有很多種,系統為每個異常分配異常號,每個異常有相對應的異常處理函數。以 x86 處理器為例,除 0 操作產生 DEE 異常 (Divide Error Exception),異常號是 0;內存非法訪問產生 GPF 異常 (General Protection Fault),異常號是 13,而缺頁 (page fault) 異常的異常號是 14。當異常出現時,處理器掛起當前進程,讀取異常號,然后執行相應的異常處理函數。如果異常是可修復,比如內存缺頁異常,異常處理函數會修復系統錯誤狀態,清除異常,然后重新執行一遍被中斷的指令,進程繼續運行;如果異常無法修復,比如內存非法訪問或者除 0 操作,異常處理函數會終止進程運行,如圖 2:


圖 2. 異常處理函數終止進程運行
圖 2. 異常處理函數終止進程運行 

實例以及分析

實例一:內存非法訪問

這類問題中最常見的就是內存非法訪問。內存非法訪問在 UNIX 平臺即 segmentation fault,在 Windows 平臺這類錯誤稱為 Access violation。

內存非法訪問是指:進程在運行時嘗試訪問尚未分配(即,沒有將物理內存映射進入進程虛擬內存空間)的內存,或者進程嘗試向只讀內存區域寫入數據。當進程執行內存非法訪問操作時,內存管理單元 MMU 會產生內存保護異常 GPF(General Protection Fault),異常號是 13。系統會立刻暫停進程的非法操作,并且跳轉到 GPF 的異常處理程序,終止進程運行。

這種編程錯誤在編譯階段編譯器不會報錯,是運行時出現的錯誤。清單 3 是內存非法訪問的一個簡單實例,進程在執行第 5 行代碼時執行非法內存訪問,異常處理函數終止進程運行。


清單 3. 內存非法訪問實例 demoSegfault.c
				       1 #include<stdio.h>        2 int main()        3 {        4      char* str = "hello";        5      str[0] = 'H';        6      return 0;        7 }  編譯并運行:  [root@machine ~]# gcc demoSegfault.c -o demoSegfault   [root@machine ~]# ./demoSegfault   Segmentation fault (core dumped)   [root@machine ~]# gdb demoSegfault core.24065   ( 已省略不相干文本 )   Core was generated by `./demoSegfault'.   Program terminated with signal 11, Segmentation fault.  

分析:實例中,字符串 str 是存儲在內存只讀區的字符串常量,而第 5 行代碼嘗試更改只讀區的字符,所以這是內存非法操作。

進程從開始執行到異常退出經歷如下幾步:

  1. 進程執行第 5 行代碼,嘗試修改只讀內存區的字符;
  2. 內存管理單元 MMU 檢查到這是非法內存操作,產生保護內存異常 GPF,異常號 13;
  3. 處理器立刻暫停進程運行,跳轉到 GPF 的異常處理函數,異常處理函數終止進程運行;
  4. 進程 segmentation fault,并且產生 core dump 文件。GDB 調試結果顯示,進程異常退出的原因是 segmentation fault。

實例二:除 0 操作

實例二是除 0 操作,軟件開發中也會引入這樣的錯誤。當進程執行除 0 操作時,處理器上的浮點單元 FPU(Floating-point unit) 會產生 DEE 除 0 異常 (Divide Error Exception),異常號是 0。


清單 4. 除 0 操作 divide0.c
				       1 #include <stdio.h>        2        3 int main()        4 {        5     int a = 1, b = 0, c;        6     printf( "Start running\n" );        7     c = a/b ;        8     printf( "About to quit\n" );        9 }  編譯并運行:  [root@machine ~]# gcc -o divide0 divide0.c   [root@machine ~]# ./divide0 &   [1] 1229   [root@machine ~]# Start running   [1]+  Floating point exception(core dumped) ./divide0   [root@xbng103 ~]# gdb divide0 /corefiles/core.1229   ( 已省略不相干文本 )   Core was generated by `./divide0'.   Program terminated with signal 8, Arithmetic exception.  

分析:實例中,代碼第 7 行會執行除 0 操作,導致異常出現,異常處理程序終止進程運行,并且輸出錯誤提示:Floating point exception。

異常處理函數內幕

異常處理函數在實現上,是通過向掛起進程發送信號,進而通過信號的默認信號處理程序終止進程運行,所以異常處理函數是“間接”終止進程運行。詳細過程如下:

  1. 進程執行非法指令或執行錯誤操作;
  2. 非法操作導致處理器異常產生;
  3. 系統掛起進程,讀取異常號并且跳轉到相應的異常處理函數;
    1. 異常處理函數首先查看異常是否可以恢復。如果無法恢復異常,異常處理函數向進程發送信號。發送的信號根據異常類型而定,比如內存保護異常 GPF 相對應的信號是 SIGSEGV,而除 0 異常 DEE 相對應的信號是 SIGFPE;
    2. 異常處理函數調用內核函數 issig() 和 psig() 來接收和處理信號。內核函數 psig() 執行默認信號處理程序,終止進程運行;
  4. 進程異常退出。

在此基礎上,我們可以把圖 2 進一步細化如下:


圖 3. 異常處理函數終止進程運行(細化)
圖 3. 異常處理函數終止進程運行(細化) 

異常處理函數執行時會檢查異常號,然后根據異常類型發送相應的信號。

再來看一下實例一(代碼清單 3)的運行結果:

 [root@machine ~]# ./demoSegfault   Segmentation fault (core dumped)   [root@machine ~]# gdb demoSegfault core.24065   ( 已省略不相干文本 )   Core was generated by `./demoSegfault'.   Program terminated with signal 11, Segmentation fault.  

運行結果顯示進程接收到信號 11 后異常退出,在 signal.h 的定義里,11 就是 SIGSEGV。MMU 產生內存保護異常 GPF(異常號 13)時,異常處理程序發送相應信號 SIGSEGV,SIGSEGV 的默認信號處理程序終止進程運行。

再來看實例二(代碼清單 4)的運行結果

 [root@machine ~]# ./divide0 &   [1] 1229   [root@machine ~]# Start running   [1]+  Floating point exception(core dumped) ./divide0   [root@xbng103 ~]# gdb divide0 /corefiles/core.1229   ( 已省略不相干文本 )   Core was generated by `./divide0'.   Program terminated with signal 8, Arithmetic exception.  

分析結果顯示進程接收到信號 8 后異常退出,在 signal.h 的定義里,8 就是信號 SIGFPE。除 0 操作產生異常(異常號 0),異常處理程序發送相應信號 SIGFPE 給掛起進程,SIGFPE 的默認信號處理程序終止進程運行。

回頁首

“信號”是進程異常退出的直接原因

信號與進程異常退出有著緊密的關系:第一類情況是因為外部環境向進程發送信號,這種情況下發送的信號是異步信號,信號的到來與進程的運行是異步的;第二類情況是進程非法操作觸發處理器異常,然后異常處理函數在內核態向進程發送信號,這種情況下發送的信號是同步信號,信號的到來與進程的運行是同步的。這兩種情況都有信號產生,并且最終都是信號處理程序終止進程運行。它們的區別是信號產生的信號源不同,前者是外部信號源產生異步信號,后者是進程自身作為信號源產生同步信號。

所以,信號是進程異常退出的直接原因。當進程異常退出時,進程必然接收到了信號。

回頁首

避免和調試進程異常退出

建議

軟件開發過程中,我們應當避免進程異常退出,針對導致進程異常退出的這兩類問題,對軟件開發者的幾點建議:

  1. 通常情況無需屏蔽外部信號。信號作為進程間的一種通信方式,異步信號到來意味著外部要求進程的退出;
  2. 綁定自定義信號處理程序做清理工作,當外部信號到來時,確保進程異常退出前,自定義信號處理程序被調用做清理工作,比如刪除創建的臨時文件。
  3. 針對第二類情況,編程過程中確保進程不要做非法操作,尤其是在訪問內存時,確保內存已經分配給進程(映射入進程虛擬地址空間),不要向只讀區寫入數據。

問題調試和定位

進程異常退出時,操作系統會產生 core dump 文件,cored ump 文件是進程異常退出前內存狀態的快照,運行 GDB 分析 core dump 文件可以幫助調試和定位問題。

1) 首先,分析 core dump 查看導致進程異常退出的具體信號和退出原因。

使用 GDB 調試實例一(代碼清單 3)的分析結果如下:

 [root@machine ~]# gdb demoSegfault core.24065   ( 已省略不相干文本 )   Core was generated by `./demoSegfault'.   Program terminated with signal 11, Segmentation fault.  

分析結果顯示,終止進程運行的信號是 11,SIGSEGV,原因是內存非法訪問。

2) 然后,定位錯誤代碼。

在 GDB 分析 core dump 時,輸入“bt”指令打印進程退出時的代碼調用鏈,即 backtrace,就可以定位到錯誤代碼。

用 gcc 編譯程序時加入參數 -g 可以生成符號文件,幫助調試。

重新編譯、執行實例一,并且分析 core dump 文件,定位錯誤代碼:

 [root@machine ~]# gcc -o demoSegfault demoSegfault.c -g   [root@machine ~]# ./demoSegfault  &   [1] 28066   [1]+  Segmentation fault      (core dumped) ./demoSegfault   [root@machine ~]# gdb demoSegfault /corefiles/core.28066   ( 已省略不相干文本 )   Core was generated by `./demoSegfault'.   Program terminated with signal 11, Segmentation fault.   #0  0x0804835a in main () at demoSegfault.c:5   5               str[0] = 'H';   (gdb) bt   #0  0x0804835a in main () at demoSegfault.c:5   (gdb)  

在加了參數 -g 編譯后,我們可以用 gdb 解析出更多的信息幫助我們調試。在輸入“bt”后,GDB 輸出提示錯誤出現在第 5 行。

3) 最后,在定位到錯誤代碼行后,就可以很快知道根本原因,并且修改錯誤代碼。

posted on 2013-09-30 16:50 C++技術中心 閱讀(1718) 評論(0)  編輯 收藏 引用 所屬分類: Linux 編程
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲精品久久| 亚洲看片一区| 在线亚洲一区| 亚洲高清视频一区| 欧美日韩中文字幕日韩欧美| 亚洲欧美999| 亚洲欧洲一区二区天堂久久| 久久久亚洲国产天美传媒修理工| 亚洲男人的天堂在线观看| 狠狠色丁香婷婷综合影院 | 亚洲国产美女| 国内外成人免费激情在线视频| 午夜在线观看欧美| 久久久久久久一区二区| 性欧美办公室18xxxxhd| 久久久国产精彩视频美女艺术照福利| 亚洲精品自在在线观看| 亚洲美女黄色片| 亚洲欧美成人在线| 一区二区欧美激情| 免费日韩一区二区| 欧美三级在线| 精品动漫3d一区二区三区免费| 一区二区在线不卡| 亚洲午夜性刺激影院| 久久精品久久99精品久久| 久热精品在线| 亚洲无玛一区| 久久久久久久久久久成人| 老司机免费视频久久| 欧美吻胸吃奶大尺度电影| 国产精品久久久久久久久免费樱桃 | 亚洲黄色三级| 亚洲蜜桃精久久久久久久| 亚洲女人天堂av| 久久久久.com| 国产精品久久久一本精品| 国外视频精品毛片| 欧美一区二区三区四区在线观看| 美国十次成人| 亚洲精品视频在线播放| 欧美亚洲视频在线观看| 久久成人羞羞网站| 欧美综合激情网| 国产日韩欧美二区| 欧美精品国产一区二区| 亚洲一级黄色| 久久久久久久久久久久久9999| 国产亚洲精品久久久久动| 久久精品国产一区二区三| 亚洲激情婷婷| 久久久夜色精品亚洲| 亚洲欧美欧美一区二区三区| 国产精品剧情在线亚洲| 亚洲素人在线| 在线观看欧美视频| 欧美成人有码| 欧美成人a视频| 在线看国产日韩| 久久综合伊人77777蜜臀| 一本一本久久a久久精品综合麻豆| 亚洲午夜女主播在线直播| 国产午夜亚洲精品不卡| 国产情侣一区| 一区二区三区在线观看国产| 欧美成年人在线观看| 欧美成人中文字幕| 日韩亚洲在线| 久久精品视频在线播放| 一本不卡影院| 欧美中文字幕在线| 亚洲福利视频网站| 亚洲专区国产精品| 国产日韩av一区二区| 欧美电影免费观看网站| 欧美日韩精品在线| 麻豆乱码国产一区二区三区| 欧美高清在线播放| 美女尤物久久精品| 国产精品视频yy9299一区| 亚洲福利视频三区| 国产日韩欧美中文| 香蕉成人啪国产精品视频综合网| 亚洲欧美精品一区| 亚洲国产片色| 羞羞色国产精品| 亚洲图片在区色| 亚洲最新色图| 欧美mv日韩mv国产网站| 亚洲国产欧美久久| 欧美精品在线一区| 午夜在线不卡| 久久久www| 亚洲国产欧美一区二区三区久久 | 亚洲午夜黄色| 欧美一区二区三区的| **网站欧美大片在线观看| 久久一区二区视频| 亚洲综合不卡| 亚洲少妇中出一区| 久久久蜜桃精品| 亚洲午夜小视频| 国产精品天天摸av网| 午夜欧美不卡精品aaaaa| 老鸭窝亚洲一区二区三区| 亚洲乱码国产乱码精品精98午夜| 欧美精品一区二区在线观看| 欧美一区二区三区四区高清| 久久国产主播精品| 一区二区三区精品视频在线观看| 欧美无乱码久久久免费午夜一区 | 欧美在线观看你懂的| 亚洲欧美成aⅴ人在线观看| 久久精品国产99| 麻豆成人在线观看| 黄色精品网站| 欧美日韩在线播放一区| 午夜精品理论片| 亚洲国产一区二区视频| 午夜亚洲视频| 一本大道久久a久久综合婷婷| 欧美日韩国产区一| 欧美一级视频一区二区| 亚洲精品乱码久久久久| 久久综合伊人77777蜜臀| 亚洲图片欧洲图片av| 亚洲精品日韩久久| 最近看过的日韩成人| 国产人成精品一区二区三| 欧美午夜电影完整版| 欧美日韩一级片在线观看| 一区二区三区视频在线看| 91久久线看在观草草青青| 欧美激情国产高清| 欧美激情一区二区三区在线视频| 久久色在线观看| 欧美国产精品va在线观看| 欧美成人午夜激情| 亚洲国产日韩欧美在线99| 亚洲精品一二三| 亚洲一区二区网站| 亚洲婷婷免费| 久久亚洲不卡| 欧美全黄视频| 国产嫩草一区二区三区在线观看| 国产精品一国产精品k频道56| 国产精品无码永久免费888| 亚洲激情电影中文字幕| 久久免费视频在线观看| 蜜桃精品久久久久久久免费影院| 欧美成人在线免费观看| 亚洲精品国精品久久99热| 久久人人精品| 99精品欧美| 久久蜜桃资源一区二区老牛| 亚欧成人在线| 欧美激情a∨在线视频播放| 久久精品观看| 激情欧美一区| 麻豆精品在线播放| 亚洲片在线资源| 一道本一区二区| 国产精品久久夜| 久久九九国产精品| 亚洲国产婷婷综合在线精品| 亚洲视频综合在线| 国产视频精品xxxx| 暖暖成人免费视频| 亚洲性感美女99在线| 久久婷婷综合激情| 日韩视频在线一区| 国产伦精品一区二区三区免费迷| 欧美一区二区福利在线| 欧美国产激情| 亚洲先锋成人| 尤物yw午夜国产精品视频| 欧美日韩一区二区三区视频| 性伦欧美刺激片在线观看| 欧美国产一区二区| 欧美一区二区高清| 最新国产乱人伦偷精品免费网站 | 欧美激情视频给我| 亚洲一区二区三区涩| 精品成人一区| 国产精品午夜在线| 欧美大尺度在线观看| 欧美一区深夜视频| 亚洲美女在线看| 欧美xx视频| 久久精品首页| 亚洲一级片在线看| 亚洲精品免费在线| 在线精品亚洲| 韩日精品视频| 国产私拍一区| 国产日韩欧美在线看| 国产精品乱码久久久久久| 欧美久久九九| 欧美国产综合视频| 免费不卡在线视频|