Linux 設備驅動--- 阻塞型字符設備驅動 --- O_NONBLOCK --- 非阻塞標志【轉】


轉自:http://blog.csdn.net/yikai2009/article/details/8653697

 
 

阻塞:

          在設計簡單字符驅動程序時,要注意一個重要問題.

          當一個設備無法立刻滿足用戶的讀寫請求時應當如何處理?

          例如:調用 read 時沒有數據可讀,但以后可能會有;

          或者一個進程試圖向設備寫入數據,但是設備暫時沒有准備好接收數據.

          應用程序通常不關心這種問題,應用程序只是調用 read 或 write 並得到返回值.

          驅動程序應當 ( 缺省地 ) 阻塞進程使它進入睡眠直到請求可以得到滿足.

阻塞操作:

          是指在執行設備操作時,若不能獲得資源則掛起進程,直到滿足可操作的條件后進行操作,

          被掛起的進程進入睡眠狀態,被從調度器的運行隊列移走,直到等待的條件被滿足.

非阻塞操作:

          進程不能進行設備操作時並不掛起,他或者放棄,或者不停的查詢,直到可以進行操作為止.

 

阻塞方式-read- 實現:

          在阻塞型驅動程序中,read 實現方式如下:

          如果進程調用 read ,但設備 沒有數據 或 數據不足,進程阻塞.

          當新數據到達后,喚醒被阻塞進程.

 

阻塞方式-write- 實現:

          在阻塞型驅動程序中,write 實現方式如下:
          如果進程調用了 write ,但設備 沒有足夠的空間供其寫入數據,進程阻塞.
          當設備中的數據被讀走后,緩沖區中空出部分空間,則喚醒進程.
 

非阻塞方式的讀寫操作:

           阻塞方式是文件讀寫操作的 默認方式,但是應用程序員可通過使用O_NONBLOCK 標志來人為
          的 設置讀寫操作為 非阻塞方式 .( 該標志定義在 < linux/fcntl.h > 中,在打開文件時指定 ) .
 
          如果 設置了 O_NONBLOCK 標志,read 和 write 的行為是不同的 ,如果進程沒有數據就緒時調用了 read ,
          或者在緩沖區沒有空間時調用了 write ,系統只是 簡單的返回 -EAGAIN,而 不會阻塞進程.
 

實例 --- 讀阻塞的實現:

          
          
 
用 while 是因為可能別的信號喚醒了睡眠,我們要通過while 重新檢測是否真有數據了....
 
 
          
 
 

實例 --- 按鍵驅動阻塞實現:

1,在 open 函數 查看看是 阻塞方式 還是 非阻塞方式:

         file 結構體中含有 f_flags 標志位,看是 阻塞方式 還是 非阻塞方式:
          O_NONBLOCK 為 非阻塞方式
[cpp]  view plain  copy
 
  1. if (file->f_flags & O_NONBLOCK)  /* 非 阻塞操作 */  
  2. {  
  3.     if (down_trylock(&button_lock))   /* 無法獲取信號量,down_trylock 立馬返回 一個 非零值 */  
  4.         return -EBUSY;  
  5. }  
  6. else                             /* 阻塞操作 */  
  7. {  
  8.     /* 獲取信號量 */  
  9.     down(&button_lock);   /* 獲取不到  睡眠 */  
  10. }  

2,在 read 函數中同樣查看:

[cpp]  view plain  copy
 
  1. if (file->f_flags & O_NONBLOCK)       /* 非 阻塞操作 */  
  2. {  
  3.     if (!ev_press)                 /* ev_press 為 1 表示有按鍵按下,為 0 if 成立 ,沒有按鍵按下, */  
  4.         return -EAGAIN;        /* 返回 -EAGAIN 讓再次來執行 */  
  5. }  
  6. else                                   /* 阻塞操作 */  
  7. {  
  8.     /* 如果沒有按鍵動作, 休眠 */  
  9.     wait_event_interruptible(button_waitq, ev_press);  
  10. }  

3,應用程序中:

1,以阻塞方式運行:

后台執行應用程序,進程處於睡眠狀態,按下按鍵,立馬打印按鍵號;
[cpp]  view plain  copy
 
  1. int main(int argc, char **argv)  
  2. {  
  3.     unsigned char key_val;  
  4.     int Oflags;  
  5.                                                      
  6.     fd = open("/dev/buttons", O_RDWR );  
  7.     if (fd < 0)  
  8.     {  
  9.         printf("can't open!\n");  
  10.         return -1;  
  11.     }  
  12.   
  13.     while (1)  
  14.     {  
  15.         read(fd, &key_val, 1);  
  16.         printf("key_val: 0x%x\n", key_val);  
  17.     }  
  18.       
  19.     return 0;  
  20. }  


2,以非阻塞方式運行:

open 驅動程序的時候,傳入標志 O_NONBLOCK 非阻塞;
后台執行應用程序:
[cpp]  view plain  copy
 
  1. int main(int argc, char **argv)  
  2. {  
  3.     unsigned char key_val;  
  4.     int ret;  
  5.     int Oflags;  
  6.   
  7.     fd = open("/dev/buttons", O_RDWR | O_NONBLOCK);  
  8.     if (fd < 0)  
  9.     {  
  10.         printf("can't open!\n");  
  11.         return -1;  
  12.     }  
  13.   
  14.     while (1)  
  15.     {  
  16.         ret = read(fd, &key_val, 1);  
  17.         printf("key_val: 0x%x, ret = %d\n", key_val, ret);  
  18.         sleep(5);  
  19.     }  
  20.       
  21.     return 0;  
  22. }  
 
非阻塞方式,沒有按鍵值按下,程序立馬返回;
read 返回值 為 -1;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM