“曾經有一份真摯的愛情擺在面前,我卻不懂珍惜;曾經有一個承諾,我卻倍感珍惜,今天一定要好好講講..”
講講啥,講講上節說的那個非同步通知的例子唄,大家喜歡看代碼,咋們就先上代碼:
struct globalfifo_dev { struct cdev cdev; /*cdev結構體*/ unsigned int current_len; /*fifo有效資料長度*/ unsigned char mem[GLOBALFIFO_SIZE]; /*全域記憶體*/ struct semaphore sem; /*並發控制用的訊號量*/ wait_queue_head_t r_wait; /*阻塞讀用的等待隊列頭*/ wait_queue_head_t w_wait; /*阻塞寫用的等待隊列頭*/ struct fasync_struct *async_queue; /* 非同步結構體指標,用於讀 */ };/*檔案釋放函數*/int globalfifo_release(struct inode *inode, struct file *filp){/* 將檔案從非同步通知清單中刪除 */ globalmem_fasync( - 1, filp, 0); return 0;}static int globalfifo_fasync(int fd, struct file *filp, int mode){struct globalfifo_dev *dev = filp->private_data; return fasync_helper(fd, filp, mode, &dev->async_queue);}/*globalfifo寫操作*/static ssize_t globalfifo_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos){ struct globalfifo_dev *dev = filp->private_data; //獲得裝置結構體指標 int ret; DECLARE_WAITQUEUE(wait, current); //定義等待隊列 down(&dev->sem); //擷取訊號量 add_wait_queue(&dev->w_wait, &wait); //進入寫等待隊列頭 /* 等待FIFO非滿 */ if (dev->current_len == GLOBALFIFO_SIZE) { if (filp->f_flags &O_NONBLOCK) //如果是非阻塞訪問 { ret = - EAGAIN; goto out; } __set_current_state(TASK_INTERRUPTIBLE); //改變進程狀態為睡眠 up(&dev->sem); schedule(); //調度其他進程執行 if (signal_pending(current)) //如果是因為訊號喚醒 { ret = - ERESTARTSYS; goto out2; } down(&dev->sem); //獲得訊號量 } /*從使用者空間拷貝到核心空間*/ if (count > GLOBALFIFO_SIZE - dev->current_len) count = GLOBALFIFO_SIZE - dev->current_len; if (copy_from_user(dev->mem + dev->current_len, buf, count)) { ret = - EFAULT; goto out; } else { dev->current_len += count; printk(KERN_INFO "written %d bytes(s),current_len:%d\n", count, dev ->current_len); wake_up_interruptible(&dev->r_wait); //喚醒讀等待隊列 /* 產生非同步讀訊號 */ if (dev->async_queue) kill_fasync(&dev->async_queue, SIGIO, POLL_IN); ret = count; } out: up(&dev->sem); //釋放訊號量 out2:remove_wait_queue(&dev->w_wait, &wait); //從附屬的等待隊列頭移除 set_current_state(TASK_RUNNING); return ret;}下面再給出測試程式:
#include ...//接收到非同步讀訊號的動作void input_handler(int signum){ printf("Receive a signal from globalfifo,signalnum:%d\n",signum);}int main(){ int fd, oflags; fd = open("/dev/globalfifo", O_RDWR, S_IRUSR | S_IWUSR); if (fd != - 1) { //啟動訊號驅動機制 signal(SIGIO, input_handler); //讓input_handler()處理SIGIO訊號 fcntl(fd, F_SETOWN, getpid()); oflags = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, oflags | FASYNC); while(1) { sleep(100); } } else { printf("device open failure\n"); }}
當我們載入完驅動並建立完裝置節點後,運行上述程式,每當通過echo向/dev/globalfilfo寫入新的資料後,input_handler將會被調用。如下所示:echo 0>/dev/globalfiforeceive a signal from globalfifo ,signalnum:29 echo 0>/dev/globalfiforeceive a signal from globalfifo ,signalnum:29
echo 0>/dev/globalfiforeceive a signal from globalfifo ,signalnum:29
通過上邊實際的例子,小王,明白了吧,我的承諾也兌現了,下次咱們可要開始更進階的東西了..