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

jake1036

linux0.11相關進程數據結構

1 進程結構
    union task_union{
     struct task_struct task ;
     char stack[PAGE_SIZE]  ;
  }
  這實際上是一個內存頁,頁的底部是進程控制塊結構。其余部分是作為進程的內核態堆棧使用。
  

Task_struct

內核態堆棧

page

Page+4K



2 task 數組

struct task_struct * task[NR_TASKS] = {&(init_task.task), };

這個數組中存儲的是task_struct 結構的指針,但是實際上數組中的每一項都指著一塊內存頁。


3 任務段數據 
  

struct tss_struct {

       long back_link;      /* 16 high bits zero */

       long esp0;

       long ss0;         /* 16 high bits zero */

       long esp1;

       long ss1;         /* 16 high bits zero */

       long esp2;

       long ss2;         /* 16 high bits zero */

       long cr3;

       long eip;

       long eflags;

       long eax,ecx,edx,ebx;

       long esp;

       long ebp;

       long esi;

       long edi;

       long es;          /* 16 high bits zero */

       long cs;          /* 16 high bits zero */

       long ss;           /* 16 high bits zero */

       long ds;          /* 16 high bits zero */

       long fs;           /* 16 high bits zero */

       long gs;          /* 16 high bits zero */

       long ldt;         /* 16 high bits zero */

       long trace_bitmap;  /* bits: trace 0, bitmap 16-31 */

       struct i387_struct i387;        

};


4  進程控制塊
    

struct task_struct {

/*----------------------- these are hardcoded - don't touch -----------------------*/

       long state;       // 進程運行狀態(-1不可運行,0可運行,>0以停止)

       long counter;  // 任務運行時間片,遞減到0是說明時間片用完

       long priority;  // 任務運行優先數,剛開始是counterpriority

       long signal;     // 任務的信號位圖,信號值=偏移+1

       struct sigaction sigaction[32];       //信號執行屬性結構,對應信號將要執行的操作和標志信息

       long blocked;  // 信號屏蔽碼

/*----------------------------------- various fields--------------------------------- */

       int exit_code;  // 任務退出碼,當任務結束時其父進程會讀取

       unsigned long start_code,end_code,end_data,brk,start_stack;

              // start_code   代碼段起始的線性地址

              // end_code     代碼段長度

              // end_data      代碼段長度+數據段長度

              // brk             代碼段長度+數據段長度+bss段長度

              // start_stack   堆棧段起始線性地址

       long pid,father,pgrp,session,leader;      

              // pid       進程號

              // father   父進程號

              // pgrp     父進程組號

              // session 會話號

              // leader 會話首領

       unsigned short uid,euid,suid;

              // uid       用戶標id

              // euid     有效用戶id

              // suid     保存的用戶id

       unsigned short gid,egid,sgid;

              // gid       id

              // egid     有效組id

// sgid     保存組id

       long alarm;     // 報警定時值

       long utime,stime,cutime,cstime,start_time;

              // utime   用戶態運行時間

              // stime    內核態運行時間

              // cutime  子進程用戶態運行時間

              // cstime  子進程內核態運行時間

              // start_time    進程開始運行時刻

       unsigned short used_math;     // 標志,是否使用了387協處理器

/* ----------------------------------file system info-------------------------------- */

       int tty;            // 進程使用tty的子設備號,-1表示沒有使用

       unsigned short umask;    //文件創建屬性屏蔽碼

       struct m_inode * pwd;   // 當前工作目錄的i節點

       struct m_inode * root;    // 根目錄的i節點

       struct m_inode * executable;  // 可執行文件的i節點

       unsigned long close_on_exec; // 執行時關閉文件句柄位圖標志

       struct file * filp[NR_OPEN]; // 進程使用的文件

/*------------------ ldt for this task 0 - zero 1 - cs 2 - ds&ss -------------------*/

       struct desc_struct ldt[3];        // 本任務的ldt表,0-空,1-代碼段,2-數據和堆棧段

/* ---------------------------------tss for this task ---------------------------------*/

