久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

驅(qū)動實現(xiàn)select機制的步驟

 新用戶8389DdzY 2021-09-22

一,、驅(qū)動實現(xiàn)select機制的步驟

    1,、首先初始化一個等待隊列頭

    2,、在驅(qū)動中實現(xiàn)poll函數(shù),,該函數(shù)只需做兩件事情

        a,、使用poll_wait()函數(shù)將等待隊列添加到poll_table中,。

        b,、返回描述設(shè)備是否可讀或可寫的掩碼,。

    3,、在驅(qū)動的相應(yīng)地方調(diào)用wake_up()函數(shù),,喚醒等待隊列。

    兩點說明:

        a,、等待隊列

            select函數(shù)阻塞的原理,,實際上是通過等待隊列實現(xiàn)的,若對等待隊列不熟悉,,請看我的另一篇文章《等待隊列的簡單使用》,。否則看以下的 “select機制內(nèi)核代碼走讀” 會很吃力。

        b,、掩碼值及含義

            POLLIN

            如果設(shè)備可被不阻塞地讀, 這個位必須設(shè)置.

            POLLRDNORM

            這個位必須設(shè)置, 如果"正常"數(shù)據(jù)可用來讀. 一個可讀的設(shè)備返回( POLLIN|POLLRDNORM ).

            POLLRDBAND

            這個位指示帶外數(shù)據(jù)可用來從設(shè)備中讀取. 當(dāng)前只用在 Linux 內(nèi)核的一個地方( DECnet 代碼 )并且通常對設(shè)備驅(qū)動不可用.

            POLLPRI

            高優(yōu)先級數(shù)據(jù)(帶外)可不阻塞地讀取. 這個位使 select 報告在文件上遇到一個異常情況, 因為 selct 報告帶外數(shù)據(jù)作為一個異常情況.

            POLLHUP

            當(dāng)讀這個設(shè)備的進(jìn)程見到文件尾, 驅(qū)動必須設(shè)置 POLLUP(hang-up). 一個調(diào)用 select 的進(jìn)程被告知設(shè)備是可讀的, 如同 selcet 功能所規(guī)定的.

            POLLERR

            一個錯誤情況已在設(shè)備上發(fā)生. 當(dāng)調(diào)用 poll, 設(shè)備被報告位可讀可寫, 因為讀寫都返回一個錯誤碼而不阻塞.

            POLLOUT

            這個位在返回值中設(shè)置, 如果設(shè)備可被寫入而不阻塞.

            POLLWRNORM

            這個位和 POLLOUT 有相同的含義, 并且有時它確實是相同的數(shù). 一個可寫的設(shè)備返回( POLLOUT|POLLWRNORM).

            POLLWRBAND

            如同 POLLRDBAND , 這個位意思是帶有零優(yōu)先級的數(shù)據(jù)可寫入設(shè)備. 只有 poll 的數(shù)據(jù)報實現(xiàn)使用這個位, 因為一個數(shù)據(jù)報看傳送帶外數(shù)據(jù).

            注:應(yīng)當(dāng)重復(fù)一下 POLLRDBAND POLLWRBAND 僅僅對關(guān)聯(lián)到 socket 的文件描述符有意義: 通常設(shè)備驅(qū)動不使用這些標(biāo)志,!

二、以按鍵驅(qū)動為例

        驅(qū)動代碼button.c

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/types.h>

#include <linux/fcntl.h>

#include <linux/mm.h>

#include <linux/fs.h>

#include <linux/cdev.h>

#include <linux/errno.h>

#include <linux/init.h>

#include <linux/device.h>

#include <linux/init.h>

#include <linux/major.h>

#include <linux/delay.h>

#include <linux/io.h>

#include <asm/uaccess.h>

#include <linux/poll.h>

#include <linux/irq.h>

#include <asm/irq.h>

#include <linux/interrupt.h>

#include <asm/uaccess.h>

#include <linux/platform_device.h>

#include <linux/cdev.h>

#include <linux/miscdevice.h>

#include <linux/sched.h>

#include <linux/gpio.h>

#include <asm/gpio.h>

#define BUTTON_NAME "poll_button"

#define BUTTON_GPIO 140

static int button_major = 0;           

static int button_minor = 0;

static struct cdev button_cdev;                               

static struct class *p_button_class = NULL;

static struct device *p_button_device = NULL;

