news 2026/1/14 11:13:10

基于 Linux 内核模块的字符设备互斥访问实验

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于 Linux 内核模块的字符设备互斥访问实验

这个信号量实验是基于 Linux 内核模块的字符设备互斥访问实验,核心是用信号量实现多进程对设备的互斥访问,步骤如下(含代码修正、编译、测试全流程):

一、环境准备

  1. 工具链与内核源码
    • 安装对应架构的交叉编译工具链(比如实验中ARCH=arm64,需安装aarch64-linux-gnu-)。
    • 准备开发板对应的Linux 内核源码,并记录其路径(后续MakefileKDIR需填写此路径)。

二、代码准备(修正实验中笔误)

将实验代码整理为 3 个文件:

1. 内核模块代码:semaphore_test.c

(修正semaphpresemaphoresleppsleep等笔误)

#include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/device.h> #include <linux/uaccess.h> #include <linux/delay.h> #include <linux/semaphore.h> struct semaphore semaphore_test; // 定义信号量 static int open_test(struct inode *inode, struct file *file) { printk("this is open_test \n"); down(&semaphore_test); // 获取信号量(值-1) return 0; } static ssize_t read_test(struct file *file, char __user *ubuf, size_t len, loff_t *off) { int ret; char kbuf[10] = "topeet"; // 内核缓冲区 printk("read_test \n"); ret = copy_to_user(ubuf, kbuf, strlen(kbuf)); // 内核→用户空间 if (ret != 0) { printk("copy_to_user is error \n"); } printk("copy_to_user is ok \n"); return 0; } static char kbuf[10] = {0}; // 全局内核缓冲区 static ssize_t write_test(struct file *file, const char __user *ubuf, size_t len, loff_t *off) { int ret; ret = copy_from_user(kbuf, ubuf, len); // 用户→内核空间 if (ret != 0) { printk("copy_from_user is error\n"); } if(strcmp(kbuf, "topeet") == 0) { // 传"topeet"则sleep4秒 sleep(4); } else if(strcmp(kbuf, "te") == 0) { // 传"te"则sleep2秒 sleep(2); } printk("copy_from_user buf is %s \n", kbuf); return 0; } static int release_test(struct inode *inode, struct file *file) { up(&semaphore_test); // 释放信号量(值+1) printk("this is release_test \n"); return 0; } // 字符设备结构 struct chrdrv_test { dev_t dev_num; // 设备号 int major, minor; // 主/次设备号 struct cdev cdev_test; // cdev结构 struct class *class_test; // 设备类 }; struct chrdrv_test devi; // 文件操作集合 static const struct file_operations fops_test = { .owner = THIS_MODULE, // 所属模块 .open = open_test, // 打开设备 .read = read_test, // 读设备 .write = write_test, // 写设备 .release = release_test // 释放设备 }; static int __init atomic_init(void) { sema_init(&semaphore_test, 1); // 初始化信号量(初始值1,互斥信号量) // 自动分配设备号 if(alloc_chrdev_region(&devi.dev_num, 0, 1, "chrdrv_name") < 0) { printk("alloc_chrdev_region is error \n"); return -1; } printk("alloc chrdrv region is ok \n"); devi.major = MAJOR(devi.dev_num); devi.minor = MINOR(devi.dev_num); printk("major is %d,minor is %d\n", devi.major, devi.minor); // 初始化cdev cdev_init(&devi.cdev_test, &fops_test); devi.cdev_test.owner = THIS_MODULE; cdev_add(&devi.cdev_test, devi.dev_num, 1); // 添加cdev到内核 // 创建设备类和设备文件 devi.class_test = class_create(THIS_MODULE, "class_test"); device_create(devi.class_test, NULL, devi.dev_num, NULL, "device_test"); return 0; } static void __exit atomic_exit(void) { device_destroy(devi.class_test, devi.dev_num); class_destroy(devi.class_test); cdev_del(&devi.cdev_test); unregister_chrdev_region(devi.dev_num, 1); } module_init(atomic_init); module_exit(atomic_exit); MODULE_LICENSE("GPL");
2. Makefile(编译内核模块)

makefile

export ARCH=arm64 export CROSS_COMPILE=aarch64-linux-gnu- obj-m = semaphore_test.o KDIR := /path/to/your/linux-kernel-source # 替换为实际内核源码路径 PWD ?= $(shell pwd) all: make -C $(KDIR) M=$(PWD) modules # 编译模块 clean: make -C $(KDIR) M=$(PWD) clean # 清理编译产物
3. 应用层测试代码:app.c
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <unistd.h> int main(int argc, char *argv[]) { int fd; char str[16] = {0}; // 打开设备文件(argv[1]是设备路径,如/dev/device_test) fd = open(argv[1], O_RDWR); if(fd < 0) { printf("file open failed \n"); return -1; } // 向设备写数据(argv[2]是要写入的内容,如"test") if (strcmp(argv[2], "test") == 0) { write(fd, "topeet", 10); } else if (strcmp(argv[2], "te") == 0) { write(fd, "te", 10); } close(fd); return 0; }

三、编译

  1. 编译内核模块:在semaphore_test.cMakefile所在目录执行:

    make

    生成semaphore_test.ko(内核模块文件)。

  2. 编译应用层程序:用交叉编译器编译app.c

    aarch64-linux-gnu-gcc app.c -o app

四、部署与测试(在开发板上操作)

  1. 上传文件:将semaphore_test.koapp传到开发板(比如用scp)。

  2. 加载内核模块

    insmod semaphore_test.ko

    执行dmesg查看输出,确认模块加载成功(会显示major is xxx, minor is 0等信息)。

  3. 测试互斥访问:打开2 个终端,分别运行测试程序:

    • 终端 1(写 "topeet",会 sleep4 秒):
      ./app /dev/device_test test
    • 终端 2(写 "te",会 sleep2 秒):
      ./app /dev/device_test te

    观察dmesg输出:终端 2 的进程会等待终端 1 的进程执行release_test(释放信号量)后,才会执行open_test(获取信号量),实现了多进程对设备的互斥访问。

五、收尾

测试完成后,卸载内核模块:

rmmod semaphore_test
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/1/14 7:04:56

Linux 字符设备驱动中 “主次设备号的静态 / 动态分配” 实验

这个实验是Linux 字符设备驱动中 “主次设备号的静态 / 动态分配” 实验&#xff0c;核心是验证 “手动指定设备号” 和 “内核自动分配设备号” 两种方式&#xff0c;步骤如下&#xff1a;一、环境准备和之前的信号量实验一致&#xff1a;安装对应架构的交叉编译工具链&#x…

作者头像 李华
网站建设 2026/1/11 23:55:07

Java毕设项目推荐-基于Spring Boot与MySQL的二手车销售管理系统的设计与实现基于Java和Spring Boot的二手车交易系统设计与实现【附源码+文档,调试定制服务】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/1/12 12:33:38

告别千篇一律:软文推广如何打造独特“新鲜感“?

在这个内容饱和的时代&#xff0c;软文同质化已成为品牌传播的首要障碍。新鲜感并非单纯的标新立异&#xff0c;而是一种系统性的内容创新思维——它要求我们突破既定的行业话语体系&#xff0c;以更深层的洞察、更本质的表达和更开放的互动&#xff0c;与受众建立全新的价值连…

作者头像 李华
网站建设 2026/1/12 12:33:36

有没有什么好办法让孩子坚持调节训练呢?

你是不是也跟很多家长一样&#xff0c;明明知道眼部调节训练能有效降低孩子近视的风险&#xff0c;却总被“孩子坚持不下来”的问题难住&#xff1f;要么是传统的“眼随手指前后移动”训练太枯燥&#xff0c;孩子坐几分钟就不耐烦&#xff1b;要么是需要专门抽时间&#xff0c;…

作者头像 李华
网站建设 2026/1/12 12:33:32

基于django+Vue的就业求职招聘信息平台

目录已开发项目效果实现截图关于博主开发技术路线相关技术介绍核心代码参考示例结论源码lw获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01;已开发项目效果实现截图 同行可拿货,招校园代理 ,本人源头供货商 基于djangoVue的就业求职招聘信息平台…

作者头像 李华