       struct tss_struct tss;        // 本任務的tss

};


 5   linux進程結構
  
      (1)  在linux中gdt中的每一項,都有兩個表項,一個是ldt描述符,另一個是tss描述符。
      (2)  在task數組中占有一項,每一項是一個物理頁面,物理內存頁面底端是進程控制塊,內存頁面的其余部分是內核態堆棧。
      (3)  task數組中的表項和gdt中的表項是一一對應的。 對于一個在task數組中的任務項是nr的任務來說,它的tss描述符在gdt中描述符
            的位置是,gdtr + 3*8 + 16 * nr ,ldt描述符在gdt中的描述符的位置是 gdtr + 3 * 8 + 16 * nr + 8 。
      (4) 對應于表項為nr的進程,它對應的頁目錄項是16 * nr --------16 * (nr + 1) 。
     



6 進程0
    進程0是一個特殊的進程,它是所有進程的祖先進程,所有其他的進程都是復制進程0或者其后代進程產生的。 但是進程0不是。
    下面主要講一下 進程0的創建順序:
    (1) 進程控制塊和頁目錄頁表的手動創建
                   
     以下就是一個任務的初始過程
#define INIT_TASK \
/* state etc */    0,15,15, \    
/* signals */    0,{{},},0, \
/* ec,brk */    0,0,0,0,0,0, \
/* pid etc.. */    0,-1,0,0,0, \
/* uid etc */    0,0,0,0,0,0, \
/* alarm */    0,0,0,0,0,0, \
/* math */    0, \
/* fs info */    -1,0022,NULL,NULL,NULL,0, \
/* filp */    {NULL,}, \
    
{ \
        
{0,0}, \                // ldt第0項是空
/* ldt */    {0x9f,0xc0fa00}, \        //代碼段長640K,基地0,G=1,D=1,DPL=3,P=1,TYPE=0x0a
        {0x9f,0xc0f200}, \        //數據段長640K,基地0,G=1, D=1, DPL=3,P=1, TYPE=0x02
    }
, \
/*tss*/    {0,PAGE_SIZE+(long)&init_task,0x10,0,0,0,0,(long)&pg_dir,\
        
// esp0 = PAGE_SIZE+(long)&init_task    內核態堆棧指針初始化為頁面最后
        
// ss0 = 0x10    內核態堆棧的段選擇符,指向系統數據段描述符,進程0的進程控制
        
//            塊和內核態堆棧都在system模塊中
        
// cr3 = (long)&pg_dir 頁目錄表,其實linux0.11所有進程共享一個頁目錄表
     0,0,0,0,0,0,0,0, \
     
0,0,0x17,0x17,0x17,0x17,0x17,0x17, \
     _LDT(
0),0x80000000, \    // ldt表選擇符指向gdt中的LDT0處
        {} \
    }
, \
}


  
  進程0的數據段基址為0,段限長為640KB ,代碼段基址為0,段限長為640KB。任務0的數據段和代碼段 和系統的代碼段和數據段是重合的。
  進程0的內核態堆棧和進程控制塊都是位于系統模塊內。
 
(2)在main模塊中調用了,sched_init()函數加載了 進程0的進程0tss段描述符,ldt段描述符,并且加載TR寄存器,使它指向進程0tss段,這時候
         進程0才完成了啟動。
   
    
