[2009.11.2]嚴重錯誤,kernel會自動poll driver是否有data給使用者,所以poll_wait函式會一直被呼叫,所以char driver只需註冊poll,open,release即可達到user space select的所有功能
前幾天跟同事討論到RTCP的事情時,突然腦中閃過一個想法,記得4年前有寫過一個小程式,可以定時把kernel的statics丟到user space, user space的program只用了select和read函式把資料讀出來並顯示在UI上,那時我以為poll_wait函式可以hang住user space process讓user space的程式可以等待kernel有資料時再讀出來,不過今天寫了一小段code發現自己觀念是錯的
poll_wait並不能hang住user process,當user process執行到select時,kernel會呼叫dirver註冊的poll方法,看看是否有資料可讀取,如果不行,會return 0給user process,poll方法的程式碼請看如下
- static unsigned int char_poll(struct file *file, poll_table *wait)
- {
- driver_private_data *dpd = file->private_data;
- int mask=0;
-
- //DBG();
-
- if (file->f_mode & FMODE_READ)
- {
- //dbg("file mode read\n");
- poll_wait(file, &dpd->wait, wait);
- if (dpd->flag==1)
- {
- mask |= POLLIN | POLLRDNORM;
- dpd->flag=0;
- }
- }
- return mask;
- }
當執行到poll_wait,kernel只會通知poll_table有process要讀/寫資料,但不會對process進行hang up動作,所以char_poll這個函式很快就return,除非當有資料可讀取(dpd->flag==1),它才會return mask |= POLLIN | POLLRDNORM通知user process有資料可讀取
[2009.11.2]select並不需要設定timeout value,application用select通知kernel hang住process,讓poll方法檢查是否有新的資料,那我以前寫的程式為什麼可以動?
回頭翻了一下以前的資料,我發現原來我用了interruptible_sleep_on和wake_up_interruptible,所以導致我有這樣的誤解……天阿…我到今天才發現,真該打屁股…底下是我今天寫的sample code,包含user space和kernel module
[char kernel module]
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/init.h>
- #include <linux/major.h>
- #include <linux/device.h>
- #include <linux/poll.h>
-
- #define dbg(fmt,args...) printk("[%s]:%d => "fmt,__FUNCTION__,__LINE__,##args)
- #define DBG() printk("[%s]:%d => \n",__FUNCTION__,__LINE__)
- #define DEVICE_NAME "charmodule"
- #define STRING_SIZE 256
- #define STRING_CHANGE_TIME 2 //seconds
-
- static int driver_major;
- static int string_counter=1;
-
- typedef struct _driver_private_data
- {
- wait_queue_head_t wait;
- struct fasync_struct *fasync;
- struct timer_list char_timer;
- char my_string[256];
- int flag;
-
- }driver_private_data;
-
- driver_private_data *gpd;
- void MyTimerFunction(unsigned long data);
-
- static ssize_t char_read(struct file *file, char __user *buffer,size_t count, loff_t *ppos)
- {
- int retval=0;
- driver_private_data *dpd = file->private_data;
-
- DBG();
- if (count<STRING_SIZE) return -EINVAL;
- while ((retval + STRING_SIZE)<= count)
- {
- if (copy_to_user(buffer, dpd->my_string, STRING_SIZE))
- return -EFAULT;
- retval += STRING_SIZE;
- }
- dpd->flag=0;
- return retval;
- }
-
- static ssize_t char_write(struct file *file, const char __user *buffer,size_t count, loff_t *ppos)
- {
- return STRING_SIZE;//just a demo, I dont implement this
- }
-
- static int char_open(struct inode *inode, struct file *file)
- {
-
- driver_private_data *dpd;
-
- DBG();
- dpd=(driver_private_data *)file->private_data;
- if (!dpd)
- {
- dpd=(driver_private_data *)kmalloc(sizeof(driver_private_data),GFP_ATOMIC);
- file->private_data=dpd;
- sprintf(dpd->my_string,"string_counter %d\n",string_counter);
- dpd->flag=0;
- string_counter++;
- init_waitqueue_head(&dpd->wait);
- gpd=dpd;
- init_timer(&dpd->char_timer);
- dpd->char_timer.function = MyTimerFunction;
- dpd->char_timer.expires = jiffies + STRING_CHANGE_TIME*HZ;
- dpd->char_timer.data = (unsigned long) gpd;
- add_timer(&dpd->char_timer);
- }
- return 0;
- }
- static unsigned int char_poll(struct file *file, poll_table *wait)
- {
- driver_private_data *dpd = file->private_data;
- int mask=0;
-
- //DBG();
-
- if (file->f_mode & FMODE_READ)
- {
- //dbg("file mode read\n");
- poll_wait(file, &dpd->wait, wait);
- if (dpd->flag==1)
- {
- mask |= POLLIN | POLLRDNORM;
- dpd->flag=0;
- }
- }
- return mask;
- }
-
- static int char_release(struct inode *inode, struct file *file)
- {
- driver_private_data *dpd;
-
- DBG();
- dpd=(driver_private_data *)file->private_data;
- del_timer(&dpd->char_timer);
- return 0;
- }
-
-
-
-
- static const struct file_operations chardev_fops =
- {
- .owner = THIS_MODULE,
- .read = char_read,
- .write = char_write,
- .poll = char_poll,
- .open = char_open,
- .release = char_release,
- };
-
- void MyTimerFunction(unsigned long data)
- {
- driver_private_data *dpd=(driver_private_data *)data;
- if (dpd)
- {
- sprintf(dpd->my_string,"string_counter %d\n",string_counter);
- string_counter++;
- //wake_up_interruptible(&dpd->wait);
- dpd->flag=1;
- init_timer(&dpd->char_timer);
- dpd->char_timer.function = MyTimerFunction;
- dpd->char_timer.expires = jiffies + STRING_CHANGE_TIME*HZ;
- dpd->char_timer.data = (unsigned long) dpd;
- add_timer(&dpd->char_timer);
- }
- }
-
- static int __init charmodule_init(void)
- {
-
- dbg("char module demo\n");
- driver_major=register_chrdev(0, DEVICE_NAME, &chardev_fops);
- if (driver_major<0)
- {
- dbg("Register character device failed\n");
- return -EFAULT;
- }
- else dbg("mknod /dev/%s c %d 0\n",DEVICE_NAME,driver_major);
-
-
- return 0;
- }
-
- static void __exit charmodule_exit(void)
- {
- unregister_chrdev(driver_major, DEVICE_NAME);
- dbg("remove driver successfully\n");
- }
- module_init(charmodule_init);
- module_exit(charmodule_exit);
-
- MODULE_DESCRIPTION("led module");
- MODULE_AUTHOR("Joey Cheng<jemicheng@gmail.com>");
- MODULE_LICENSE("GPL");
- MODULE_ALIAS("QT2410:char module");
[user space program]
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <sys/select.h>
- #include <unistd.h>
-
-
-
- int main()
- {
- fd_set myset,rset;
- int fd,i,width,count;
- char buf[1024];
- struct timeval tv;
-
- fd=open("/dev/charmodule",O_RDWR);
- if (fd<0)
- {
- printf("open failed\n");
- return;
- }
- FD_ZERO(&myset);
- FD_SET(fd,&myset);
- width=fd;
-
- //for (i=0;i<10;i++)
- while (1)
- {
- rset=myset;
- tv.tv_sec=0;
- tv.tv_usec=0;
- select(width+1,&rset,NULL,NULL,&tv);
- if (FD_ISSET(fd,&rset))
- {
- count=read(fd,buf,1024);
- printf("I have read %d bytes and data is %s\n",count,buf);
- }
- }
-
- }
程式碼打包在這邊下載
Regular expression-跟brainfuck差不多的東西 (2009-11-13 15:37)
Reading file in kernel-簡單但實用 (2009-10-13 15:18)
Linux file system for dummies-只花你45分鐘 (2009-08-19 15:40)
OPENSSL-TCP SSL初心者之路 (2009-07-16 15:16)
NAPI與pure interrupt driver的效能比較 (2009-04-29 19:06)
usermode helper-來自kernel的呼喚 (2009-04-21 16:19)
kernel module memory detector-抓出有害的kernel module (2009-03-31 13:50)
kernel space coding-如履薄冰 (2009-03-26 09:52)
readahead與posix_advise-預讀取是萬能靈丹? (2009-03-06 15:54)