監視多個文件描述符事件,無事件時進程睡眠釋放 CPU,有事件喚醒並返回就緒集合。struct pollfd 每次調用前需重新設置。
/* 等待隊列頭 */
static DECLARE_WAIT_QUEUE_HEAD(wq);
static int key_event = 0; // 條件標誌
/* 中斷處理:置位喚醒 */
irqreturn_t key_isr(int irq, void *dev) {
key_value = gpio_get_value(KEY_GPIO);
key_event = 1;
wake_up_interruptible(&wq);
return IRQ_HANDLED;
}
/* poll 入口:掛接等待隊列,檢查條件 */
unsigned int key_poll(struct file *filp, poll_table *wait) {
poll_wait(filp, &wq, wait); // 將當前進程加入 wq
if (key_event)
return POLLIN | POLLRDNORM; // 有數據可讀
return 0;
}
/* read 入口:清理條件,複製數據 */
ssize_t key_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off) {
wait_event_interruptible(wq, key_event); // 也可不調用,由用戶態 poll 保證
key_value = gpio_get_value(KEY_GPIO);
copy_to_user(buf, &key_value, sizeof(key_value));
key_event = 0;
return sizeof(key_value);
}
int main() {
int fd = open("/dev/key", O_RDWR);
struct pollfd pfd = { .fd = fd, .events = POLLIN };
while (1) {
memset(&pfd, 0, sizeof(pfd)); // poll 後結構被清零,必須重置
pfd.fd = fd; pfd.events = POLLIN;
int ret = poll(&pfd, 1, 5000); // 5秒超時
if (ret < 0) { perror("poll"); break; }
if (ret == 0) { puts("Timeout"); continue; }
if (pfd.revents & POLLERR) { puts("Device error"); break; }
if (pfd.revents & POLLIN) {
int val; read(fd, &val, sizeof(val));
printf("Key: %d\n", val);
}
}
close(fd);
return 0;
}
pollfd 每次循環必須 memset 重置,內核返回時會清零events 是輸入(關心什麼),revents 是輸出(實際發生什麼)poll_wait 不會睡眠,只是掛接;真正睡眠在用戶態 poll()LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := polltest
LOCAL_SRC_FILES := polltest.c
LOCAL_SHARED_LIBRARIES := liblog libcutils
include $(BUILD_EXECUTABLE)