loff_t解析和单个进程和父子进程之间是如何处理文件描述符的

转自:http://www.cnblogs.com/Blue-Moon/archive/2012/09/25/2702028.html

驱动模块中有一个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字段,令我不得其解啊。。求路过大神指导

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

经过一些的指点后我才知道我这个问题很二,也是因为对前面的知识遗忘的比较多。对上面问题的解答是,父子进程是共享一个文件描述符表的,而不同的进程是独享

一个文件描述符表,现在上传两张图,一看便知道

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值