globalfifo驅動例項(poll機制)

2021-05-26 15:03:12 字數 4899 閱讀 3810

阻塞操作是指在執行裝置操作時若不能獲得資源則掛起程序,直到滿足可操作的條件後在進行操作。非阻塞操作的程序在不能進行裝置操作時並不掛起,它或者被放棄,或者不停的查詢,直到可以進行操作為止

喚醒程序的地方最大可能發生在中斷裡面,因為硬體資源獲得的同時往往伴隨著乙個中斷

在使用者程式中,select()和poll()也是與裝置阻塞與非阻塞訪問息息相關的,使用非阻塞i/o的應用程式通常會使用select和poll系統呼叫查詢是否可對裝置進行無阻塞的訪問。select和poll系統呼叫最終會引發裝置驅動中的poll函式被執行

poll函式原型:

unsigned int(*poll)(struct file *filp, struct poll_table *wait);

第乙個引數為file結構體指標,第二個引數為輪詢表指標。這個函式應該進行以下兩項工作

1、對可能引起裝置檔案狀態變化的等待佇列呼叫poll_wait()函式,將對應等待佇列新增到          poll_table          

2、返回表示是否能對裝置進行無阻塞、寫訪問的掩碼

poll_wait()函式不會引起阻塞。它所做的工作就是把當前程序新增到wait引數指定的等待列表(poll_table)中

驅動程式poll函式應該返回裝置資源的可獲取狀態

fd_zero(fd_set *fdset);將指定的檔案描述符集清空,在對檔案描述符集合進行設定前,必須對其進行初始化,如果不清空,由於在系統分配記憶體空間後,通常並不作清空處理,所以結果是不可知的。

fd_set(fd_set *fdset);用於在檔案描述符集合中增加乙個新的檔案描述符。

fd_clr(fd_set *fdset);用於在檔案描述符集合中刪除乙個檔案描述符。

fd_isset(int fd,fd_set *fdset);判斷檔案描述符是否被置位

linux下select呼叫的過程:

1、使用者層應用程式呼叫select(),底層呼叫poll())

2、核心層呼叫sys_select() ------> do_select()

最終呼叫檔案描述符fd對應的struct file型別變數的struct file_operations *f_op的poll函式。

poll指向的函式返回當前可否讀寫的資訊。

1)如果當前可讀寫,返回讀寫資訊。

2)如果當前不可讀寫,則阻塞程序,並等待驅動程式喚醒,重新呼叫poll函式,或超時返回。

3、驅動需要實現poll函式。

當驅動發現有資料可以讀寫時,通知核心層,核心層重新呼叫poll指向的函式查詢資訊。

poll_wait(filp,&wait_q,wait) // 此處將當前程序加入到等待佇列中,但並不阻塞

在中斷中使用wake_up_interruptible(&wait_q)喚醒等待佇列

#define globalfifo_size 0x1000 /*全域性fifo最大4k位元組*/

#define fifo_clear 0x1  /*清0全域性記憶體的長度*/

#define globalfifo_major 200    /*預設的globalfifo的主裝置號*/

static int globalfifo_major = globalfifo_major;

/*globalfifo裝置結構體*/

struct globalfifo_dev                                    

;struct globalfifo_dev *globalfifo_devp; /*裝置結構體指標*/

/*檔案開啟函式*/

int globalfifo_open(struct inode *inode, struct file *filp)

/*檔案釋放函式*/

int globalfifo_release(struct inode *inode, struct file *filp)

/* ioctl裝置控制函式 */

static int globalfifo_ioctl(struct inode *inodep, struct file *filp, unsigned

int cmd, unsigned long arg)

return 0;

}static unsigned int globalfifo_poll(struct file *filp, poll_table *wait)

/*fifo非滿*/

if (dev->current_len != globalfifo_size)

up(&dev->sem);

return mask;

}/*globalfifo讀函式*/

static ssize_t globalfifo_read(struct file *filp, char __user *buf, size_t count,

loff_t *ppos)

//阻塞

