1、设备驱动技术实验五嵌入式设备驱动技术课程实验报告班 级: 学 号: (需要填写) 姓 名: (需要填写) 指导老师: 成 绩: 实验五 Linux设备驱动中的并发控制一、目的与任务目的:了解Linux内核中的并发控制, 及熟悉并发与竞态、中断屏蔽、原子操作、自旋锁、信号量、互斥体机制。任务:增加并发控制后的globalmem模块的编程、编译与测试。二、内容、要求与安排方式1、实验内容与要求:1)原子操作; 2)自旋锁;3)信号量、互斥体机制。2、实验安排方式:采用1人1组,上机在Linux系统下进行编程实验。三、实验设备1、所用设备:PC机一台四、实验过程1)原子操作;所谓原子操作,就是该操作
2、绝不会在执行完毕前被任何其他任务或事件打断,也就说,它的最小的执行单位,不可能有比它更小的执行单位,因此这里的原子实际是使用了物理学里的物质微粒的概念。原子操作需要硬件的支持,因此是架构相关的,其API和原子类型的定义都定义在内核源码树的include/asm/atomic.h文件中,它们都使用汇编语言实现,因为C语言并不能实现这样的操作。原子操作主要用于实现资源计数,很多引用计数(refcnt)就是通过原子操作实现的。原子类型定义如下: volatile修饰字段告诉gcc不要对该类型的数据做优化处理,对它的访问都是对内存的访问,而不是对寄存器的访问。原子操作API包括:0.该函数对原子类型的
3、变量进行原子读操作,它返回原子类型的变量v的值。1.该函数设置原子类型的变量v的值为iatomic_set(atomic_t * v, int i);2.该函数给原子类型的变量v增加值i。void atomic_add(int i, atomic_t *v);3.该函数从原子类型的变量v中减去i。atomic_sub(int i, atomic_t *v);4.该函数从原子类型的变量v中减去i,并判断结果是否为0,如果为0,返回真,否则返回假。int atomic_sub_and_test(int i, atomic_t *v);5.该函数对原子类型变量v原子地增加1。void atomic_
4、inc(atomic_t *v);6.该函数对原子类型的变量v原子地减1void atomic_dec(atomic_t *v);7.该函数对原子类型的变量v原子地减1,并判断结果是否为0,如果为0,返回真,否则返回假。int atomic_dec_and_test(atomic_t *v);8.该函数对原子类型的变量v原子地增加1,并判断结果是否为0,如果为0,返回真,否则返回假。int atomic_inc_and_test(atomic_t *v);9.该函数对原子类型的变量v原子地增加I,并判断结果是否为负数,如果是,返回真,否则返回假。int atomic_add_negative(
5、int i, atomic_t *v);10.该函数对原子类型的变量v原子地增加i,并且返回指向v的指针。int atomic_add_return(int i, atomic_t *v);11.该函数从原子类型的变量v中减去i,并且返回指向v的指针。int atomic_sub_return(int i, atomic_t *v);12.该函数对原子类型的变量v原子地增加1并且返回指向v的指针。int atomic_inc_return(atomic_t * v);13.该函数对原子类型的变量v原子地减1并且返回指向v的指针。int atomic_dec_return(atomic_t *
6、v);2)自旋锁;自旋锁原语要求的包含文件是 . 一个实际的锁有类型 spinlock_t. 象任何其他数据结构, 一个 自旋锁必须初始化. 这个初始化可以在编译时完成, 如下: spinlock_t my_lock = SPIN_LOCK_UNLOCKED; 或者在运行时使用: void spin_lock_init(spinlock_t *lock);在进入一个临界区前, 你的代码必须获得需要的 lock , 用: void spin_lock(spinlock_t *lock);注意所有的自旋锁等待是, 由于它们的特性, 不可中断的. 一旦调用 spin_lock, 将自旋直到锁变为可用
7、.为释放一个已获得的锁, 传递它给:void spin_unlock(spinlock_t *lock);4 个函数可以加锁一个自旋锁: void spin_lock(spinlock_t *lock); void spin_lock_irqsave(spinlock_t *lock, unsigned long flags); void spin_lock_irq(spinlock_t *lock); void spin_lock_bh(spinlock_t *lock)4 个方法释放一个自旋锁void spin_unlock(spinlock_t *lock); void spin_unl
8、ock_irqrestore(spinlock_t *lock, unsigned long flags); void spin_unlock_irq(spinlock_t *lock); void spin_unlock_bh(spinlock_t *lock);阻塞的自旋锁操作: int spin_trylock(spinlock_t *lock); int spin_trylock_bh(spinlock_t *lock);2 种方式被声明和被初始化: rwlock_t my_rwlock = RW_LOCK_UNLOCKED; /* Static way */ rwlock_t my_
9、rwlock; rwlock_init(&my_rwlock); /* Dynamic way */3)信号量、互斥体机制。为了记录可用资源的数量,需要一个count计数,标记当前可用资源数量。需要一个count计数和等待进程的链表头即可。描述信号量的结构体如下。在linux中,需要一个结构体记录当前的进程信息(task_struct)。struct semaphore_waiter的list成员是当进程无法获取信号量的时候挂入semaphore的wait_list成员。task成员就是记录后续被唤醒的进程信息。一切准备就绪,现在就可以实现信号量的申请函数。(1).如果信号量标记的资源还有剩余
10、,自然可以成功获取信号量。只需要递减可用资源计数。(2).既然无法获取信号量,就需要将当前进程挂入信号量的等待队列链表上。(3).schedule()主要是触发任务调度的示意函数,主动让出CPU使用权。在让出之前,需要将当前进程从运行队列上移除。既然mutex是一种二值信号量,因此就不需要像semaphore那样需要一个count计数。由于mutex具有“持锁者才能解锁”的特点,所以我们需要一个变量owner记录持锁进程。释放锁的时候必须是同一个进程才能释放。当然也需要一个链表头,主要用来便利睡眠等待的进程。原理和semaphore及其相似,因此在代码上也有体现。struct mutex_wa
11、iter的list成员是当进程无法获取互斥量的时候挂入mutex的wait_list链表。首先实现申请互斥量的函数。(1).当mutex-owner的值为0的时候,代表没有任何进程持有锁。因此可以直接申请成功。然后,记录当前申请锁进程的task_struct。(2).既然不能获取互斥量,自然就需要睡眠等待,挂入等待链表。 互斥量的释放代码实现也同样和semaphore有很多相似之处。(1).mutex具有“持锁者才能解锁”的特点就是在这行代码体现。(2).如果等待链表没有进程,那么自然只需要将mutex-owner置0,代表没有锁是释放状态。(3).mutex-owner的值改成当前可以持锁进
12、程的task_struct。(4).从等待进程链表取出第一个进程,并从链表上移除。然后就是唤醒该进程。五、程序清单1)原子操作;原子操作函数如下:atomic_read(atomic_t * v);atomic_set(atomic_t * v, int i);void atomic_add(int i, atomic_t *v);atomic_sub(int i, atomic_t *v);int atomic_sub_and_test(int i, atomic_t *v);void atomic_inc(atomic_t *v);void atomic_dec(atomic_t *v);
13、int atomic_dec_and_test(atomic_t *v);int atomic_inc_and_test(atomic_t *v);int atomic_add_negative(int i, atomic_t *v);int atomic_add_return(int i, atomic_t *v);int atomic_sub_return(int i, atomic_t *v);int atomic_inc_return(atomic_t * v);int atomic_dec_return(atomic_t * v); 2)自旋锁;自旋锁函数spinlock_t my_
14、lock = SPIN_LOCK_UNLOCKED; void spin_lock_init(spinlock_t *lock);void spin_lock(spinlock_t *lock);void spin_unlock(spinlock_t *lock);void spin_lock(spinlock_t *lock); void spin_lock_irqsave(spinlock_t *lock, unsigned long flags); void spin_lock_irq(spinlock_t *lock); void spin_lock_bh(spinlock_t *lo
15、ck)void spin_unlock(spinlock_t *lock); void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags); void spin_unlock_irq(spinlock_t *lock); void spin_unlock_bh(spinlock_t *lock);int spin_trylock(spinlock_t *lock); int spin_trylock_bh(spinlock_t *lock);rwlock_t my_rwlock = RW_LOCK_UNLOCKED; /*
16、 Static way */ rwlock_t my_rwlock; rwlock_init(&my_rwlock); /* Dynamic way */3)信号量、互斥体机制。描述信号量的结构体struct semaphore unsigned int count; struct list_head wait_list;结构体记录当前的进程信息struct semaphore_waiter struct list_head list; struct task_struct *task;实现信号量的申请函数void down(struct semaphore *sem) struct sema
17、phore_waiter waiter; if (sem-count 0) sem-count-; /* 1 */ return; waiter.task = current; /* 2 */ list_add_tail(&waiter.list, &sem-wait_list); /* 2 */ schedule(); /* 3 */两个类似的结构体分别描述mutexstruct mutex_waiter struct list_head list; struct task_struct *task; struct mutex long owner; struct list_head wai
18、t_list;申请互斥量的函数void mutex_take(struct mutex *mutex) struct mutex_waiter waiter; if (!mutex-owner) mutex-owner = (long)current; /* 1 */ return; waiter.task = current; list_add_tail(&waiter.list, &mutex-wait_list); /* 2 */ schedule(); /* 2 */互斥量的释放代码int mutex_release(struct mutex *mutex) struct mutex_
19、waiter waiter; if (mutex-owner != (long)current) /* 1 */ return -1; if (list_empty(&mutex-wait_list) mutex-owner = 0; /* 2 */ return 0; waiter = list_first_entry(&mutex-wait_list, struct mutex_waiter, list); list_del(&waiter-list); mutex-owner = (long)waiter-task; /* 3 */ wake_up_process(waiter-task); /* 4 */ return 0;六、实验体会(需要填写)指导教师评语:
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1