1. 程式人生 > >嵌入式核心及驅動開發之學習筆記(九) 多路複用+中斷實現讀取資料

嵌入式核心及驅動開發之學習筆記(九) 多路複用+中斷實現讀取資料

使用阻塞模型雖然可以避免等待資料過程中,CPU對程序的消耗,但是僅僅是為了等待這一個結果,就讓程序進入休眠,對於還要進行其他IO操作的程序而言太“奢侈”。所以引入多路複用的概念,解決這個問題。

非阻塞:立即返回結果,如果想得到期望的結果,要不停的呼叫這個方法(輪詢),非常耗費資源

阻塞:沒有得到真正的資料前,不返回結果。此時,程序進入阻塞(休眠)態,直到有資料喚醒程序,這個過程不耗資源。

多路複用:和原理和阻塞類似,不過多路複用是同時進行多個IO讀寫操作。這樣就減少了在等待時間上的浪費,提高效率。

 

 

多路複用要對檔案描述符進行操作,在應用層上進行實現。關於多路複用在應用層上的使用,之前我有總結過一份

筆記。這裡使用poll函式完成;應用中使用poll對裝置檔案進行了監控,那麼裝置驅動就必須實現poll介面。所以...

  1. poll函式實現對標準輸入流(按鍵)與裝置輸入流(按鍵)的監控
  2. 在裝置驅動中實現poll的介面

Linux環境下使用`man 2 poll`檢視poll函式的介紹,程式包含標頭檔案poll.h

#include <poll.h>

int poll(struct pollfd *fds, nfds_t nfds, int timeout);
引數1: 表示多個檔案描述符集合
    struct pollfd描述的是檔案描述符到資訊
    struct pollfd {
       int   fd;  //檔案描述符
       short events;   //希望監控fd的什麼事件:讀,寫,出錯
                    POLLIN 讀,
                    POLLOUT 寫,
                    POLLERR出錯
       short revents;    //結果描述,表示當前的fd是否有讀,寫,出錯
                    //用於判斷,是核心自動賦值
                    POLLIN 讀,
                    POLLOUT 寫,
                    POLLERR出錯
    };
引數2:被監控到fd的個數
引數3: 監控的時間:
            正: 表示監控多少ms
            負數: 無限的時間去監控
            0: 等待0ms,類似於非阻賽
返回值: 負數:出錯
        大於0,表示fd中有資料
        等於0: 時間到 

 

應用程式

//key_test.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <poll.h>




struct key_event{
	int code; // 按鍵的型別
	int value; // 狀態
};


#define KEY_ENTER		28

int main(int argc, char *argv[])
{
	int ret;
	char in_buf[128];	//接收標準輸入資料
	struct key_event event;	//接收按鍵裝置資料
	
	int fd = open("/dev/key0", O_RDWR);
	
	if(fd < 0)
	{
		perror("open");
		exit(1);
	}
	//描述2個檔案描述符,標準輸入0 和 按鍵裝置結點fd
	struct pollfd pfd[2];

	pfd[0].fd = fd; //監控按鍵裝置
	pfd[0].events = POLLIN;

	pfd[1].fd = 0; //標準輸入
	pfd[1].events = POLLIN;

	while(1)
	{
			ret = poll(pfd, 2, -1); // 多路複用 poll 同時監控按鍵與標準輸入
			printf("ret = %d\n", ret);
			
			if(ret > 0)
			{//表示有資料
				if(pfd[0].revents & POLLIN)
				{//按鍵裝置
					//讀裝置結點中的資料
					read(pfd[0].fd, &event, sizeof(struct key_event));	
					if(event.code == KEY_ENTER)
					{
						if(event.value)
						{
							printf("APP__ key enter pressed\n");
						}else
						{
							printf("APP__ key enter up\n");
						}
					}
				}
				if(pfd[1].revents & POLLIN)
				{//標準輸入
					fgets(in_buf, 128, stdin);
					printf("in_buf = %s\n", in_buf);
				}
			}else{
				perror("poll");
				exit(1);
			}
	}



	close(pfd[0].fd);


	return 0;

}



 

裝置驅動檔案

1.在file_operations中 poll指向key_drv_poll函式

const struct file_operations key_fops = {
	.open = key_drv_open,
	.read = key_drv_read,
	.write = key_drv_write,
	.release = key_drv_close,
	.poll = key_drv_poll,

};

2.在key_drv_poll函式中實現介面

unsigned int key_drv_poll(struct file *filp, struct poll_table_struct *pts)
{
	
	// 返回一個mask值
	unsigned int mask;
	// 呼叫poll_wait,將當前到等待佇列註冊系統中
	poll_wait(filp, &key_dev->wq_head, pts);
	
	// 1,當沒有資料到時候返回一個0
	if(!key_dev->key_state)
		mask = 0;

	// 2,有資料返回一個POLLIN
	if(key_dev->key_state)
		mask |= POLLIN;

	return mask;
	
}

 

最終結果