01
14

寫程式,花10分鐘,證明自己的觀念是錯的,無價

[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方法的程式碼請看如下

 

  1. static unsigned int char_poll(struct file *file, poll_table *wait)
  2. {
  3.  driver_private_data *dpd = file->private_data;
  4.  int mask=0;
  5.  
  6.  //DBG();
  7.  
  8.  if (file->f_mode & FMODE_READ)
  9.  {
  10.   //dbg("file mode read\n");
  11.   poll_wait(file, &dpd->wait, wait);
  12.   if (dpd->flag==1)
  13.   {
  14.    mask |= POLLIN | POLLRDNORM;
  15.    dpd->flag=0;
  16.   }
  17.  }
  18.  return mask;
  19. }

當執行到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]

  1. #include <linux/module.h> 
  2. #include <linux/kernel.h> 
  3. #include <linux/init.h> 
  4. #include <linux/major.h> 
  5. #include <linux/device.h> 
  6. #include <linux/poll.h> 
  7.  
  8. #define dbg(fmt,args...) printk("[%s]:%d => "fmt,__FUNCTION__,__LINE__,##args)
  9. #define DBG() printk("[%s]:%d => \n",__FUNCTION__,__LINE__)
  10. #define DEVICE_NAME "charmodule"
  11. #define STRING_SIZE 256
  12. #define STRING_CHANGE_TIME 2 //seconds
  13.  
  14. static int driver_major;
  15. static int string_counter=1;
  16.  
  17. typedef struct _driver_private_data 
  18. { 
  19. wait_queue_head_t wait;
  20. struct fasync_struct *fasync;
  21. struct timer_list char_timer;
  22. char my_string[256];
  23. int flag;
  24.  
  25. }driver_private_data;
  26.  
  27. driver_private_data *gpd;
  28. void MyTimerFunction(unsigned long data);
  29.  
  30. static ssize_t char_read(struct file *file, char __user *buffer,size_t count, loff_t *ppos) 
  31. { 
  32. int retval=0;
  33. driver_private_data *dpd = file->private_data;
  34.  
  35. DBG();
  36. if (count<STRING_SIZE) return -EINVAL;
  37. while ((retval + STRING_SIZE)<= count) 
  38. { 
  39. if (copy_to_user(buffer, dpd->my_string, STRING_SIZE)) 
  40. return -EFAULT;
  41. retval += STRING_SIZE;
  42. } 
  43. dpd->flag=0;
  44. return retval;
  45. } 
  46.  
  47. static ssize_t char_write(struct file *file, const char __user *buffer,size_t count, loff_t *ppos) 
  48. { 
  49. return STRING_SIZE;//just a demo, I dont implement this
  50. } 
  51.  
  52. static int char_open(struct inode *inode, struct file *file) 
  53. { 
  54.  
  55. driver_private_data *dpd;
  56.  
  57. DBG();
  58. dpd=(driver_private_data *)file->private_data;
  59. if (!dpd) 
  60. { 
  61. dpd=(driver_private_data *)kmalloc(sizeof(driver_private_data),GFP_ATOMIC);
  62. file->private_data=dpd;
  63. sprintf(dpd->my_string,"string_counter %d\n",string_counter);
  64. dpd->flag=0;
  65. string_counter++;
  66. init_waitqueue_head(&dpd->wait);
  67. gpd=dpd;
  68. init_timer(&dpd->char_timer);
  69. dpd->char_timer.function = MyTimerFunction;
  70. dpd->char_timer.expires = jiffies + STRING_CHANGE_TIME*HZ;
  71. dpd->char_timer.data = (unsigned long) gpd;
  72. add_timer(&dpd->char_timer);
  73. } 
  74. return 0;
  75. } 
  76. static unsigned int char_poll(struct file *file, poll_table *wait) 
  77. { 
  78. driver_private_data *dpd = file->private_data;
  79. int mask=0;
  80.  
  81. //DBG();
  82.  
  83. if (file->f_mode & FMODE_READ) 
  84. { 
  85. //dbg("file mode read\n");
  86. poll_wait(file, &dpd->wait, wait);
  87. if (dpd->flag==1) 
  88. { 
  89. mask |= POLLIN | POLLRDNORM;
  90. dpd->flag=0;
  91. } 
  92. } 
  93. return mask;
  94. } 
  95.  
  96. static int char_release(struct inode *inode, struct file *file) 
  97. { 
  98. driver_private_data *dpd;
  99.  
  100. DBG();
  101. dpd=(driver_private_data *)file->private_data;
  102. del_timer(&dpd->char_timer);
  103. return 0;
  104. } 
  105.  
  106.  
  107.  
  108.  
  109. static const struct file_operations chardev_fops =
  110. { 
  111. .owner = THIS_MODULE,
  112. .read = char_read,
  113. .write = char_write,
  114. .poll = char_poll,
  115. .open = char_open,
  116. .release = char_release,
  117. };
  118.  
  119. void MyTimerFunction(unsigned long data) 
  120. { 
  121. driver_private_data *dpd=(driver_private_data *)data;
  122. if (dpd) 
  123. { 
  124. sprintf(dpd->my_string,"string_counter %d\n",string_counter);
  125. string_counter++;
  126. //wake_up_interruptible(&dpd->wait);
  127. dpd->flag=1;
  128. init_timer(&dpd->char_timer);
  129. dpd->char_timer.function = MyTimerFunction;
  130. dpd->char_timer.expires = jiffies + STRING_CHANGE_TIME*HZ;
  131. dpd->char_timer.data = (unsigned long) dpd;
  132. add_timer(&dpd->char_timer);
  133. } 
  134. } 
  135.  
  136. static int __init charmodule_init(void) 
  137. { 
  138.  
  139. dbg("char module demo\n");
  140. driver_major=register_chrdev(0, DEVICE_NAME, &chardev_fops);
  141. if (driver_major<0) 
  142. { 
  143. dbg("Register character device failed\n");
  144. return -EFAULT;
  145. } 
  146. else dbg("mknod /dev/%s c %d 0\n",DEVICE_NAME,driver_major);
  147.  
  148.  
  149. return 0;
  150. } 
  151.  
  152. static void __exit charmodule_exit(void) 
  153. { 
  154. unregister_chrdev(driver_major, DEVICE_NAME);
  155. dbg("remove driver successfully\n");
  156. } 
  157. module_init(charmodule_init);
  158. module_exit(charmodule_exit);
  159.  
  160. MODULE_DESCRIPTION("led module");
  161. MODULE_AUTHOR("Joey Cheng<jemicheng@gmail.com>");
  162. MODULE_LICENSE("GPL");
  163. MODULE_ALIAS("QT2410:char module");

