【1】复习
1. led驱动
readl & writel
2. regster_chrdev & unregister_chrdev
3.
kmalloc kzalloc kfree
vmalloc vzalloc vfree
__get_free_page & __get_free_pages
--->>> get_order();
4. 并发竟态
同步互斥
中断屏蔽
自旋锁
原子操作
===========================
信号量
互斥体
【2】作业
【一】、信号量
<linux/semaphore.h>
struct semaphore 信号量结构体数据类型
//初始化信号量的值
void sema_init(struct semaphore *sem, int val)
//减操作
void down(struct semaphore *sem);
//可中断(被信号)
int down_interruptible(struct semaphore *sem);
//加操作
void up(struct semaphore *sem);
down(); --->>> 减失败 --->>> 进程睡眠 (down -->>> D(进程状态))
down_interruptible() 减失败 --->>> 进程睡眠 (down -->>> S(进程状态))
临界区
up();
【二】、互斥体
<linux/mutex.h>
struct mutex //互斥体数据类型
mutex_init(struct mutex * mutex) //初始化互斥体
//上锁
void mutex_lock(struct mutex *lock)
//解锁
void mutex_unlock(struct mutex *lock)
mutex_lock()
临界区
mutex_unlock();
【三】、IO模型
阻塞 --->>> 进程休眠(D S)
条件不满足的时候,进程休眠等
非阻塞
条件不满足的时候,错误返回
IO多路复用
异步通知
【四】、阻塞
1. 找一个固定的地方 --->>> 等待队列头 wait_queue_head_t
//定义并初始化等待队列头(变量名)
#define DECLARE_WAIT_QUEUE_HEAD(name) \
wait_queue_head_t name = { \
.lock = __SPIN_LOCK_UNLOCKED(name.lock), \
.task_list = { &(name).task_list, &(name).task_list }
}
//初始化等待队列头
init_waitqueue_head(wait_queue_head_t *q)
2. 定义一个等待队列项 --- wait_queue_t
--->>> 进程相关信息(task_struct)
/*******************************************************************
*功能:初始化等待队列项
*参数:
* @q 等待队列项结构体指针
* @p task_struct结构体指针
*返回值:void
******************************************************************/
void init_waitqueue_entry(wait_queue_t *q, struct task_struct *p)
3. 将等待队列项挂在等待队列头上
//将等待队列项挂在等待队列头上
void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
4. 设置进程的状态 --->>> S/D
<linux/sched.h>
set_current_state(state_value)
TASK_RUNNING
TASK_INTERRUPTIBLE
TASK_UNINTERRUPTIBLE
5. -----调度 ------
void schedule(void)
6. 一旦唤醒,往下执行
7. 将等待队列项从等待队列头移除
void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
8. 设置进程的状态 (R)
--->>> 读数据
---------------------------条件满足----------------------------------
1. 唤醒
wake_up(wait_queue_head_t *x)
wake_up_interruptible(wait_queue_head_t *x)
=======================================================================================
1. 简化版的阻塞实现
/**************************************************
*功能:实现阻塞 --->>> D :不可中断睡眠态
*参数:
* @wq
* @condition 阻塞条件(非零为真)
*************************************************/
wait_event(wait_queue_head_t wq, condition)
wait_event_interruptible(wq, condition)
【五】、非阻塞
条件不满足的时候,错误返回
return -errno;
O_NONBLOCK
open("xxxx",O_RDWR | O_NONBLOCK); --->>> struct file
struct file {
unsigned int f_flags;
}
if(filp->f_flags & O_NONBLOCK){
return -errno;
}
【六】、IO多路复用
1. 网络学习IO多路复用
select poll epoll --->>> io多路复用的接口
2. 解决什么问题
server: client:
int main() int main()
{ {
socket(); socket();
bind(); ...
accept(); connet();
...
while(1){ while(1){
gets();
send(); recv();
gets();
recv(); send();
} }
} }
gets 和 recv 相互阻塞的问题
gets : 条件不满足阻塞 , 条件满足,从标准输入获取数据
recv : 条件不满足阻塞 , 条件满足,接收数据
wait()监控gets和recv的阻塞,如果其中有一个返回,wait返回,否则阻塞
server: client:
int main() int main()
{ {
socket(); socket();
bind(); ...
accept(); connet();
...
while(1){ while(1){
wait(0,sockfd); wait(0,sockfd);
gets(); if(gets条件满足)
gets();send();
send(); if(recv条件满足)
recv();
recv();
} }
} }
--->>> read 阻塞 select() --->>> man select
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
条件满足或不满足是驱动知道
select --->>> 调用驱动的某一个接口来确定是否条件满足
找到驱动的io多路复用接口 --->>> 完成接口
(open --->>> fops->open)
select --->>> fops -> poll
fs/select.c
SYSCALL_DEFINE5(select, int, n, fd_set __user *, inp, fd_set __user *, outp,
fd_set __user *, exp, struct timeval __user *, tvp)
--->>> core_sys_select(n, inp, outp, exp, to);