/*****************************************************************************/
/* 功能:    1.    初始化task數組和GDT(包括設置進程1的LDT和TSS)            */
/*            2.    加載TR和IDTR寄存器                                        */
/*            3.    設置時鐘中斷門和系統調用中斷門                                */
/* 參數:    (無)                                                            */
/* 返回:    (無)                                                            */
/*****************************************************************************/
void sched_init(void)
{
    
int i;
    
struct desc_struct * p;

    
if (sizeof(struct sigaction) != 16)
        panic(
"Struct sigaction MUST be 16 bytes");
// 在gdt中設置進程0的tss段描述符
    set_tss_desc(gdt+FIRST_TSS_ENTRY,&(init_task.task.tss));
// 在gdt中設置進程0的ldt段描述符
    set_ldt_desc(gdt+FIRST_LDT_ENTRY,&(init_task.task.ldt));
// 下面的循環把gdt和task中其他的項清空
    p = gdt+2+FIRST_TSS_ENTRY;
    
for(i=1;i<NR_TASKS;i++{
        task[i] 
= NULL;
        p
->a=p->b=0;
        p
++;
        p
->a=p->b=0;
        p
++;
    }

/* Clear NT, so that we won't have troubles with that later on */
    __asm__(
"pushfl ; andl $0xffffbfff,(%esp) ; popfl");
    ltr(
0);    // 把進程0的tss段加載到TR寄存器
    lldt(0);    // 把進程0的ldt段加載到IDTR寄存器。
            
// 這是將gdt中進程0的ldt描述符對應的選擇符加載到TR中。CPU將
            
// 選擇符加載到可見部分,將tss的基地址和段長等加載到不可見部分。
            
// TR寄存器只在這里明確加載一次,以后新任務ldt的加載是CPU根據
            
// TSS段中LDT字段自動加載。
// 初始化8253定時器
    outb_p(0x36,0x43);        /* binary, mode 3, LSB/MSB, ch 0 */
    outb_p(LATCH 
& 0xff , 0x40);    /* LSB */
    outb(LATCH 
>> 8 , 0x40);    /* MSB */
    set_intr_gate(
0x20,&timer_interrupt);        // 設置時鐘中斷門
    outb(inb_p(0x21)&~0x01,0x21);
    set_system_gate(
0x80,&system_call);        // 設置系統調用中斷門
}






    (3)切換回用戶態。
    
// 把進程0從內核態切換到用戶態去執行,使用的方法是模擬中斷調用返回
// 利用指令iret完成特權級的轉變。
#define move_to_user_mode() \
__asm__ (
"movl %%esp,%%eax\n\t" \        // 當前堆棧指針保存到eax中
"pushl $0x17\n\t" \    // 當前堆棧段選擇符0x17入棧,它指向進程0的數據段描述符// 因為進程0的代碼段、數據段、內核代碼段、數據段4者重
// 合,所以它指向的仍然是內核模塊區域。
    "pushl %%eax\n\t" \    // 把當前堆棧指針入棧。這樣模擬外層堆棧的SS:ESP。
                        
// 由于進程0數據段選擇符0x17對應的還是內核模塊,和
// 內核數據段選擇符0x10的差別僅在與對應描述符的dpl和
// 本身rpl的不同,所以外層堆棧指針指向的還是原來的堆棧
// 即user_stack
    "pushfl\n\t" \            // eflags入棧
    "pushl $0x0f\n\t" \        // 進程0代碼段選擇符入棧,模擬返回的CS
    "pushl $1f\n\t" \        // 下面標號1的偏移地址入棧,模擬返回的EIP
                        
// 也是由于4段重合,所以這里返回的CS對應的段的基地址與
                        
// 內核代碼段基地址一樣,都是0,故將返回的CS:EIP就是下
                        
// 面標號1處。
    "iret\n" \                // 中斷返回。由于當前CPL=0,將返回的CS的RPL=3,所以
                        
// 不僅僅要改變CS,EIP,還要發生堆棧切換(但實際上堆棧
// 還是user_stack),同時CPL變成3。
    "1:\tmovl $0x17,%%eax\n\t" \    // 把數據段寄存器的值設為進程0的數據段
    "movw %%ax,%%ds\n\t" \
    
"movw %%ax,%%es\n\t" \
    
"movw %%ax,%%fs\n\t" \
    
"movw %%ax,%%gs" \
    :::
"ax")
 


6 用fork創建進程
   除了進程0,所有其他的進程都是由fork()系統調用創建的,子進程是通過復制父進程的數據和代碼而產生的。
   創建結束之后,子進程與父進程的代碼和數據共享,但是子進程有自己的進程控制塊,內核堆棧和頁表。
 
  一個進程需要以下三中數據結構
   (1) 進程控制塊 task__struct 。
   (2) gdt中的tss 和ldt描述符。
   (3)頁目錄項和頁表項。
    所以fork系統調用的任務就是創建進程的上述三個部分。
    sys_fork()函數分兩步實現,第一步 首先調用,find_empty_process() 函數,第二步調用 copy_process()函數,復制進程。

  
_sys_fork:
// 第一步,調用find_empty_process()函數,找task[]中的空閑項。
// 找到后數組下標放在eax中。如果沒找到直接跳轉到ret指令。
    call _find_empty_process
    testl 
%eax,%eax
    js 1f
    push 
%gs        // 中斷時沒有入棧的寄存器入棧,
// 作為copy_process() 函數的參數
    pushl %esi
    pushl 
%edi
    pushl 
%ebp
    pushl 
%eax
 
// 第二步,調用copy_process() 函數復制進程。
    call _copy_process    
    addl $
20,%esp
1:    ret


  內存復制函數
   
copy_mem

/*****************************************************************************/
/*    功能:設置新進程的LDT項(數據段描述符和代碼段描述符)中的基地址部分     */
/*          并且復制父進程(也就是當前進程)的頁目錄和頁表,                      */
/*          實現父子進程數據代碼共享                                              */
/*    參數:    nr    新進程任務數組下標                                             */
/*            p    新進程的進程控制塊                                             */
/*    返回:    0 (成功),    -ENOMEM(出錯)                                     */
/*****************************************************************************/

int copy_mem(int nr,struct task_struct * p)
{
    unsigned 
long old_data_base,new_data_base,data_limit;
    unsigned 
long old_code_base,new_code_base,code_limit;

    code_limit
=get_limit(0x0f);    // 取當前進程代碼段長度
    data_limit=get_limit(0x17);    // 取當前進程數據段長度
    old_code_base = get_base(current->ldt[1]);    // 取當前進程代碼段基地址,這是線性地址
    old_data_base = get_base(current->ldt[2]);    // 取當前進程數據段基地址,這是線性地址
    
// 0.11進程代碼段和數據段基地址必須重合
if (old_data_base != old_code_base)
        panic(
"We don't support separate I&D");
    
//0.11中數據段代碼段的基地址是重合的,都是nr*64M(nr是task[]數組下標),所以
    
//數據段的長度肯定大于代碼段長度。而且 copy_page_tables()傳入的是data_limit,這
    
// 把代碼和數據都包含進去了。
    if (data_limit < code_limit)
        panic(
"Bad data_limit");
    
// 新進程的代碼段基地址 = 數據段基地址 = 64M*nr
    new_data_base = new_code_base = nr * 0x4000000;
    
// 設置進程的起始線性地址
    p->start_code = new_code_base;
    
// 設置新進程的ldt項。在copy_process()中完全復制父進程的ldt,所以
    
// 只需重新設置ldt的基地址字段,其他字段和父進程一樣
    set_base(p->ldt[1],new_code_base);
    set_base(p
->ldt[2],new_data_base);
    
// 把線性地址old_data_base處開始,一共data_limit個字節的內存對應的頁目錄、
// 頁表復制到線性地址new_data_base。這里僅僅復制相關的頁目錄和頁表,使它們
// 指向同一個物理頁面,實現父子進程數據代碼共享。
    if (copy_page_tables(old_data_base,new_data_base,data_limit)) {
        free_page_tables(new_data_base,data_limit);
        
return -ENOMEM;
    }

    
return 0;
}



復制進程


/*****************************************************************************/
/*    功能:復制進程,把當前進程current復制到task[nr]                             */
/*    參數:當前進程(current)內核堆棧的所有內容                                 */
/*          當前進程內核堆棧保存了所有寄存器的值,在程序中要把這些寄存器的值     */
/*          全部復制給子進程,從而給子進程創造和父進程一樣的運行環境             */
/*    返回:子進程pid                                                             */
/*****************************************************************************/
int copy_process(int nr,long ebp,long edi,long esi,long gs,long none,
        
long ebx,long ecx,long edx,
        
long fs,long es,long ds,
        
long eip,long cs,long eflags,long esp,long ss)
{
    
struct task_struct *p;
    
int i;
    
struct file *f;
// 在主內存區申請一頁新的內存,用來放置子進程的task_struct和內核堆棧
// get_free_page()返回的是物理地址
    p = (struct task_struct *) get_free_page();
    
if (!p)
        
return -EAGAIN;
// 設置task數組中相關項
    task[nr] = p;
// 下面的賦值語句僅僅把父基礎的task_struct部分全部復制給子進程
// 注意:僅僅復制task_struct部分,內核堆棧不復制,因此子程序的內核堆棧
//          是空的,這也是我們希望的
    *= *current;    /* NOTE! this doesn't copy the supervisor stack */
// 下面的很多賦值語句修改子進程的task_struct中若干字段
// 這些字段跟父進程是有差別的
    p->state = TASK_UNINTERRUPTIBLE;    //子進程設為不可中斷狀態
    p->pid = last_pid;            // 設置子進程pid
    p->father = current->pid;    // 把當前進程pid舍為子進程的father
    p->counter = p->priority;    // 繼承父親的優先級
    p->signal = 0;
    p
->alarm = 0;
    p
->leader = 0;        /* process leadership doesn't inherit */
    p
->utime = p->stime = 0;
    p
->cutime = p->cstime = 0;
    p
->start_time = jiffies;    // 子進程開始時間
    p->tss.back_link = 0;
// 子進程的內核堆棧指針設置為task_struct所在頁面的最高端
    p->tss.esp0 = PAGE_SIZE + (long) p;    
// 子進程的內核堆棧選擇符為0x10,指向GDT中系統數據段。
// 注意 雖然子進程的內核堆棧位于內核system模塊外,在主內存區,但是因為系統數據段
//        基地址為0,限長為16M,函概了所有物理內存,故子進程內核堆棧也位于系統數
//        段內。esp0要的是段內偏移,也是因為系統數據段基地址為0,物理地址
//        PAGE_SIZE + (long) p 也是段內偏移。
p->tss.ss0 = 0x10;
// 把父進程系統調用返回地址賦給子進程當前運行的eip。這樣當子進程被調度程序選中
// 后他從fork返回地址處開始執行。
    p->tss.eip = eip;
    p
->tss.eflags = eflags;
// eax是函數返回值存放的地方,把子進程的eax設置為0,這樣fork在子進程中返回的是0。
// 注意 子進程并沒有執行fork()函數,子進程的系統堆棧沒有進行過操作,當然不會有像
//        父進程那樣的fork函數調用。但是當子進程開始運行時,就好像它從fork中返回。
    p->tss.eax = 0;        
    p
->tss.ecx = ecx;
    p
->tss.edx = edx;
    p
->tss.ebx = ebx;
    p
->tss.esp = esp;    // 用戶堆棧指針和父進程一樣,子進程完全復制父進程的用戶堆棧
    p->tss.ebp = ebp;
    p
->tss.esi = esi;
    p
->tss.edi = edi;
    p
->tss.es = es & 0xffff;
    p
->tss.cs = cs & 0xffff;
    p
->tss.ss = ss & 0xffff;
    p
->tss.ds = ds & 0xffff;
    p
->tss.fs = fs & 0xffff;
    p
->tss.gs = gs & 0xffff;
// 設置子進程的ldt。從這里可以看到,task下標為nr的進程在GDT中的2項一定是
// _LDT(nr)和_TSS(nr)。task[]中的項和GDT中的2項一一對應。
    p->tss.ldt = _LDT(nr);
    p
->tss.trace_bitmap = 0x80000000;
    
if (last_task_used_math == current)
        __asm__(
"clts ; fnsave %0"::"m" (p->tss.i387));
// 在copy_mem函數中設置子進程的代碼段描述符,數據段描述符,并且復制父進程的
// 頁目錄、頁表。實現和父進程代碼數據的共享。
    if (copy_mem(nr,p)) {
        task[nr] 
= NULL;
        free_page((
long) p);
        
return -EAGAIN;
    }

// 子進程繼承父進程打開的文件,所以文件引用數目要加一
    for (i=0; i<NR_OPEN;i++)
        
if (f=p->filp[i])
            f
->f_count++;
// 子進程繼承父進程的工作目錄、根目錄和可執行文件,所以引用數目加一
    if (current->pwd)
        current
->pwd->i_count++;
    
if (current->root)
        current
->root->i_count++;
    
if (current->executable)
        current
->executable->i_count++;
// GDT中對應位置(和nr對應)放入子進程的TSS描述符、LDT描述符
    set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss));
    set_ldt_desc(gdt
+(nr<<1)+FIRST_LDT_ENTRY,&(p->ldt));
// 最后把子進程的狀態設置為可運行狀態,這樣子進程可以被調度
    p->state = TASK_RUNNING;    /* do this last, just in case */