__set_current_state(task_interruptible); //改變程序狀態為睡眠

up(&dev->sem);

schedule(); //排程其他程序執行

if (signal_pending(current))

//如果是因為訊號喚醒

down(&dev->sem);

}/* 拷貝到使用者空間 */

if (count > dev->current_len)

count = dev->current_len;

if (copy_to_user(buf, dev->mem, count)) //從核心空間拷貝到使用者空間

else

out: up(&dev->sem); //釋放訊號量

out2:remove_wait_queue(&dev->w_wait, &wait); //從附屬的等待佇列頭移除

set_current_state(task_running);

return ret;

}/*globalfifo寫操作*/

static ssize_t globalfifo_write(struct file *filp, const char __user *buf,

size_t count, loff_t *ppos)

__set_current_state(task_interruptible); //改變程序狀態為睡眠

up(&dev->sem);

schedule(); //排程其他程序執行

if (signal_pending(current))

//如果是因為訊號喚醒

down(&dev->sem); //獲得訊號量

}/*從使用者空間拷貝到核心空間*/

if (count > globalfifo_size - dev->current_len)

count = globalfifo_size - dev->current_len;

if (copy_from_user(dev->mem + dev->current_len, buf, count))

else

out: up(&dev->sem); //釋放訊號量

out2:remove_wait_queue(&dev->w_wait, &wait); //從附屬的等待佇列頭移除

set_current_state(task_running);

return ret;

}/*檔案操作結構體*/

static const struct file_operations globalfifo_fops =

;/*初始化並註冊cdev*/

static void globalfifo_setup_cdev(struct globalfifo_dev *dev, int index)

/*裝置驅動模組載入函式*/

int globalfifo_init(void)

if (ret < 0)

return ret;

/* 動態申請裝置結構體的記憶體*/

globalfifo_devp = kmalloc(sizeof(struct globalfifo_dev), gfp_kernel);

if (!globalfifo_devp)    /*申請失敗*/

memset(globalfifo_devp, 0, sizeof(struct globalfifo_dev));

globalfifo_setup_cdev(globalfifo_devp, 0);

init_mutex(&globalfifo_devp->sem);   /*初始化訊號量*/

init_waitqueue_head(&globalfifo_devp->r_wait); /*初始化讀等待佇列頭*/

init_waitqueue_head(&globalfifo_devp->w_wait); /*初始化寫等待佇列頭*/

return 0;

fail_malloc: unregister_chrdev_region(devno, 1);

return ret;

}/*模組解除安裝函式*/

void globalfifo_exit(void)

module_author("song baohua");

module_license("dual bsd/gpl");

module_param(globalfifo_major, int, s_irugo);

module_init(globalfifo_init);

module_exit(globalfifo_exit);

應用程式:

#define fifo_clear 0x1

#define buffer_len 20

main()

while (1)

/*資料可寫入*/

if (fd_isset(fd, &wfds))

}}else

}

globalfifo 驅動例項(工作佇列)

define globalfifo size 0x1000 全域性fifo最大4k位元組 define fifo clear 0x1 清0全域性記憶體的長度 define globalfifo major 200 預設的globalfifo的主裝置號 static int globalfifo ma...

支援非同步通知的globalfifo驅動

驅動程式執行在核心空間中,應用程式執行在使用者空間中,兩者是不能直接通訊的。但在實際應用中,在裝置已經準備好的時候,我們希望通知使用者程式裝置已經ok,使用者程式可以讀取了,這樣應用程式就不需要一直查詢該裝置的狀態,從而節約了資源,這就是非同步通知。好,那下乙個問題就來了,這個過程如何實現呢?簡單,...

驅動篇 支援輪詢操作的 globalfifo 驅動

1.globalfifo 驅動中增加輪詢操作 在 globalfifo 的 poll 函式中,首先將裝置結構體中的 r wait 和 w wait 等待佇列頭新增到等待列表,然後通過判斷 dev current len 是否等於 0 來獲得裝置的可讀狀態,通過判斷 dev current len 是...