static struct timer_list button_timer;

static volatile int ev_press = 0;

static volatile char key_value[] = {0};

static int old_value;

static int Button_Irq = 0;

static int flag_interrupt = 1;

static DECLARE_WAIT_QUEUE_HEAD(button_waitq);

static irqreturn_t buttons_interrupt(int irq, void *dev_id)

{

if(flag_interrupt) {

flag_interrupt = 0;

old_value = gpio_get_value(BUTTON_GPIO);

mod_timer(&button_timer,jiffies + HZ/100);    //啟動消抖定時器,,消抖時間10ms

}

return IRQ_RETVAL(IRQ_HANDLED);

}

static void button_timer_handle(unsigned long arg)

{

int tmp_value;

tmp_value = gpio_get_value(BUTTON_GPIO);

if(tmp_value == old_value) {

    key_value[0] = tmp_value;     

ev_press= 1;                                 //有按鍵按下,,喚醒等待隊列

wake_up_interruptible(&button_waitq);

}

    flag_interrupt = 1;        

}

static int button_open(struct inode *inode,struct file *file)

{

    Button_Irq = gpio_to_irq(BUTTON_GPIO);

    enable_irq(Button_Irq);

if(request_irq(Button_Irq, buttons_interrupt, IRQF_TRIGGER_FALLING, "BUTTON_IRQ", NULL) != 0) {

printk("request irq failed !!! \n");

    disable_irq(Button_Irq);

free_irq(Button_Irq, NULL);

return -EBUSY;

}

return 0;

}

static int button_close(struct inode *inode, struct file *file)

{

free_irq(Button_Irq, NULL);

return 0;

}

static int button_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)

{

    unsigned long err;

    if (filp->f_flags & O_NONBLOCK) {        

        /*nothing to do*/

        //如果沒有使用select機制,,并且應(yīng)用程序設(shè)置了非阻塞O_NONBLOCK,那么驅(qū)動這里就不使用等待隊列進(jìn)行等待,。

    } else {

        wait_event_interruptible(button_waitq, ev_press); //如果應(yīng)用層沒有使用select,,直接讀的話,這里會阻塞,,直到按鍵按下,。如果使用select機制,進(jìn)來這里時ev_press為真,,不會阻塞,。

    }

    err = copy_to_user(buff, (const void *)key_value, min(sizeof(key_value), count));

    key_value[0] = 0;

    ev_press = 0;

    return err ? -EFAULT : min(sizeof(key_value), count);

}

static unsigned int button_poll(struct file *file, struct poll_table_struct *wait)

{

unsigned int mask = 0;

    //將等待隊列添加到poll_table

poll_wait(file, &button_waitq, wait);

if(ev_press) {

    //返回描述設(shè)備是否可讀或可寫的掩碼

mask = POLLIN | POLLRDNORM;

}

return mask;

}

static const struct file_operations button_fops = {

.owner = THIS_MODULE,

.open = button_open,

.release = button_close,

.read = button_read,

.poll = button_poll,

//.write = button_write,

//.ioctl = button_ioctl

};

static int button_setup_cdev(struct cdev *cdev, dev_t devno)

{

int ret = 0;

cdev_init(cdev, &button_fops);

cdev->owner = THIS_MODULE;

ret = cdev_add(cdev, devno, 1);

return ret;

}

static int __init button_init(void)

{

int ret;

dev_t devno;

printk("button driver init...\n");

init_timer(&button_timer);

button_timer.function = &button_timer_handle;

if(button_major) {

devno = MKDEV(button_major, button_minor);

ret = register_chrdev_region(devno, 1, BUTTON_NAME);

} else {

ret = alloc_chrdev_region(&devno, button_minor, 1, BUTTON_NAME);

button_major = MAJOR(devno);

}

if(ret < 0) {

printk("get button major failed\n");

return ret;

}

ret = button_setup_cdev(&button_cdev, devno);

if(ret) {

printk("button setup cdev failed, ret = %d\n",ret);

goto cdev_add_fail;

}

p_button_class = class_create(THIS_MODULE, BUTTON_NAME);

ret = IS_ERR(p_button_class);

if(ret) {

printk(KERN_WARNING "button class create failed\n");

goto class_create_fail;

}

p_button_device = device_create(p_button_class, NULL, devno, NULL, BUTTON_NAME);

ret = IS_ERR(p_button_device);

if (ret) {

printk(KERN_WARNING "button device create failed, error code %ld", PTR_ERR(p_button_device));

goto device_create_fail;

}

return 0;

device_create_fail:

class_destroy(p_button_class);

class_create_fail:

cdev_del(&button_cdev);

cdev_add_fail:

unregister_chrdev_region(devno, 1);

return ret;

}

