依旧不喜欢用作业本做嵌入式的学习笔记,倒是用电脑写起来有点感觉。
1、cdev结构体
struct cdev{ struct kobject kobj; /*内嵌的kobject对象*/ struct module *owner; struct file_operations *ops; struct list_head list; dev_t dev; /*设备号*/ unsigned int count; }
2、分配和释放设备号
int register_chrev_region(dev_t from, unsigned count, const char *name); /*分配指定的设备号*/
int alloc_chrdev_region(dev_t *dev,unsigned baseminor, unsigned count, const char *name); /*由系统分配一个动态设备号*/
void unregister_chrdev_region(dev_t from, unsigned count); /*释放设备号*/
3、 file_operations 结构体 cdev常用
struct file_operations{ struct module *owner; loff_t(*llseek)(struct file *, loff_t, int); /*用来修改文件当前的读写位置*/ ssize_t(*read)(struct file *,char __user *, size_t, loff_t *); /*从设备中同步读数据*/ unsigned int(*poll)(struct file *, struct poll_table_struct*); /*轮询函数*/ int(*ioctl)(struct inode *,struct file *, unsigned int,unsigned long);/*ioctl 函数*/ int (*mmap)(struct inode *, struct file*); /*用于请求将设备内存映射到进程地址空间*/ int (*open)(struct inode *, struct file*); int(*release)(struct inode *, struct file*); int (*fasync)(int ,struct file *, int); /*通知设备FASYNC标志位发生变化*/ }
4、中断屏蔽
local_irq_diable() /*屏蔽中断*/ critical section /*临界区*/ local_irq_enable() /*开中断*/
由于Linux的异步I/O、进程调度等很多重要操作都依赖于中断,中断对于内核的运行非常重要,
在屏蔽中断期间所有的中断都无法得到处理,因此长时间屏蔽只能中断是很危险的,这就要求屏蔽
了中断之后,当前的内核执行路径应当尽快地执行完临界区的代码。它适宜和自旋锁联合使用。
5、整型原子操作
void atomic_set(atomic_t *v, int i); /*设置原子变量的值为i*/ atomic_t v = AROMIC_INIT(0); /*定义原子变量v 并初始化为0*/ atomic_read(atomic_t *v); /*返回原子变量的值*/ void atomic_add(int i, atomic_t *v); //原子变量加i void atomic_dec(int i, atomic_t *v); //原子变量减i void atomic_inc(atomic_t *v); //原子变量增加1 void atomic_dec(atomic_t *v); //原子变量减少1 操作测试 int atomic_inc_and_test(atomic_t *v); int atomic_dec_and_test(atomic_t *v); int atomic_sub_and_test(int i, atomic_t *v);
6、位原子操作
void set_bit(nr, void *addr); //设置位 void clear_bit(nr, void *addr); //清除位 void change_bit(nv, void *addr); //改变位 test_bit(nr, void *addr); //测试位
7、自旋锁 : 自旋锁(spin lock)是一种典型的对临界资源进行互斥访问的手段。
spinlock_t lock; //定义自旋锁 spin_lock_init(lock); //初始化自旋锁 spin_lock(lock); //获得自旋锁,能够获得锁,则马上返回,否则自旋等待持有者释放锁 spin_trylock(lock); // 获得自旋锁,能够获得锁,返回为真,否则立即返回为假,不自旋等待 spin_unlock(lock) //释放自旋锁 /*自旋锁一般使用方式*/ spinlock_t lock; spin_lock_init(&lock); spin_lock (&lock); /*获取自旋锁,保护临界区*/ . . . . /*临界区*/ spin_unlock (&lock); //解锁
尽管用了自旋锁可以保证临界区不受别的cpu和本cpu内的抢占进程打扰,但是得到锁的代码路径
在执行临界区的时候,还可能收到中断的底半部的影响。
1) 自旋锁实际上是一个忙等待
2)自旋锁可能导致系统死锁
3)自旋锁锁定器件不能调用可能引起进程调度的函数,如copy_from_user(), copy_to_user(), kmalloc(), msleep()等。
7.1、读写自旋锁 : 自旋锁的衍生锁读写自旋锁(rwlock)可允许读的并发。
7.2、顺序锁 : 是对读写锁的一种优化,读执行单元绝对不会被写执行单元阻塞。
7.3、读-拷贝-更新 RCU (read copy update)
8、信号量
struct semaphore sem; //定义信号量 void sema_init(struct semaphore *sem, int val); //初始化信号量 void down(struct semaphore * sem); //获得信号量,会导致睡眠,因此不能在中断上下文使用 int down_interruptible(struct semaphore *sem);//进入睡眠的进程可以被信号打断,而down()不会 int trylock(struct semaphore *sem); //尝试获得sem,如果获得立刻返回0,否则返回非0,不导致睡眠, 可以在中断的上下文使用 void up(struct semaphore * sem); //释放信号量 /*信号量的一般使用*/ DECLARE_MUTEX(mount_sem); //定义并初始化信号量的宏定义 down(&mount_sem); //获取信号量,保护临界区 . . . .. . critical section //临界区 . . . . . up(&mount_sem); //释放信号量