概念:将进程访问临界资源的过程看作一个不可分割的原子状态,只有当进程访问完毕之后从内部打破,原子状态可以通过对于原子变量数据的修改来实现,原子变量的修改是通过一个内联汇编的形式来实现
定义原子变量并进行初始化
atomic_t atm=ATOMIC_INIT(1)
int atomic_dec_and_test(atomic *v)
功能:将原子变量数值-1并与0比较
v:原子变量的指针
返回值,如果原子变量-1的值返回0则为真,否则为假
void atomic_inc(atomic_t *v)
将原子变量数值+1;
*******************************************
atomic_t atm=ATOMIC_INIT(-1)
int atomic_inc_and_test(atomic *v)
功能:将原子变量数值+1并于0去比较
返回值,如果原子变量+1的值为0则返回真,否则返回假
void atomic_t dec(atomic_t *v)
将原子变量的数值+1
非阻塞IO
在open函数打开文件的时候以O_NONBLOC的模式打开文件,此时的文件描述符属性为非阻塞的,当读取硬件数据时,不管数据有没有准备好,驱动中直接读取硬件寄存器的数据,然后将数据拷贝到用户空间,用户读走即可,但这种方式不一定是准确的,因为不关注硬件数据是否准备好了
int fd=open("/dev/mycdev",O_RDWR|O_NONBLOCK);
阻塞IO
当用户程序调用read()函数读取硬件数据,在驱动中判断硬件数据有没有准备好,让进程阻塞在read()函数的位置,当硬件数据准备好了之后,驱动中将阻塞的进程唤醒,把准备好的硬件数据通过copy to user拷贝到用户空间
休眠态有两种方式
D uninterruptible sleep (usually IO) //不可中断休眠态
S interruptible sleep //可中断的休眠态,可以被信号中断
实现原理
1 构建等待队列并初始化
2 判断condition的值,为真,则表示数据准备好了,此时不让进程切换到休眠状态,直接将数据拷贝到用户空间,如果condition的值为假,此时将进程的task_strcut插入到等待队列中并且让进程切换为休眠状态(可中断休眠态,不可中断休眠态)
当硬件数据准备好了之后,硬件发起一个中断,在中断处理函数中将condition设置为1,并且将休眠的进程进行唤醒
相关的API
定义等待队列头并且初始化
wait_queue_head_t wq_head
init_waitqueue_head(&wq_head) //初始化
2 wait_event(wq_head,condition)
功能:让进程切换为不可中断的休眠状态,在这个函数中首先会判读condition,如果
condition为真,则不将进程切换为休眠态
返回值:如果被一个信号中断则返回-ERESTARTSYS,如果被正常唤醒则返回0
wake up(&wq_head)
功能:唤醒不可中断的休眠态进程,
wake_up_interruptible(&wq_head)
IO多路复用
IO多路复用机制:select\poll\epoll
当通过IO多路复用机制同时监听多个硬件数据时,如果没有一个硬件数据达到,此时将进程切换为休眠态(可中断休眠态)。当一个或多个硬件数据就绪后,将休眠的进程唤醒,进程再根据准备好的硬件数据对应的文件描述符将准备好的数据读走即可
************************************************************************
VFS(虚拟文件系统层)
sys_select()
1.在内核中申请一块内存,用于存放从用户拷贝下来的文件描述符集合
2.通过循环遍历文件描述符表,针对每一个文件描述符,按照fd->fd_array[fd]->struct file->f_op->poll() 路线调用每一个文件描述符对应的驱动中中poll方法
3.判断每个文件描述符对应的poll方法的返回值,如果所有poll方法的返回值都为0,表示没有任何事件发生
4.如果所有文件描述符对应的返回值否为0,此时将该进程进入休眠状态(可中断休眠态)
5.如果收到一个或多个文件描述符对应的事件唤醒操作,此时可重新遍历文件描述符表,找出发生事件的文件描述符
6.将发生事件的文件描述符拷贝到用户空间
7.用户空间针对发生事件的文件描述符将数据读走即可
驱动程序
//对于各种IO多路复用机制,驱动中对应的操作方法只用一个:poll方法
__poll_t (*poll) (struct file *file,struct poll_table_struct *wait)
{
//向上提交等待对列头
void poll_wait(struct file *filp,wait_queue_head_t * wait_address,poll_table *p)
参数:
filp:文件结构体指针
wait_address: 等待对垒头节点的地址
p:驱动连接的上层的通道
if(condition)
return POLLIN; //POLLIN代表读事件,POLLOUT代表写事件
else
return 0;
}