static void __exit button_exit(void)

{

dev_t devno;

printk("button driver exit...\n");

del_timer_sync(&button_timer);

devno = MKDEV(button_major, button_minor);

device_destroy(p_button_class, devno);

class_destroy(p_button_class);

cdev_del(&button_cdev);

unregister_chrdev_region(devno, 1);

}

module_init(button_init);

module_exit(button_exit);

MODULE_AUTHOR("Jimmy");

MODULE_DESCRIPTION("button Driver");

MODULE_LICENSE("GPL");

        驅(qū)動Makefile文件

ifneq ($(KERNELRELEASE),)

obj-m := button.o

else

KERNELDIR ?= /ljm/git_imx6/linux-fsl/src/linux-3-14-28-r0

TARGET_CROSS = arm-none-linux-gnueabi-

PWD := $(shell pwd)

default:

$(MAKE) ARCH=arm CROSS_COMPILE=$(TARGET_CROSS) -C $(KERNELDIR) M=$(PWD) modules

endif

install:

$(MAKE) ARCH=arm CROSS_COMPILE=$(TARGET_CROSS) -C $(KERNELDIR) M=$(PWD) modules_install

clean:

rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions *.symvers *.order

        應(yīng)用程序main.c

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <linux/ioctl.h>

#define DEV_BUTTON "/dev/poll_button"

int main(void)

{

int dev_fd;

int ret;

char read_buf[20] = {-1};

struct timeval rto;

fd_set read_fds;

rto.tv_sec = 10;

rto.tv_usec = 0;

dev_fd = open(DEV_BUTTON, O_RDWR /*| O_NONBLOCK*/);

if ( dev_fd == -1 ) {

printf("open %s failed, ret = %d\n", DEV_BUTTON, dev_fd);

return -1;

}

while(1)

{

rto.tv_sec =10;

rto.tv_usec = 0;

FD_ZERO(&read_fds);

FD_SET(dev_fd, &read_fds);

ret = select(dev_fd+1, &read_fds, NULL, NULL, &rto);

if(ret == -1) {

printf("error\n");

continue;

} else if(ret == 0) {

printf("timeout\n");

continue;

} else {

    if(FD_ISSET(dev_fd, &read_fds)) {

    read(dev_fd, read_buf, 1);

    printf("button pressed, val = %d\n", read_buf[0]);

}

}

}

    printf("clsoe %s\n", DEV_BUTTON);

close(dev_fd);

return 0;

}

        應(yīng)用程序Makefile

WORKDIR  =

INCLUDES = -I.

LIBS     =

LINKS    = -lpthread

CC = arm-none-linux-gnueabi-gcc

TARGET = main

