Linux字符设备知识点/*嵌入式学习*/

依旧不喜欢用作业本做嵌入式的学习笔记,倒是用电脑写起来有点感觉。

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); //释放信号量











你可能感兴趣的:(linux)