詳解Linux設備(bèi)驅動中的阻塞與非阻塞
「阻塞(sāi)與(yǔ)非阻塞定義」阻塞操作是指,在執行設備操作時,若不能獲得(dé)資源,則進程掛起直到滿足可操作的條件(jiàn)再進行操作。被掛起的進程進入sleep 狀態,被從(cóng)調度器的運行隊列移走,直到等待的條件被滿(mǎn)足。
非阻塞操作的進程在不能進行設備操作時,並不掛起。
「阻塞實例」
多個進程對驅動中(zhōng)的全局(jú)變量,有的讀有的寫,用阻塞機製(zhì)來保證隻有在某個進程寫過之(zhī)後,其他進程在能夠讀這個變(biàn)量。
#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;//定義等待隊列頭static int flag = 0;//阻塞(sāi)條件(jiàn)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)
{ //等待數據可獲得if (wait_event_interruptible(outq, flag != 0))//在這裏讓調用自己的進程進入掛起狀(zhuàng)態,直到滿/ //足後麵的條件才脫離掛起狀態(tài){ return - ERESTARTSYS;} if (down_interruptible(&sem))
{ return - ERESTARTSYS;} flag = 0; //阻塞(sāi)條件在這裏(lǐ)發生改變,意味著每次隻能對這個變量讀一次,除非再次給這個//變量賦了新值。
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;//阻塞條件在(zài)這(zhè)裏發(fā)生改變,意味著可以掛起的進程可以(yǐ)解禁了(le)/*通知數據可獲得前麵調用驅動read函(hán)數的(de)進程被調整到了掛起(qǐ)狀態,隻有當滿(mǎn)足一個條件的時候才會從掛(guà)起狀態擺脫(tuō)。這個地方注意了,並沒有一個機製(zhì)自(zì)動的檢測條(tiáo)件,或者條件改變(biàn)的時候,自動(dòng)通知內(nèi)核改變進程的狀態。而(ér)是,我(wǒ)們需要調用函數去手動喚醒等待隊列,隊列會檢測條件,如果條件滿足,那麽解禁(jìn)進程,如果條件不滿足(zú),進程(chéng)依然被封印。
*/ wake_up_interruptible(&outq);return sizeof(int);} module_init(globalvar_init);module_exit(globalvar_exit);
這裏有一個問題,等待隊(duì)列應該可能會(huì)有多個被封印的進程,在這種情況下:1. 後麵的進程能否(fǒu)被(bèi)前麵的進程更早的解禁?
2. 每次通過函數試圖喚(huàn)醒隊列的時候,隊列對條(tiáo)件的檢測機製是(shì)怎樣的?是否一個(gè)一個的(de)進程順序的檢測各自(zì)的條件嗎?
用來對本驅動進(jìn)行測試的參考應用(yòng)程序為:「讀程序」
#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)); //程序將阻塞在此語句,除非有(yǒu)針對globalvar 的輸入printf("The globalvar is %d\n", num);//如(rú)果輸入是0,則退出if (num == 0)
{ close(fd);break;} else { printf("device open failure\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)
{ printf("Please input the globalvar:\n");scanf("%d", &num);write(fd, &num, sizeof(int));//如果輸(shū)入0,退出if (num == 0)
{ close(fd);break;} else { printf("device open failure\n");}
關鍵(jiàn)詞:Linux,設備驅(qū)動
閱讀本文後您有什麽感想? 已有 人給(gěi)出評(píng)價!
- 1
- 1
- 1
- 1
- 1
- 1