Linux设备驱动中的并发控制(四)

简介: Linux设备驱动中的并发控制(四)

前言

之前咱们不是自己写了个驱动globalmem的设备驱动嘛,不过当时只有简单的驱动文件描述符。这里我们不是学习了并发,于是这里给咱们的这个驱动增加上。

增加并发控制后的globalmem的设备驱动

在globalmem()的读写函数中,由于要调用copy_from_user()、copy_to_user()这些可能导致阻塞的函数,因此不能使用自旋锁,宜使用互斥体。(阻塞的就不适合用自旋锁)

驱动工程师习惯将某设备所使用的自旋锁、互斥体等辅助手段也放在设备结构中,因此,可如代码清单7.4那样修改globalmem_dev结构体的定义,并在模块初始化函数中初始化这个信号量,如代码清单7.5所示。

增加并发控制后的globalmem设备结构体

1struct globalmem_dev {
 2      struct cdev cdev;
 3      unsigned char mem[GLOBALMEM_SIZE];
 4      struct mutex mutex;
 5};

增加并发控制后的globalmem设备驱动模块加载函数

1static int __init globalmem_init(void)
 2 {
 3  int ret;
 4  dev_t devno = MKDEV(globalmem_major, 0);
 5
 6  if (globalmem_major)
 7       ret = register_chrdev_region(devno, 1, "globalmem");
 8  else {
 9       ret = alloc_chrdev_region(&devno, 0, 1, "globalmem");
10       globalmem_major = MAJOR(devno);
11  }
12  if (ret < 0)
13       return ret;
14
15  globalmem_devp = kzalloc(sizeof(struct globalmem_dev), GFP_KERNEL);
16  if (!globalmem_devp) {
17       ret = -ENOMEM;
18       goto fail_malloc;
19  }
20
21  mutex_init(&globalmem_devp->mutex);
22  globalmem_setup_cdev(globalmem_devp, 0);
23  return 0;
24
25 fail_malloc:
26  unregister_chrdev_region(devno, 1);
27  return ret;
28 }
29module_init(globalmem_init);

在访问globalmem_dev中的共享资源时,需先获取这个互斥体,访问完成后,随即释放这个互斥体。驱动中新的globalmem读、写操作如代码清单7.6所示。

增加并发控制后的globalmem读、写操作

1static ssize_t globalmem_read(struct file *filp, char __user * buf, size_t size,
 2              loff_t * ppos)
 3{
 4 unsigned long p = *ppos;
 5 unsigned int count = size;
 6 int ret = 0;
 7 struct globalmem_dev *dev = filp->private_data;
 8
 9 if (p >= GLOBALMEM_SIZE)
10      return 0;
11 if (count > GLOBALMEM_SIZE - p)
12      count = GLOBALMEM_SIZE - p;
13
14 mutex_lock(&dev->mutex);
15
16 if (copy_to_user(buf, dev->mem + p, count)) {
17      ret = -EFAULT;
18 } else {
19      *ppos += count;
20      ret = count;
21
22      printk(KERN_INFO "read %u bytes(s) from %lu\n", count, p);
23 }
24
25 mutex_unlock(&dev->mutex);
26
27 return ret;
28 }
29
30static ssize_t globalmem_write(struct file *filp, const char __user * buf,
31                size_t size, loff_t * ppos)
32 {
33 unsigned long p = *ppos;
34 unsigned int count = size;
35 int ret = 0;
36 struct globalmem_dev *dev = filp->private_data;
37
38 if (p >= GLOBALMEM_SIZE)
39      return 0;
40 if (count > GLOBALMEM_SIZE - p)
41      count = GLOBALMEM_SIZE - p;
42
43 mutex_lock(&dev->mutex);
44
45 if (copy_from_user(dev->mem + p, buf, count))
46      ret = -EFAULT;
47 else {
48      *ppos += count;
49      ret = count;
50
51      printk(KERN_INFO "written %u bytes(s) from %lu\n", count, p);
52 }
53
54 mutex_unlock(&dev->mutex);
55
56 return ret;
57 }

代码第14行和第43行用于获取互斥体,代码第25和54行用于在对临界资源访问结束后释放信号量。除了globalmem的读、写操作之外,如果在读、写的同时,另一个执行单元执行MEM_CLEAR IO控制命令,也会导致全局内存的混乱,因此,globalmem_ioctl()函数也需被重写,如代码清单7.7所示。

增加并发控制后的globalmem设备驱动ioctl()函数

1static long globalmem_ioctl(struct file *filp, unsigned int cmd,
 2             unsigned long arg)
 3{
 4 struct globalmem_dev *dev = filp->private_data;   /* μ éè±  á11ì      */
 5
 6 switch (cmd) {
 7 case MEM_CLEAR:
 8     mutex_lock(&dev->mutex);
 9     memset(dev->mem, 0, GLOBALMEM_SIZE);
10     mutex_unlock(&dev->mutex);
11
12     printk(KERN_INFO "globalmem is set to zero\n");
13     break;
14
15 default:
16     return -EINVAL;
17 }
18
19 return 0;
20}