// 父進程返回子進程的pid
    return last_pid;
}




  7 進程的結束
 

進程結束的時候,需要關閉的資源主要有:
  (1)  釋放所有的物理頁面。(子進程自己清除
  (2)  關閉所有打開的文件。(子進程自己清除
  (3)  清除task[] 中的相應的項。(父進程自己清除

  子進程通過exit()清除前面兩個選項,將自身的狀態變為TASK_ZOMBIE 。
  父進程通過調用waitpid() 將task[] 數組清空。


   一個進程的經過exit()之后,物理頁表被清除 , 頁表頁目錄項也被清除,但是它的進程控制塊和內核堆棧還在,,
  此時進程的狀態變為TASK_ZOMBIE ,不會再被處理器處理。不被處理但是還占用著task數組中的一個表項,這
 就成為了僵尸進程。

    子進程調用了exit()函數之后,就通知父進程,父進程調用waitpid() 來清除 task數組中的表項。但是很有可能,
    父進程沒有執行waitpid()操作,情況如下:
   (1) 父進程早于子進程執行exit()函數。
   (2) 子進程僵死,但是父進程沒有調用waitpid()操作。
   (3) 父進程調用了waitpid(),但是因為某種愿意沒有釋放資源。
   
   解決方法:
    如果父進程無法釋放資源,那么就讓進程1來釋放資源。
    當一個父進程早于子進程exit()的時候,它把所有的子進程過繼給父進程。

posted on 2010-11-13 20:50 kahn 閱讀(2223) 評論(0)  編輯 收藏 引用


只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲欧美视频一区| 久久性天堂网| 久久久久久久久久久久久女国产乱 | 欧美jizz19性欧美| 另类图片国产| 亚洲伦理久久| 亚洲在线成人精品| 亚洲第一区在线| 最近中文字幕日韩精品| 久久偷看各类wc女厕嘘嘘偷窃| 在线播放日韩| 亚洲五月六月| 亚洲精品国产欧美| 亚洲综合色视频| 日韩亚洲欧美中文三级| 午夜亚洲福利在线老司机| 亚洲精品久久久久久一区二区| 99在线精品视频| 亚洲欧洲美洲综合色网| 午夜精品久久| 亚洲午夜电影| 欧美激情1区| 毛片av中文字幕一区二区| 欧美午夜a级限制福利片| 欧美精品在欧美一区二区少妇| 久久不射中文字幕| 国产精品护士白丝一区av| 男女精品网站| 国内揄拍国内精品少妇国语| 亚洲欧美www| 欧美伊人久久久久久午夜久久久久| 欧美成人自拍| 99re热这里只有精品视频| 亚洲人体大胆视频| 欧美大片免费观看| 亚洲黄色高清| 亚洲最黄网站| 欧美日韩一本到| 一区二区三区精品国产| 亚欧成人在线| 在线成人av.com| 免费看亚洲片| 亚洲一二三区在线| 免费久久99精品国产自在现线| 亚洲二区在线视频| 欧美日韩亚洲一区二区三区在线观看| 99这里只有精品| 久久久噜噜噜久久中文字幕色伊伊| 国内成人精品一区| 欧美精品18| 久久免费偷拍视频| 亚洲视频观看| 亚洲国产成人精品久久| 亚洲一区二区精品在线| 激情婷婷欧美| 国产亚洲女人久久久久毛片| 欧美激情中文字幕乱码免费| 性xx色xx综合久久久xx| 亚洲理论在线| 亚洲激情视频网| 久久一区亚洲| 亚洲欧美日韩国产综合在线| 久久久久久久精| 欧美日产一区二区三区在线观看| 国产精品99久久久久久久女警| 欧美中文日韩| 亚洲一区二区高清| 亚洲网址在线| 亚洲最新合集| 在线观看一区欧美| 国产亚洲欧美日韩精品| 国产欧美一区二区精品仙草咪| 欧美伦理影院| 久久精品麻豆| 亚洲小说区图片区| 亚洲一区二区三区精品在线| 99精品热6080yy久久| 日韩一级免费观看| 一区二区三区四区国产| 欧美亚洲午夜视频在线观看| 亚洲欧洲av一区二区| 亚洲欧美在线免费| 久久精品一二三| 欧美sm视频| 欧美国产精品一区| 欧美日韩日本网| 国产欧美日韩一区| 亚洲高清在线观看| 亚洲午夜极品| 久久九九国产精品| 亚洲国产成人精品久久| 在线亚洲一区二区| 欧美3dxxxxhd| 国产一区二区三区电影在线观看| 在线播放豆国产99亚洲| 亚洲一区二区在线播放| 麻豆精品网站| 亚洲欧美资源在线| 欧美日韩一区国产| 亚洲电影欧美电影有声小说| 亚洲综合色在线| 在线亚洲一区二区| 欧美三级免费| 欧美成人综合| 国产一区激情| 久久爱www| 夜夜嗨av一区二区三区网页| 麻豆精品在线播放| 国产最新精品精品你懂的| 亚洲欧美中日韩| 一区二区免费看| 欧美日韩一区二区三| 日韩亚洲精品视频| 亚洲日本激情| 欧美日韩国产综合视频在线观看| 亚洲国产mv| 欧美岛国在线观看| 免费日本视频一区| 日韩一级欧洲| 一区二区电影免费观看| 国产精品国产自产拍高清av| 亚洲自拍偷拍网址| 午夜精品久久久久久久99黑人| 国产精品五区| 久久综合99re88久久爱| 久久久噜噜噜久久| 亚洲精品综合| 亚洲一区二区成人在线观看| 国产亚洲免费的视频看| 欧美激情一区二区久久久| 欧美日韩第一区日日骚| 国产精品99久久久久久久久| 亚洲综合色激情五月| 亚洲娇小video精品| 中日韩美女免费视频网址在线观看 | 日韩写真在线| 亚洲一区二区精品| ●精品国产综合乱码久久久久| 亚洲美女免费精品视频在线观看| 欧美日韩亚洲一区二区三区在线| 久久成人精品一区二区三区| 久久免费一区| 欧美一区二区三区婷婷月色 | 亚洲欧美日本国产有色| 亚洲国产欧美日韩| 欧美一区二区三区久久精品 | 中国成人黄色视屏| 久久五月婷婷丁香社区| 欧美一区二区免费观在线| 欧美三级视频在线| 欧美国产日韩精品| 在线观看视频亚洲| 久久久亚洲一区| 久久综合色影院| 一区二区在线视频播放| 久久九九99视频| 久久综合给合| 一区福利视频| 免费av成人在线| 欧美成人午夜激情| 亚洲电影免费观看高清完整版| 久久高清国产| 亚洲黄色小视频| 一区二区三区四区五区精品视频 | 欧美国产在线观看| 亚洲欧洲精品一区| 欧美日韩午夜视频在线观看| 日韩亚洲欧美一区| 欧美一级黄色网| 激情综合网激情| 欧美—级在线免费片| 国产精品五月天| 欧美~级网站不卡| 中国女人久久久| 欧美成人精品不卡视频在线观看| 亚洲啪啪91| 国产日韩成人精品| 欧美v亚洲v综合ⅴ国产v| 中文在线不卡| 亚洲国产成人久久综合| 午夜精品久久久久久久久久久| 国产一区在线看| 欧美婷婷六月丁香综合色| 久久av一区二区| 中文一区字幕| 亚洲看片网站| 亚洲国产综合视频在线观看| 久久久久久网址| 欧美日韩综合一区| 久久久久久久久久久久久9999| 99精品福利视频| 亚洲免费播放| 欧美国产视频一区二区| 久久免费精品视频| 亚洲欧美视频一区| 亚洲一区二区三区视频播放| 亚洲肉体裸体xxxx137| 亚洲欧洲精品天堂一级| 亚洲国产另类 国产精品国产免费| 国产精品日韩久久久|