linux驅動學習---loff_t 字段的迷惑


驅動模塊中有一個file結構體。該結構體中有一個 loff_t 字段 用來維護當前讀寫位置。此回就拿loff_t這個字段來開刀。下面展示一個字符設備的驅動代碼,來自《Linux設備驅動開發詳解》-宋寶華一書

  1 #include <linux/module.h>
  2 #include <linux/slab.h>
  3 #include <linux/types.h>
  4 #include <linux/fs.h>
  5 #include <linux/errno.h>
  6 #include <linux/mm.h>
  7 #include <linux/sched.h>
  8 #include <linux/init.h>
  9 #include <linux/cdev.h>
 10 #include <asm/io.h>
 11 #include <asm/system.h>
 12 #include <asm/uaccess.h>
 13 
 14 #define GLOBALMEM_SIZE    0x1000    /*全局內存最大4K字節*/
 15 #define MEM_CLEAR 0x1  /*清0全局內存*/
 16 #define GLOBALMEM_MAJOR 0    /*預設的globalmem的主設備號*/
 17 
 18 static globalmem_major = GLOBALMEM_MAJOR;
 19 /*globalmem設備結構體*/
 20 struct globalmem_dev                                     
 21 {                                                        
 22   struct cdev cdev; /*cdev結構體*/                       
 23   unsigned char mem[GLOBALMEM_SIZE]; /*全局內存*/     
 24   struct semaphore sem; /*並發控制用的信號量*/    
 25 };
 26 
 27 struct globalmem_dev *globalmem_devp; /*設備結構體指針*/
 28 
 29 /*文件打開函數*/
 30 int globalmem_open(struct inode *inode, struct file *filp)
 31 {
 32   /*將設備結構體指針賦值給文件私有數據指針*/
 33   filp->private_data = globalmem_devp;
 34   return 0;
 35 }
 36 
 37 /*文件釋放函數*/
 38 int globalmem_release(struct inode *inode, struct file *filp)
 39 {
 40   return 0;
 41 }
 42 
 43 /* ioctl設備控制函數 */
 44 static int globalmem_ioctl(struct inode *inodep, struct file *filp, unsigned
 45   int cmd, unsigned long arg)
 46 {
 47   struct globalmem_dev *dev = filp->private_data; /*獲得設備結構體指針*/
 48 
 49   switch (cmd)
 50   {
 51     case MEM_CLEAR:
 52       if (down_interruptible(&dev->sem))
 53       {
 54         return  - ERESTARTSYS;
 55       }
 56       memset(dev->mem, 0, GLOBALMEM_SIZE);
 57       up(&dev->sem); //釋放信號量
 58 
 59       printk(KERN_INFO "globalmem is set to zero\n");
 60       break;
 61 
 62     default:
 63       return  - EINVAL;
 64   }
 65   return 0;
 66 }
 67 
 68 /*讀函數*/
 69 static ssize_t globalmem_read(struct file *filp, char __user *buf, size_t size,
 70   loff_t *ppos)
 71 {
 72   unsigned long p =  *ppos;
 73   unsigned int count = size;
 74   int ret = 0;
 75   struct globalmem_dev *dev = filp->private_data; /*獲得設備結構體指針*/
 76 
 77   /*分析和獲取有效的寫長度*/
 78   if (p >= GLOBALMEM_SIZE)
 79     return count ?  - ENXIO: 0;
 80   if (count > GLOBALMEM_SIZE - p)
 81     count = GLOBALMEM_SIZE - p;
 82 
 83   if (down_interruptible(&dev->sem))
 84   {
 85     return  - ERESTARTSYS;
 86   }
 87 
 88   /*內核空間->用戶空間*/
 89   if (copy_to_user(buf, (void*)(dev->mem + p), count))
 90   {
 91     ret =  - EFAULT;
 92   }
 93   else
 94   {
 95     *ppos += count;
 96     ret = count;
 97 
 98     printk(KERN_INFO "read %d bytes(s) from %d\n", count, p);
 99   }
100   up(&dev->sem); //釋放信號量
101 
102   return ret;
103 }
104 
105 /*寫函數*/
106 static ssize_t globalmem_write(struct file *filp, const char __user *buf,
107   size_t size, loff_t *ppos)
108 {
109   unsigned long p = *ppos;
110   unsigned int count = size;
111   int ret = 0;
112 
113   struct globalmem_dev *dev = filp->private_data; /*獲得設備結構體指針*/
114 
115   /*分析和獲取有效的寫長度*/
116   if (p >= GLOBALMEM_SIZE)
117     return count ?  - ENXIO: 0;
118   if (count > GLOBALMEM_SIZE - p)
119     count = GLOBALMEM_SIZE - p;
120 
121   if (down_interruptible(&dev->sem))//獲得信號量
122   {
123     return  - ERESTARTSYS;
124   }
125   /*用戶空間->內核空間*/
126 
127      
128   if (copy_from_user(dev->mem + p, buf, count))
129     ret =  - EFAULT;
130   else
131   {
132      *ppos +=count;
133     ret = count;
134 
135     printk(KERN_INFO "written %d bytes(s) from %d\n", count, p);
136   }
137   up(&dev->sem); //釋放信號量
138   return ret;
139 }
140 
141 /* seek文件定位函數 */
142 static loff_t globalmem_llseek(struct file *filp, loff_t offset, int orig)
143 {
144   loff_t ret = 0;
145   switch (orig)
146   {
147     case 0:   /*相對文件開始位置偏移*/
148       if (offset < 0)
149       {
150         ret =  - EINVAL;
151         break;
152       }
153       if ((unsigned int)offset > GLOBALMEM_SIZE)
154       {
155         ret =  - EINVAL;
156         break;
157       }
158       filp->f_pos = (unsigned int)offset;
159       ret = filp->f_pos;
160       break;
161     case 1:   /*相對文件當前位置偏移*/
162       if ((filp->f_pos + offset) > GLOBALMEM_SIZE)
163       {
164         ret =  - EINVAL;
165         break;
166       }
167       if ((filp->f_pos + offset) < 0)
168       {
169         ret =  - EINVAL;
170         break;
171       }
172       filp->f_pos += offset;
173       ret = filp->f_pos;
174       break;
175     default:
176       ret =  - EINVAL;
177       break;
178   }
179   return ret;
180 }
181 
182 /*文件操作結構體*/
183 static const struct file_operations globalmem_fops =
184 {
185   .owner = THIS_MODULE,
186   .llseek = globalmem_llseek,
187   .read = globalmem_read,
188   .write = globalmem_write,
189   .ioctl = globalmem_ioctl,
190   .open = globalmem_open,
191   .release = globalmem_release,
192 };
193 
194 /*初始化並注冊cdev*/
195 static void globalmem_setup_cdev(struct globalmem_dev *dev, int index)
196 {
197   int err, devno = MKDEV(globalmem_major, index);
198 
199   cdev_init(&dev->cdev, &globalmem_fops);
200   dev->cdev.owner = THIS_MODULE;
201   dev->cdev.ops = &globalmem_fops;
202   err = cdev_add(&dev->cdev, devno, 1);
203   if (err)
204     printk(KERN_NOTICE "Error %d adding LED%d", err, index);
205 }
206 
207 /*設備驅動模塊加載函數*/
208 int globalmem_init(void)
209 {
210   int result;
211   dev_t devno = MKDEV(globalmem_major, 0);
212 
213   /* 申請設備號*/
214   if (globalmem_major)
215     result = register_chrdev_region(devno, 1, "globalmem");
216   else  /* 動態申請設備號 */
217   {
218     result = alloc_chrdev_region(&devno, 0, 1, "globalmem");
219     globalmem_major = MAJOR(devno);
220   }  
221   if (result < 0)
222     return result;
223     
224   /* 動態申請設備結構體的內存*/
225   globalmem_devp = kmalloc(sizeof(struct globalmem_dev), GFP_KERNEL);
226   if (!globalmem_devp)    /*申請失敗*/
227   {
228     result =  - ENOMEM;
229     goto fail_malloc;
230   }
231   memset(globalmem_devp, 0, sizeof(struct globalmem_dev));
232   
233   globalmem_setup_cdev(globalmem_devp, 0);
234   init_MUTEX(&globalmem_devp->sem);   /*初始化信號量*/  
235   return 0;
236 
237   fail_malloc: unregister_chrdev_region(devno, 1);
238   return result;
239 }
240 
241 /*模塊卸載函數*/
242 void globalmem_exit(void)
243 {
244   cdev_del(&globalmem_devp->cdev);   /*注銷cdev*/
245   kfree(globalmem_devp);     /*釋放設備結構體內存*/
246   unregister_chrdev_region(MKDEV(globalmem_major, 0), 1); /*釋放設備號*/
247 }
248 
249 MODULE_AUTHOR("Song Baohua");
250 MODULE_LICENSE("Dual BSD/GPL");
251 
252 module_param(globalmem_major, int, S_IRUGO);
253 
254 module_init(globalmem_init);
255 module_exit(globalmem_exit);


