博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
linux驱动学习---loff_t 字段的迷惑
阅读量:4651 次
发布时间:2019-06-09

本文共 7392 字,大约阅读时间需要 24 分钟。

驱动模块中有一个file结构体。该结构体中有一个 loff_t 字段 用来维护当前读写位置。此回就拿loff_t这个字段来开刀。下面展示一个字符设备的驱动代码,来自《Linux设备驱动开发详解》-宋宝华一书

1 #include 
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 #include
10 #include
11 #include
12 #include
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 else131 {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
2 #include
3 #include
4 #include
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
2 #include
3 #include
4 #include
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 else24 { 25 if(!write(dev_fd,a,8))26 printf("write error");27 }28 return 0;29 30 }

编译这个代码 运行 ,然后cat 该设备,得到如下结果

父子进程仿佛是在同时维护着一个loff_t字段,令我不得其解啊。。求路过大神指导

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

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

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

 

转载于:https://www.cnblogs.com/Blue-Moon/archive/2012/09/25/2702028.html

你可能感兴趣的文章