詳解Linux設(shè)備驅(qū)動(dòng)中的阻塞與非阻塞
「阻塞與非阻塞定義」阻塞操作是指,在執(zhí)行設(shè)備操作時(shí),若不能獲得資源,則進(jìn)程掛起直到滿足可操作的條件再進(jìn)行操作。被掛起的進(jìn)程進(jìn)入sleep 狀態(tài),被從調(diào)度器的運(yùn)行隊(duì)列移走,直到等待的條件被滿足。
非阻塞操作的進(jìn)程在不能進(jìn)行設(shè)備操作時(shí),并不掛起。
「阻塞實(shí)例」
多個(gè)進(jìn)程對(duì)驅(qū)動(dòng)中的全局變量,有的讀有的寫,用阻塞機(jī)制來保證只有在某個(gè)進(jìn)程寫過之后,其他進(jìn)程在能夠讀這個(gè)變量。
#include #include #include #include #include #include
MODULE_LICENSE("GPL");
#define MAJOR_NUM 254
static ssize_t globalvar_read(struct file *, char *, size_t, loff_t*);static ssize_t globalvar_write(struct file *, const char *, size_t, loff_t*);
struct file_operations globalvar_fops = { read: globalvar_read,write: globalvar_write,};
static int global_var = 0;static struct semaphore sem;static wait_queue_head_t outq;//定義等待隊(duì)列頭static int flag = 0;//阻塞條件static int __init globalvar_init(void)
{ int ret;ret = register_chrdev(MAJOR_NUM, "globalvar", &globalvar_fops);if (ret)
{ printk("globalvar register failure");} else { printk("globalvar register success");init_MUTEX(&sem);init_waitqueue_head(&outq);} return ret;} static void __exit globalvar_exit(void)
{ int ret;ret = unregister_chrdev(MAJOR_NUM, "globalvar");if (ret)
{ printk("globalvar unregister failure");} else { printk("globalvar unregister success");}
static ssize_t globalvar_read(struct file *filp, char *buf, size_t len, loff_t *off)
{ //等待數(shù)據(jù)可獲得if (wait_event_interruptible(outq, flag != 0))//在這里讓調(diào)用自己的進(jìn)程進(jìn)入掛起狀態(tài),直到滿/ //足后面的條件才脫離掛起狀態(tài){ return - ERESTARTSYS;} if (down_interruptible(&sem))
{ return - ERESTARTSYS;} flag = 0; //阻塞條件在這里發(fā)生改變,意味著每次只能對(duì)這個(gè)變量讀一次,除非再次給這個(gè)//變量賦了新值。
if (copy_to_user(buf, &global_var, sizeof(int)))
{ up(&sem);return - EFAULT;} up(&sem);return sizeof(int);}
static ssize_t globalvar_write(struct file *filp, const char *buf, size_t len,loff_t *off)
{ if (down_interruptible(&sem))
{ return - ERESTARTSYS;} if (copy_from_user(&global_var, buf, sizeof(int)))
{ up(&sem);return - EFAULT;} up(&sem);flag = 1;//阻塞條件在這里發(fā)生改變,意味著可以掛起的進(jìn)程可以解禁了/*通知數(shù)據(jù)可獲得前面調(diào)用驅(qū)動(dòng)read函數(shù)的進(jìn)程被調(diào)整到了掛起狀態(tài),只有當(dāng)滿足一個(gè)條件的時(shí)候才會(huì)從掛起狀態(tài)擺脫。這個(gè)地方注意了,并沒有一個(gè)機(jī)制自動(dòng)的檢測(cè)條件,或者條件改變的時(shí)候,自動(dòng)通知內(nèi)核改變進(jìn)程的狀態(tài)。而是,我們需要調(diào)用函數(shù)去手動(dòng)喚醒等待隊(duì)列,隊(duì)列會(huì)檢測(cè)條件,如果條件滿足,那么解禁進(jìn)程,如果條件不滿足,進(jìn)程依然被封印。
*/ wake_up_interruptible(&outq);return sizeof(int);} module_init(globalvar_init);module_exit(globalvar_exit);
這里有一個(gè)問題,等待隊(duì)列應(yīng)該可能會(huì)有多個(gè)被封印的進(jìn)程,在這種情況下:1. 后面的進(jìn)程能否被前面的進(jìn)程更早的解禁?
2. 每次通過函數(shù)試圖喚醒隊(duì)列的時(shí)候,隊(duì)列對(duì)條件的檢測(cè)機(jī)制是怎樣的?是否一個(gè)一個(gè)的進(jìn)程順序的檢測(cè)各自的條件嗎?
用來對(duì)本驅(qū)動(dòng)進(jìn)行測(cè)試的參考應(yīng)用程序?yàn)椋骸缸x程序」
#include #include #include #include main()
{ int fd, num;fd = open("/dev/globalvar", O_RDWR, S_IRUSR | S_IWUSR);if (fd != - 1)
{ while (1)
{ read(fd, &num, sizeof(int)); //程序?qū)⒆枞诖苏Z(yǔ)句,除非有針對(duì)globalvar 的輸入printf("The globalvar is %d\n", num);//如果輸入是0,則退出if (num == 0)
{ close(fd);break;} else { printf("device open failure\n");}
「寫程序」
#include #include #include #include main()
{ int fd, num;fd = open("/dev/globalvar", O_RDWR, S_IRUSR | S_IWUSR);if (fd != - 1)
{ while (1)
{ printf("Please input the globalvar:\n");scanf("%d", &num);write(fd, &num, sizeof(int));//如果輸入0,退出if (num == 0)
{ close(fd);break;} else { printf("device open failure\n");}
關(guān)鍵詞:Linux,設(shè)備驅(qū)動(dòng)
閱讀本文后您有什么感想? 已有 人給出評(píng)價(jià)!
- 1
- 1
- 1
- 1
- 1
- 1