增加并发控制后globalmem的完整驱动位于本书虚拟机的例子/kernel/drivers/globalmem/ch7目录下,其使用方法与第6章globalmem驱动在用户空间的验证一致。

总结

并发和竞态广泛存在,中断屏蔽、原子操作、自旋锁和互斥体都是解决并发问题的机制。中断屏蔽很少单独被使用,原子操作只能针对整数进行,因此自旋锁和互斥体应用最为广泛。

自旋锁会导致死循环,锁定期间不允许阻塞因此要求锁定的临界区小。互斥体允许临界区阻塞,可以适用于临界区大的情况。

内容来自:Linux设备驱动开发详解 感谢这些前辈的总结

目录
相关文章
|
24天前
|
Linux 网络安全 网络虚拟化
Linux虚拟网络设备:底层原理与性能优化深度解析
在深入探讨Linux虚拟网络设备的底层原理之前,重要的是要理解这些设备如何在Linux内核中实现,以及它们如何与操作系统的其他部分交互以提供高效且灵活的网络功能。虚拟网络设备在现代网络架构中发挥着关键作用🔑,特别是在云计算☁️、容器化📦和网络功能虚拟化(NFV)环境中。
Linux虚拟网络设备:底层原理与性能优化深度解析
|
24天前
|
Linux 网络虚拟化 虚拟化
Linux虚拟网络设备深度解析:使用场景、分类与开发者指南
Linux虚拟网络设备支撑着各种复杂的网络需求和配置,从基础的网络桥接到高级的网络隔离和加密🔐。以下是对主要Linux虚拟网络设备的介绍、它们的作用以及适用场景的概览,同时提出了一种合理的分类,并指出应用开发人员应该着重掌握的设备。
Linux虚拟网络设备深度解析:使用场景、分类与开发者指南
|
24天前
|
安全 Linux API
Linux设备模型统一:桥接硬件多样性与应用程序开发的关键
在Linux的宏大世界中,各种各样的硬件设备如星辰般繁多。从常见的USB设备到复杂的网络接口卡,从嵌入式设备到强大的服务器,Linux需要在这些差异极大的硬件上运行。这就引出了一个问题:Linux是如何统一这些不同硬件的设备模型的呢?本文将探讨Linux是如何针对不同的硬件统一设备模型的,这一统一的设备模型对于应用程序开发人员来说又有何意义。让我们一探究竟🕵️‍♂️。
Linux设备模型统一:桥接硬件多样性与应用程序开发的关键
|
2月前
|
Shell Linux C语言
【Shell 命令集合 设备管理 】Linux 创建设备文件 MAKEDEV命令 使用指南
【Shell 命令集合 设备管理 】Linux 创建设备文件 MAKEDEV命令 使用指南
35 0
|
2月前
|
监控 Linux Shell
【Shell 命令集合 网络通讯 】Linux管理终端设备的登录过程 getty命令 使用指南
【Shell 命令集合 网络通讯 】Linux管理终端设备的登录过程 getty命令 使用指南
34 0
|
2月前
|
监控 Linux Shell
【Shell 命令集合 磁盘维护 】Linux 交换分区的特殊文件或设备 swapon命令使用指南
【Shell 命令集合 磁盘维护 】Linux 交换分区的特殊文件或设备 swapon命令使用指南
40 1
|
23天前
|
Cloud Native Linux 网络虚拟化
深入理解Linux veth虚拟网络设备:原理、应用与在容器化架构中的重要性
在Linux网络虚拟化领域,虚拟以太网设备(veth)扮演着至关重要的角色🌐。veth是一种特殊类型的网络设备,它在Linux内核中以成对的形式存在,允许两个网络命名空间之间的通信🔗。这篇文章将从多个维度深入分析veth的概念、作用、重要性,以及在容器和云原生环境中的应用📚。
深入理解Linux veth虚拟网络设备:原理、应用与在容器化架构中的重要性
|
24天前
|
监控 中间件 Linux
深入Linux设备模型:开发者指南
Linux的设备模型是操作系统管理硬件设备的一种高级抽象,它不仅涉及到设备驱动程序的加载和卸载,还包括设备之间的关系、设备的状态管理以及与用户空间通信的机制。理解Linux的设备模型对于应用开发人员来说至关重要,它有助于开发出更加稳定、高效的应用程序。🌟
深入Linux设备模型:开发者指南
|
2月前
|
安全 Shell Linux
【Shell 命令集合 网络通讯 】Linux 打开终端设备 mingetty命令 使用指南
【Shell 命令集合 网络通讯 】Linux 打开终端设备 mingetty命令 使用指南
43 0
|
4天前
|
存储 监控 Linux
【专栏】如何在 Linux 中列出已安装的驱动器?
【4月更文挑战第28天】在 Linux 中,了解已安装驱动器是系统管理的关键。本文介绍了三种方法:1) 使用 `lsblk` 命令显示设备名、大小和类型;2) `fdisk -l` 命令提供详细分区信息;3) `gnome-disks` 等系统管理工具展示驱动器信息。此外,还讨论了驱动器类型识别、挂载点概念及其应用。通过这些方法,用户能有效地监控和管理 Linux 系统中的驱动器。