阻塞操作是指在執行裝置操作時若不能獲得資源則掛起程序,直到滿足可操作的條件後在進行操作。非阻塞操作的程序在不能進行裝置操作時並不掛起,它或者被放棄,或者不停的查詢,直到可以進行操作為止
喚醒程序的地方最大可能發生在中斷裡面,因為硬體資源獲得的同時往往伴隨著乙個中斷
在使用者程式中,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 是...