在使用socket或串口的時候應用代碼經常使用select來判斷有沒接收到資料,驅動需要做什麼處理,應用程式層使用者才能正確判斷有資料收到並讀取資料呢?使用select能夠監視我們需要監視的檔案描述符的變化情況——讀寫或是異常。
先建立簡單模型,應用使用select監聽裝置是否可讀,當裝置可讀將資料讀出後繼續監聽。已經有了一個監聽裝置可讀狀態的進程,還要開啟終端使用echo xxx >/dev/moddev60向裝置寫入資料,裝置驅動收到資料後控制裝置變成可讀狀態,select進程select函數返回,查詢裝置可讀後讀出資料。代碼為了示範做了簡化不做並發出錯處理等。
先看下應用c代碼
#include <stdio.h>#include <fcntl.h>unsigned char rdBuf[1024];int main (int *argc,char**argv){ int fd,res;fd_set fset; FD_ZERO(&fset); fd=open("/dev/moduledev60",O_RDWR); if(fd<0){ printf("open devices error\n");return -1; } while(1) { FD_ZERO(&fset); FD_SET(fd,&fset); res=select(fd+1,&fset,NULL,NULL,NULL); if(res==-1) { close(fd); return -1; } else if(res==0) break; else { /*select 返回後判斷可讀*/ if(FD_ISSET(fd,&fset)) { read(fd,rdBuf,1024); printf("read data:%s\n",rdBuf); } } }close(fd);return 0;}
驅動關鍵代碼
struct file_operations ops={ .owner=THIS_MODULE , .read =fileops_read , .write=fileops_write, .poll =fileops_poll};
DECLARE_WAIT_QUEUE_HEAD(rdWait);//poll_wait中使用static unsigned char rdBuf[1024];//測試用讀寫緩衝 寫入資料和讀取資料0結尾static unsigned char rdFlag=0; //可讀標記 0不可讀緩衝內無資料 1可讀ssize_t fileops_read(struct file *filp, char __user *buff, size_t count, loff_t *offp){ unsigned int len; if(rdFlag==0) return 0; //不可讀時直接返回 len=strlen(rdBuf); //讀緩衝字串長 這個模型只做字串(0結尾)的寫入和讀取 copy_to_user(buff,rdBuf,len); // rdFlag=0; //清標記 return len;}ssize_t fileops_write(struct file *filp, const char __user *buff, size_t count, loff_t *offp){ copy_from_user(rdBuf,buff,count);// rdBuf[count]=0; //補字串結束標記 rdFlag=1; //標記可讀 poll函數檢測這個標記 wake_up_interruptible(&rdWait); /*fileops_poll 函數使用了 poll_wait 加入了rdWait等待列隊,執行後fileops_poll會被調用,如果不使用等待列隊 fileops_poll只在應用調用select時執行一次 這樣有資料select也不會返回*/ return count;}unsigned int fileops_poll(struct file *filp,poll_table *wait){ /*這裡測試只處理的可讀標記 也可以增加可寫標記*/ int mask=0; poll_wait(filp,&rdWait,wait); //這個函數不阻塞的,當狀態改變時,應該喚醒列隊這個函數才會重新調用更新新的狀態。 if(rdFlag) { mask=POLLIN|POLLRDNORM; } return mask; }
編譯後測試結果先運行應用,監聽裝置是否可讀[root@localhost ctest]# ./main 開啟另外一個終端,寫入資料[root@localhost ctest]# echo eeee>/dev/moduledev60[root@localhost ctest]# echo eeee>/dev/moduledev60[root@localhost ctest]# echo eeee>/dev/moduledev60應用判斷到可讀後讀出資料[root@localhost ctest]# ./main read data:eeeeread data:eeeeread data:eeee