src=$(wildcard *.c ./callback/*.c)

C_OBJS=$(patsubst %.c, %.o,$(src))

#C_OBJS=$(dir:%.c=%.o)

compile:$(TARGET)

$(C_OBJS):%.o:%.c

$(CC) $(CFLAGS) $(INCLUDES) -o $*.o -c $*.c

$(TARGET):$(C_OBJS)

$(CC) -o $(TARGET) $^ $(LIBS) $(LINKS)

@echo

@echo Project has been successfully compiled.

@echo

install: $(TARGET)

cp $(TARGET) $(INSTALL_PATH)

uninstall:

rm -f $(INSTALL_PATH)/$(TARGET)

rebuild: clean compile

clean:

rm -rf *.o  $(TARGET) *.log *~

三、select的整體流程

    應(yīng)用層的select函數(shù)會調(diào)用到內(nèi)核函數(shù)do_select,,do_select調(diào)用驅(qū)動的poll函數(shù),,若poll函數(shù)返回的掩碼不可讀寫,那么do_select進(jìn)入睡眠阻塞,。要從睡眠中醒來并且跳出,,有兩種情況:a、超時跳出,;b,、驅(qū)動中喚醒等待隊列,這時do_select再次調(diào)用poll函數(shù),,如果poll函數(shù)返回的掩碼可讀寫,,那么就跳出阻塞,否則繼續(xù)睡眠,。注意:上述是在select函數(shù)設(shè)成阻塞的情況,,select函數(shù)可以設(shè)置成非阻塞的(select函數(shù)的timeout參數(shù)設(shè)置成0)

四,、select機制內(nèi)核代碼走讀

    調(diào)用順序如下select() -> core_sys_select() -> do_select() -> fop->poll()

    1,、select函數(shù)解析

<pre name="code">SYSCALL_DEFINE5(select, int, n, fd_set __user *, inp, fd_set __user *, outp,

    fd_set __user *, exp, struct timeval __user *, tvp)

{

       struct timespec end_time, *to = NULL;

       struct timeval tv;

       int ret;

       if (tvp) {// 如果超時值非NULL

              if (copy_from_user(&tv, tvp, sizeof(tv)))   // 從用戶空間取數(shù)據(jù)到內(nèi)核空間

                     return -EFAULT;

              to = &end_time;

              // 得到timespec格式的未來超時時間

              if (poll_select_set_timeout(to,

                            tv.tv_sec + (tv.tv_usec / USEC_PER_SEC),

                            (tv.tv_usec % USEC_PER_SEC) * NSEC_PER_USEC))

                     return -EINVAL;

       }

       ret = core_sys_select(n, inp, outp, exp, to);             // 關(guān)鍵函數(shù)

       ret = poll_select_copy_remaining(&end_time, tvp, 1, ret);

       /*如果有超時值, 并拷貝離超時時刻還剩的時間到用戶空間的timeval*/

       return ret;             // 返回就緒的文件描述符的個數(shù)

}   

   2core_sys_select函數(shù)解析

int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp,

                        fd_set __user *exp, struct timespec *end_time)

{

    fd_set_bits fds;

    /**

    typedef struct {

        unsigned long *in, *out, *ex;

        unsigned long *res_in, *res_out, *res_ex;

    } fd_set_bits;

    這個結(jié)構(gòu)體中定義的全是指針,,這些指針都是用來指向描述符集合的。

    **/

    void *bits;

    int ret, max_fds;

    unsigned int size;

    struct fdtable *fdt;

    /* Allocate small arguments on the stack to save memory and be faster */

    long stack_fds[SELECT_STACK_ALLOC/sizeof(long)];

    // 256/32 = 8, stack中分配的空間

    /**

        @ include/linux/poll.h

        #define FRONTEND_STACK_ALLOC     256

        #define SELECT_STACK_ALLOC    FRONTEND_STACK_ALLOC

    **/

    ret = -EINVAL;

    if (n < 0)

        goto out_nofds;

    /* max_fds can increase, so grab it once to avoid race */

    rcu_read_lock();

    fdt = files_fdtable(current->files); // RCU ref, 獲取當(dāng)前進(jìn)程的文件描述符表

    max_fds = fdt->max_fds;

    rcu_read_unlock();

    if (n > max_fds)                     // 如果傳入的n大于當(dāng)前進(jìn)程最大的文件描述符,,給予修正

        n = max_fds;

    /*

    * We need 6 bitmaps (in/out/ex for both incoming and outgoing),

    * since we used fdset we need to allocate memory in units of

    * long-words.

    */

    size = FDS_BYTES(n);

    // 以一個文件描述符占一bit來計算,,傳遞進(jìn)來的這些fd_set需要用掉多少個字

    bits = stack_fds;

    if (size > sizeof(stack_fds) / 6) {

        // 6,為什么?因為每個文件描述符需要6bitmaps

        /* Not enough space in on-stack array; must use kmalloc */

        ret = -ENOMEM;

        bits = kmalloc(6 * size, GFP_KERNEL); // stack中分配的太小,,直接kmalloc

        if (!bits)

            goto out_nofds;

    }

    // 這里就可以明顯看出struct fd_set_bits結(jié)構(gòu)體的用處了,。

    fds.in      = bits;

    fds.out     = bits +   size;

    fds.ex      = bits + 2*size;

    fds.res_in  = bits + 3*size;

    fds.res_out = bits + 4*size;

    fds.res_ex  = bits + 5*size;

    // get_fd_set僅僅調(diào)用copy_from_user從用戶空間拷貝了fd_set

    if ((ret = get_fd_set(n, inp, fds.in)) ||

        (ret = get_fd_set(n, outp, fds.out)) ||

        (ret = get_fd_set(n, exp, fds.ex)))

        goto out;

    zero_fd_set(n, fds.res_in);  // 對這些存放返回狀態(tài)的字段清0

    zero_fd_set(n, fds.res_out);

    zero_fd_set(n, fds.res_ex);

    ret = do_select(n, &fds, end_time);    // 關(guān)鍵函數(shù),完成主要的工作

    if (ret < 0)                           // 有錯誤

        goto out;

    if (!ret) {                            // 超時返回,,無設(shè)備就緒

        ret = -ERESTARTNOHAND;

        if (signal_pending(current))

            goto out;

        ret = 0;

    }

    // 把結(jié)果集,拷貝回用戶空間

    if (set_fd_set(n, inp, fds.res_in) ||

        set_fd_set(n, outp, fds.res_out) ||

        set_fd_set(n, exp, fds.res_ex))

        ret = -EFAULT;

out:

    if (bits != stack_fds)

        kfree(bits);               // 如果有申請空間,,那么釋放fds對應(yīng)的空間

out_nofds:

    return ret;                    // 返回就緒的文件描述符的個數(shù)

}

    3do_select函數(shù)解析

int do_select(int n, fd_set_bits *fds, struct timespec *end_time)

{

       ktime_t expire, *to = NULL;

       struct poll_wqueues table;

       poll_table *wait;

       int retval, i, timed_out = 0;

       unsigned long slack = 0;

       rcu_read_lock();

       // 根據(jù)已經(jīng)設(shè)置好的fd位圖檢查用戶打開的fd, 要求對應(yīng)fd必須打開, 并且返回

       // 最大的fd

       retval = max_select_fd(n, fds);

       rcu_read_unlock();

       if (retval < 0)

              return retval;

       n = retval;

       // 一些重要的初始化:

       // poll_wqueues.poll_table.qproc函數(shù)指針初始化,,該函數(shù)是驅(qū)動程序中poll函數(shù)實

       // 現(xiàn)中必須要調(diào)用的poll_wait()中使用的函數(shù),。

       poll_initwait(&table);

       wait = &table.pt;

       if (end_time && !end_time->tv_sec && !end_time->tv_nsec) {

              wait = NULL;

              timed_out = 1;     // 如果系統(tǒng)調(diào)用帶進(jìn)來的超時時間為0,那么設(shè)置

                                          // timed_out = 1,,表示不阻塞,,直接返回。

       }

       if (end_time && !timed_out)

              slack = estimate_accuracy(end_time); // 超時時間轉(zhuǎn)換

       retval = 0;

       for (;;) {

              unsigned long *rinp, *routp, *rexp, *inp, *outp, *exp;

              inp = fds->in; outp = fds->out; exp = fds->ex;

              rinp = fds->res_in; routp = fds->res_out; rexp = fds->res_ex;

              // 所有nfd的循環(huán)

              for (i = 0; i < n; ++rinp, ++routp, ++rexp) {

                     unsigned long in, out, ex, all_bits, bit = 1, mask, j;

                     unsigned long res_in = 0, res_out = 0, res_ex = 0;

                     const struct file_operations *f_op = NULL;

                     struct file *file = NULL;

                     // 先取出當(dāng)前循環(huán)周期中的32個文件描述符對應(yīng)的bitmaps

                     in = *inp++; out = *outp++; ex = *exp++;

                     all_bits = in | out | ex;  // 組合一下,,有的fd可能只監(jiān)測讀,,或者寫,或者e rr,,或者同時都監(jiān)測

                     if (all_bits == 0) {  // 32個描述符沒有任何狀態(tài)被監(jiān)測,,就跳入下一個32fd的循環(huán)中

                            i += __NFDBITS; //32個文件描述符一個循環(huán),正好一個long型數(shù)

                            continue;

                     }

                     // 本次32fd的循環(huán)中有需要監(jiān)測的狀態(tài)存在

                     for (j = 0; j < __NFDBITS; ++j, ++i, bit <<= 1) {// 初始bit = 1

                            int fput_needed;

                            if (i >= n)      // i用來檢測是否超出了最大待監(jiān)測的fd

                                   break;

                            if (!(bit & all_bits))

                                   continue; // bit每次循環(huán)后左移一位的作用在這里,,用來跳過沒有狀態(tài)監(jiān)測的fd

                            file = fget_light(i, &fput_needed); // 得到file結(jié)構(gòu)指針,,并增加引用計數(shù)字段f_count

                            if (file) {        // 如果file存在

                                   f_op = file->f_op;

                                   mask = DEFAULT_POLLMASK;

                                   if (f_op && f_op->poll) {

                                          wait_key_set(wait, in, out, bit);// 設(shè)置當(dāng)前fd待監(jiān)測的事件掩碼

                                          mask = (*f_op->poll)(file, wait);

                                          /*

                                          調(diào)用驅(qū)動程序中的poll函數(shù),以evdev驅(qū)動中的

                                          evdev_poll()為例該函數(shù)會調(diào)用函數(shù)poll_wait(file, &evdev->wait, wait),,

                                          繼續(xù)調(diào)用__pollwait()回調(diào)來分配一個poll_table_entry結(jié)構(gòu)體,,該結(jié)構(gòu)體有一個內(nèi)嵌的等待隊列項,

                                          設(shè)置好wake時調(diào)用的回調(diào)函數(shù)后將其添加到驅(qū)動程序中的等待隊列頭中,。

                                          */

                                   }

                                   fput_light(file, fput_needed);

                                   // 釋放file結(jié)構(gòu)指針,,實際就是減小他的一個引用計數(shù)字段f_count

                                   // mask是每一個fop->poll()程序返回的設(shè)備狀態(tài)掩碼,。

                                   if ((mask & POLLIN_SET) && (in & bit)) {

                                          res_in |= bit;         // fd對應(yīng)的設(shè)備可讀

                                          retval++;

                                          wait = NULL;       // 后續(xù)有用,,避免重復(fù)執(zhí)行__pollwait()

                                   }

                                   if ((mask & POLLOUT_SET) && (out & bit)) {

                                          res_out |= bit;              // fd對應(yīng)的設(shè)備可寫

                                          retval++;

                                          wait = NULL;

                                   }

                                   if ((mask & POLLEX_SET) && (ex & bit)) {

                                          res_ex |= bit;

                                          retval++;

                                          wait = NULL;

                                   }

                            }

                     }

                     // 根據(jù)poll的結(jié)果寫回到輸出位圖里,返回給上級函數(shù)

                     if (res_in)

                            *rinp = res_in;

                     if (res_out)

                            *routp = res_out;

                     if (res_ex)

                            *rexp = res_ex;

                     /*

                            這里的目的純粹是為了增加一個搶占點。

                            在支持搶占式調(diào)度的內(nèi)核中(定義了CONFIG_PREEMPT),,

                            cond_resched是空操作,。

                     */

                     cond_resched();

              }

              wait = NULL;  // 后續(xù)有用,避免重復(fù)執(zhí)行__pollwait()

              if (retval || timed_out || signal_pending(current))

                     break;

              if (table.error) {

                     retval = table.error;

                     break;

              }

              /*跳出這個大循環(huán)的條件有: 有設(shè)備就緒或有異常(retval!=0), 超時(timed_out

              = 1), 或者有中止信號出現(xiàn)*/

              /*

               * If this is the first loop and we have a timeout

               * given, then we convert to ktime_t and set the to

               * pointer to the expiry value.

               */

              if (end_time && !to) {

                     expire = timespec_to_ktime(*end_time);

                     to = &expire;

              }

              // 第一次循環(huán)中,,當(dāng)前用戶進(jìn)程從這里進(jìn)入休眠,,

              // 上面?zhèn)飨聛淼某瑫r時間只是為了用在睡眠超時這里而已

              // 超時,poll_schedule_timeout()返回0,;被喚醒時返回-EINTR

              if (!poll_schedule_timeout(&table, TASK_INTERRUPTIBLE,

                                      to, slack))

                     timed_out = 1; /* 超時后,,將其設(shè)置成1,方便后面退出循環(huán)返回到上層 */

       }

       // 清理各個驅(qū)動程序的等待隊列頭,,同時釋放掉所有空出來的page(poll_table_entry)

       poll_freewait(&table);

       return retval; // 返回就緒的文件描述符的個數(shù)

}    

---------------------

作者:o倚樓聽風(fēng)雨o

來源:CSDN

原文:https://blog.csdn.net/silent123go/article/details/52577648

版權(quán)聲明:本文為博主原創(chuàng)文章,,轉(zhuǎn)載請附上博文鏈接!

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點,。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多