我們編譯這個模塊,然后insmod,mknod 之后,我們便可以開始寫測試程序來測試這個字符設備了

下面是我的第一個測試代碼

 1 #include<sys/types.h>
 2 #include<stdio.h>
 3 #include<unistd.h>
 4 #include<fcntl.h>
 5 
 6 int main()
 7 {
 8 
 9 
10     char buf[]="fuck gay";
11 
12 
13     int dev_fd=open("/dev/globalmem_lock",O_RDWR | O_NONBLOCK);
14     if(!write(dev_fd,buf,8))
15         printf("write error");
16     if(!write(dev_fd,buf,8))
17         printf("write error");
18 
19     
20     return 0;
21     
22 }

 

我們編譯運行這個代碼,如下所示

我們用cat 查看這個設備時 發覺,fuck gayfuck gay已經被正確的輸入到設備中,

但是如果此時,我們用echo命令向這個設備寫進東西,發覺會覆蓋掉原先寫進的內容,如下所示:

對於這種情況的唯一解釋是,每個進程都維護着自己獨有的loff_t 字段,所以當echo命令向該設備寫時,是從0開始寫的

但是我又遇到了一個問題,至今無法解決。源於我又寫了個測試程序如下

 1 #include<sys/types.h>
 2 #include<stdio.h>
 3 #include<unistd.h>
 4 #include<fcntl.h>
 5 
 6 int main()
 7 {
 8 
 9     pid_t pid;
10     char a[]="fuck";
11     char b[]="hello";
12         int dev_fd=open("/dev/globalmem_lock",O_RDWR | O_NONBLOCK);
13         if( ( pid=fork() ) <0)
14         printf("fork error\n");
15         else if(pid==0)    
16        {
17         if(!write(dev_fd,b,8))
18             printf("write error");
19         sleep(3);
20         if(!write(dev_fd,b,8))
21             printf("write error");
22            }
23     else
24        {    
25         if(!write(dev_fd,a,8))
26             printf("write error");
27            }
28         return 0;
29     
30 }


編譯這個代碼 運行 ,然后cat 該設備,得到如下結果

父子進程仿佛是在同時維護着一個loff_t字段,令我不得其解啊。。求路過大神指導

 -----------------------------------------------------------------------------------

經過一些的指點后我才知道我這個問題很二,也是因為對前面的知識遺忘的比較多。對上面問題的解答是,父子進程是共享一個文件描述符表的,而不同的進程是獨享

一個文件描述符表,現在上傳兩張圖,一看便知道

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM