强调互斥机制
独占共享资源
获取互斥锁失败,也会触发上下文调度
强调信号机制 (同步)
生产者–消费者模型
获取信号量失败,触发上下文调度
服务于多个线程间的执行的逻辑顺序,选信号量
服务于共享资源,选互斥锁
加锁成本低,不释放cpu使用权
不会引起上下文调度,不存在此方面的开销
会引起进程/线程切换
加锁成本更高(上下文切换耗时在几十纳秒到几微秒之间),加锁失败时会释放 CPU 给其他线程
无法判断锁住的代码会执行多久时,首选互斥锁
确定被锁住的代码执行时间很短,使用自旋锁
struct mutex lock;2、初始化互斥锁
void mutex_init(mutex *lock);
参数:
- lock:指定要初始化的互斥锁
void mutex_lock(struct mutex *lock);
参数:
- lock:指定要加锁的互斥锁
int mutex_trylock(struct mutex *lock);
尝试获取一次互斥锁,获取成功返回“true”,获取失败返回“false”。程序继续往下执行
5、互斥锁解锁void mutex_unlock(struct mutex *lock);
参数:
- lock:指定要解锁的互斥锁
test.c
#include#include #include #include #include #include #include #include #include #include #include #include #define DTSLED_NAME "dtsled" #define LED_OFF 0 #define LED_ON 1 // 定义一组全局变量,用于存放映射得到的虚拟地址 static void __iomem *IMX6U_CCM_CCGR1; static void __iomem *SW_MUX_GPIO1_IO03; static void __iomem *SW_PAD_GPIO1_IO03; static void __iomem *GPIO1_DR; static void __iomem *GPIO1_GDIR; struct mutex lock; extern struct dtsled_dev dtsled; static void led_switch(u8 state) { u32 val = 0; if(state == LED_ON) { val = readl(GPIO1_DR); val &= (~(1<<3)); writel(val, GPIO1_DR); } else if(state == LED_OFF) { val = readl(GPIO1_DR); val |= (1<<3); writel(val, GPIO1_DR); } } static int dtsled_open(struct inode *inode, struct file *filp) { mutex_lock(&lock); // struct file 结构体定义在 include/linux/fs.h 中 // struct file 有一个成员(空指针):void *private_data printk("%s(%d):%sn", __FILE__, __LINE__, __func__); filp->private_data = &dtsled; return 0; } static int dtsled_release(struct inode *inode, struct file *filp) { //struct dtsled_dev *dev = (struct dtsled_dev *)filp->private_data; mutex_unlock(&lock); return 0; } static ssize_t dtsled_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos) { int ret; u8 databuf[1]; //struct dtsled_dev *dev = (struct dtsled_dev *)filp->private_data; printk("%s(%d):%sn", __FILE__, __LINE__, __func__); printk("%s(%d):buf=(%s), count=%dn", __FILE__, __LINE__, buf, count); ret = copy_from_user(databuf, buf, count); printk("%s(%d):databuf=(%s)n", __FILE__, __LINE__, databuf); if(ret < 0) { printk("Kernel write failed.rn"); return -1; } printk("%s(%d):%sn", __FILE__, __LINE__, __func__); led_switch(databuf[0]-'0'); return 0; } // 操作集结构体,是 struct cdev 的成员 static const struct file_operations dtsled_fops = { .owner = THIS_MODULE, .write = dtsled_write, .open = dtsled_open, .release = dtsled_release, }; // 自定义结构体类型来描述 LED struct dtsled_dev { dev_t devid; struct cdev cdev; // 用于注册字符设备,操作集结构体是其成员变量 struct file_operations dtsled_fops; // 操作集结构体 struct class *class; // 用于自动创建设备节点 struct device *device; // 用于自动创建设备节点 u32 major; u32 minor; struct device_node *nd; // 设备树结点,用来表示 LED 设备节点 }; // 自定结构体来描述 LED struct dtsled_dev dtsled; // 驱动入口函数 static int __init dtsled_init(void) { int ret = 0; int val = 0; const char *str; u32 regdata[10]; u8 i; // 1、使用新方法来获取设备号 dtsled.major = 0; if(dtsled.major) { dtsled.devid = MKDEV(dtsled.major, 0); ret = register_chrdev_region(dtsled.devid, 1, DTSLED_NAME); } else { ret = alloc_chrdev_region(&dtsled.devid, 0, 1, DTSLED_NAME); dtsled.major = MAJOR(dtsled.devid); dtsled.minor = MINOR(dtsled.devid); } if(ret < 0) { printk("%d:Register char dev error.rn", __LINE__); goto fail_devid; } // 2、添加(注册)字符设备 dtsled.cdev.owner = THIS_MODULE; // zhu yi liang ge qu di zhi fu ! cdev_init(&dtsled.cdev, &dtsled_fops); ret = cdev_add(&dtsled.cdev, dtsled.devid, 1); if(ret < 0) { goto fail_cdev; } // 3、自动创建设备节点,需要一个 struct class,一个 struct device dtsled.class = class_create(THIS_MODULE, DTSLED_NAME); if(IS_ERR(dtsled.class)) { ret = PTR_ERR(dtsled.class); goto fail_class; } // 第一个 NULL 表示副设备, 第二个 NULL 表示 drvdata dtsled.device = device_create(dtsled.class, NULL, dtsled.devid, NULL, DTSLED_NAME); if(IS_ERR(dtsled.device)) { ret = PTR_ERR(dtsled.device); goto fail_device; } // 4、设备树相关,读取属性值 dtsled.nd = of_find_node_by_path("/alpha_led"); if(dtsled.nd == NULL) { goto fail_findnd; } // 获取状态属性,注意是指针的指针 ret = of_property_read_string(dtsled.nd, "status", &str); if(ret) { printk("%d:failrn", __LINE__); goto fail_rs; } else { printk("%d:status = "%s"rn", __LINE__, str); } //huoqu shuxing ret = of_property_read_string(dtsled.nd, "compatible", &str); if(ret) { printk("%d:failrn", __LINE__); goto fail_rs; } else { printk("%d:compatible = "%s"rn", __LINE__, str); } // 获取 reg 属性, 也就是获取 u32 类型属性值的方法 ret = of_property_read_u32_array(dtsled.nd, "reg", regdata, 10); if(ret < 0) { printk("%d:failrn", __LINE__); goto fail_rs; } else { printk("< reg > = < "); for(i=0; i<10; i++) { printk("%#X ", regdata[i]); } printk(">rn"); } // 5、初始化 LED IMX6U_CCM_CCGR1 = of_iomap(dtsled.nd, 0); SW_MUX_GPIO1_IO03 = of_iomap(dtsled.nd, 1); SW_PAD_GPIO1_IO03 = of_iomap(dtsled.nd, 2); GPIO1_DR = of_iomap(dtsled.nd, 3); GPIO1_GDIR = of_iomap(dtsled.nd, 4); // 初始化 LED 相关寄存器 val = readl(IMX6U_CCM_CCGR1); val &= (~(3<<26)); val |= (3<<26); writel(val, IMX6U_CCM_CCGR1); writel(0X5, SW_MUX_GPIO1_IO03);//io mux writel(0x10B0, SW_PAD_GPIO1_IO03); // set electrical properity val = readl(GPIO1_GDIR); // set bit3, out val |= (1<<3); writel(val, GPIO1_GDIR); val = readl(GPIO1_DR); val &= (~(1<<3));//turn on led writel(val, GPIO1_DR); mutex_init(&lock); return 0; fail_rs: fail_findnd: device_destroy(dtsled.class, dtsled.devid); fail_device: class_destroy(dtsled.class); fail_class: cdev_del(&dtsled.cdev); fail_cdev: unregister_chrdev_region(dtsled.devid, 1); fail_devid: return ret; } // 出口函数 static void __exit dtsled_exit(void) { unsigned int val = 0; val = readl(GPIO1_DR); val |= (1<<3); // turn off led writel(val, GPIO1_DR); // 取消地址映射 iounmap(IMX6U_CCM_CCGR1); iounmap(SW_MUX_GPIO1_IO03); iounmap(SW_PAD_GPIO1_IO03); iounmap(GPIO1_DR); iounmap(GPIO1_GDIR); // 删除字符设备 cdev_del(&dtsled.cdev); // 释放设备号 unregister_chrdev_region(dtsled.devid, 1); // 删除设备 device_destroy(dtsled.class, dtsled.devid); // 删除类 class_destroy(dtsled.class); } // 注册出口函数和入口函数 module_init(dtsled_init); module_exit(dtsled_exit); MODULE_LICENSE("GPL");
app.c
#include#include #include #include int main(int argc, char *argv[]) { int error; int fd; if(argc != 3) { printf(" command error ! n"); return -1; } fd = open(argv[1], O_RDWR); if(fd < 0) { printf("%s(%d):fail to open file : %s !!!n", __FILE__, __LINE__, argv[1]); return -1; } error = write(fd,argv[2],sizeof(argv[2])); if(error < 0) { printf("%s(%d):write file error! n", __FILE__, __LINE__); close(fd); } printf("%s(%d):wait for 10s! n", __FILE__, __LINE__); sleep(10); printf("%s(%d):will release the dev! n", __FILE__, __LINE__); error = close(fd); if(error < 0) { printf("%s(%d):close file error! n", __FILE__, __LINE__); } return 0; }