[user space program]

  1. #include <stdio.h> 
  2. #include <sys/types.h> 
  3. #include <sys/stat.h> 
  4. #include <fcntl.h> 
  5. #include <sys/select.h> 
  6. #include <unistd.h> 
  7.  
  8.  
  9.  
  10. int main() 
  11. { 
  12. fd_set myset,rset;
  13. int fd,i,width,count;
  14. char buf[1024]; <br/>struct timeval tv;
  15.  
  16. fd=open("/dev/charmodule",O_RDWR);
  17. if (fd<0) 
  18. { 
  19. printf("open failed\n");
  20. return;
  21. } 
  22. FD_ZERO(&myset);
  23. FD_SET(fd,&myset);
  24. width=fd;
  25.  
  26. //for (i=0;i<10;i++)
  27. while (1) 
  28. { 
  29. rset=myset;
  30. tv.tv_sec=0;
  31. tv.tv_usec=0;
  32. select(width+1,&rset,NULL,NULL,&tv);
  33. if (FD_ISSET(fd,&rset)) 
  34. { 
  35. count=read(fd,buf,1024);
  36. printf("I have read %d bytes and data is %s\n",count,buf);
  37. } 
  38. } 
  39.  
  40. }

程式碼打包在這邊下載

標籤: linux
評論: 0 | 引用: 0 | 閱讀: 9866
發表評論
暱 稱: 密 碼:
網 址: E - mail:
驗證碼: 驗證碼圖片 選 項:
頭 像:
內 容: