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设备驱动开发详解 感谢这些前辈的总结

目录
相关文章
|
1月前
|
缓存 Linux 开发者
Linux内核中的并发控制机制:深入理解与应用####
【10月更文挑战第21天】 本文旨在为读者提供一个全面的指南,探讨Linux操作系统中用于实现多线程和进程间同步的关键技术——并发控制机制。通过剖析互斥锁、自旋锁、读写锁等核心概念及其在实际场景中的应用,本文将帮助开发者更好地理解和运用这些工具来构建高效且稳定的应用程序。 ####
41 5
|
1月前
|
Linux 数据库
Linux内核中的锁机制:保障并发操作的数据一致性####
【10月更文挑战第29天】 在多线程编程中,确保数据一致性和防止竞争条件是至关重要的。本文将深入探讨Linux操作系统中实现的几种关键锁机制,包括自旋锁、互斥锁和读写锁等。通过分析这些锁的设计原理和使用场景,帮助读者理解如何在实际应用中选择合适的锁机制以优化系统性能和稳定性。 ####
59 6
|
4月前
|
NoSQL Unix Linux
Linux 设备驱动程序(一)(上)
Linux 设备驱动程序(一)
168 62
|
4月前
|
Java Linux API
Linux设备驱动开发详解2
Linux设备驱动开发详解
54 6
|
4月前
|
消息中间件 算法 Unix
Linux设备驱动开发详解1
Linux设备驱动开发详解
58 5
|
4月前
|
存储 缓存 Unix
Linux 设备驱动程序(三)(上)
Linux 设备驱动程序(三)
50 3
|
4月前
|
缓存 安全 Linux
Linux 设备驱动程序(一)((下)
Linux 设备驱动程序(一)
47 3
|
4月前
|
安全 数据管理 Linux
Linux 设备驱动程序(一)(中)
Linux 设备驱动程序(一)
34 2
|
4月前
|
Linux
Linux 设备驱动程序(四)
Linux 设备驱动程序(四)
31 1
|
4月前
|
存储 数据采集 缓存
Linux 设备驱动程序(三)(中)
Linux 设备驱动程序(三)
49 1
下一篇
DataWorks