Poll就是監控文件是否可讀的一種機制,作用與select一樣。
應用程序的調用函數如下:
int poll(struct pollfd *fds,nfds_t nfds, int timeout);
Poll機制會判斷fds中的文件是否可讀,如果可讀則會立即返回,返回的值就是可讀fd的數量,如果不可讀,那么就進程就會休眠timeout這么長的時間,然后再來判斷是否有文件可讀,如果有,返回fd的數量,如果沒有,則返回0.
使用非阻塞I/O的應用程序通常會使用select()和poll()系統調用查詢是否可對設備進行無阻塞的訪問,這兩個系統調用最終又會引發設備驅動中的poll()函數被執行
如果當前不可讀(先調用驅動.poll確定是否可讀,然后繼續do_poll),那么在sys_poll->do_poll中當前進程就會睡眠在等待隊列上,這個等待隊列是由驅動程序提供的(就是poll_wait中傳入的那個)。當可讀的時候,驅動程序可能有一部分代碼運行了(比如驅動的中斷服務
程序),那么在這部分代碼中,就會喚醒等待隊列上的進程,也就是之前睡眠的那個,當那個進程被喚醒后do_poll會再一次的調用驅動程序的poll函數,這個時候應用程序就知道是可讀的了。
Demo程序(一個線程中同時監聽兩個UDP客戶程序的數據發送):
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #include <errno.h> /// Handle poll input types #define POLL_INPUT (POLLIN | POLLPRI) /// Handle poll error types #define POLL_ERROR (POLLERR | POLLHUP | POLLNVAL) /// Handle pool output types #define POLL_OUTPUT (POLLOUT) /// Identify each physical interface typedef enum FHandleVal { INTERFACE_UDP_DCP = 0, INTERFACE_UDP_LTE, INTERFACE_MAX_VAL } eFHandleVal; static struct pollfd FDesc[INTERFACE_MAX_VAL]; static int rxUDPLTEInit(); static int rxUDPDCPInit(); static int rxLteUDPData(int fd); static int rxDCPUDPData(int fd); int rxUDPLTEInit() { struct sockaddr_in server_lte_addr; /// UDP datagram socket int sock_Lte_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (sock_Lte_fd < 0) { // oops printf("UDP lte: RX socket failed %d, %s\n", errno, strerror(errno)); sock_Lte_fd = -errno; return -1; } memset(&server_lte_addr,0,sizeof(struct sockaddr_in)); server_lte_addr.sin_family = AF_INET; server_lte_addr.sin_addr.s_addr = htonl(INADDR_ANY); server_lte_addr.sin_port = htons(27358); int rc = bind(sock_Lte_fd, (struct sockaddr *)&server_lte_addr, sizeof(server_lte_addr)); if (rc < 0) { // oops printf("UDP: bind(%d, ANY) RX failed: %d, %s\n", sock_Lte_fd, errno, strerror(errno)); close(sock_Lte_fd); sock_Lte_fd = -errno; } else { printf("UDP: bind on RX port %d\n",27358); } return sock_Lte_fd; } int rxUDPDCPInit() { int sock_fd; struct sockaddr_in server_addr; struct sockaddr_in src_addr; socklen_t client_len; memset(&server_addr,0,sizeof(struct sockaddr_in)); if ((sock_fd = socket(AF_INET, SOCK_DGRAM,0)) < 0) { perror("socket create error\n"); exit(1); } server_addr.sin_family = AF_INET; server_addr.sin_port = htons(4004); server_addr.sin_addr.s_addr = htonl(INADDR_ANY); printf("Ready bind 4004\n"); if (bind(sock_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_in)) < 0) { perror("bind socket error.\n"); exit(1); } return sock_fd; } int rxDCPUDPData(int fd) { int rcv_num = -1; char rcv_buff[512]; struct sockaddr_in src_addr; socklen_t client_len; int encodeNum = -1; BSM_t BSMData; client_len = sizeof(struct sockaddr_in); rcv_num= recvfrom(fd, rcv_buff, sizeof(rcv_buff), 0, (struct sockaddr*)&src_addr, &client_len); if (rcv_num>0) { rcv_buff[rcv_num] = '\0'; printf("%s %d says: %s\n",inet_ntoa(src_addr.sin_addr),ntohs(src_addr.sin_port),rcv_buff); } else { perror("recv DCP Data error\n"); exit(1); } return 0; } int rxLteUDPData(int fd) { int rcv_num = -1; char rcv_buff[512]; struct sockaddr_in src_addr; socklen_t client_len; client_len = sizeof(struct sockaddr_in); rcv_num= recvfrom(fd, rcv_buff, sizeof(rcv_buff), 0, (struct sockaddr*)&src_addr, &client_len); if (rcv_num>0) { rcv_buff[rcv_num] = '\0'; printf("%s %d says: %s\n",inet_ntoa(src_addr.sin_addr),ntohs(src_addr.sin_port),rcv_buff); }else { perror("recv LTE-V Data error:"); exit(1); } } int main(void) { FDesc[INTERFACE_UDP_LTE].fd = rxUDPLTEInit(); if (FDesc[INTERFACE_UDP_LTE].fd < 0) exit(1); FDesc[INTERFACE_UDP_DCP].fd = rxUDPDCPInit(); if (FDesc[INTERFACE_UDP_DCP].fd < 0) exit(1); // setup the poll events FDesc[INTERFACE_UDP_DCP].events = POLL_INPUT; FDesc[INTERFACE_UDP_LTE].events = POLL_INPUT; while (1) { int Data = poll(FDesc, INTERFACE_MAX_VAL, 1000); // poll status check if (Data < 0) { // error printf("Poll error %d '%s'\n", errno, strerror(errno)); } else if (Data == 0) { // timeout printf("Poll timeout\n"); continue; } // Receive DCP UDP if (FDesc[INTERFACE_UDP_DCP].revents & POLL_ERROR) { printf("Poll error on UDP (revents 0x%02x)\n", FDesc[INTERFACE_UDP_DCP].revents); } if (FDesc[INTERFACE_UDP_DCP].revents & POLL_INPUT) { int Res = rxDCPUDPData(FDesc[INTERFACE_UDP_DCP].fd); if(Res!=0) { } } // Receive LTE UDP if (FDesc[INTERFACE_UDP_LTE].revents & POLL_ERROR) { printf("Poll error on UDP (revents 0x%02x)\n", FDesc[INTERFACE_UDP_LTE].revents); } if (FDesc[INTERFACE_UDP_LTE].revents & POLL_INPUT) { int Res = rxLteUDPData(FDesc[INTERFACE_UDP_LTE].fd); } } if(FDesc[INTERFACE_UDP_LTE].fd) close(FDesc[INTERFACE_UDP_LTE].fd); if(FDesc[INTERFACE_UDP_DCP].fd) close(FDesc[INTERFACE_UDP_DCP].fd); return 0; }