Chinaunix首页 | 论坛 | 博客
  • 博客访问: 844641
  • 博文数量: 321
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 936
  • 用 户 组: 普通用户
  • 注册时间: 2013-02-23 11:25
文章分类

全部博文(321)

文章存档

2017年(1)

2016年(10)

2015年(61)

2014年(187)

2013年(62)

分类: 嵌入式

2013-03-07 22:37:32


一、进程的状态

a) 就绪:从等待过来的,当给他分配处理器(CPU)和时间片,就能到达执行状态了。

b) 执行:可以转成就绪和等待状态。当正在执行的进程因发生某等待事件而无法执行,则进程由执行状态变为等待状态。当正在执行的进程,因时间片用完而被暂停执行,或在采用抢先式优先级调度算法的系统中,当有更高优先级的进程要运行而被迫让出处理机时,该进程便由执行状态转变为就绪状态。

c) 等待:不能马上进入执行状态,要先转为就绪。等到时间片和分配到CPU,才可以执行。


二、

TASK_RUNNING ---就绪

TASK_INTERRUPTIBLE  ---可被信号打断的休眠

TASK_UNINTERRUPTIBLE---不可被信号打断的休眠

TASK_STOPPED---挂起

当进程处于TASK_INTERRUPTIBLE TASK_UNINTERRUPTIBLE 状态时,称进程 睡眠(进程阻塞)。

三、直接改变进程状态的方法:

a) DECLARE_WAITQUEUE(wait,current);//3current,本进程,把本进程定义成等待队列

b) __set_current_state(TASK_INTERRUPTIBLE)是阻塞时改变进程状态为睡眠

schedule( );  调度其他进程执行,让出CPU,进入休眠,程序不再执行

c) current->state = TASK_INTERRUPTIBLE;

schedule( ); //让出CPU,进入休眠

被信号唤醒。

四、阻塞与非阻塞I/O----------------可通过信号唤醒(要做判断)

阻塞操作:在执行设备操作时若不能获得资源则挂起进程,直到满足可操作的条件后再进行操作。  如果进程调用read,但没有数据或数据不足,进程阻塞。当数据到达时,进程被唤醒,并将数据返回给调用者。(没有数据可读)===阻塞效率更高。让出CPU给其他工作

非阻塞操作:在执行设备操作时若不能获得资源时并不挂起,它或者放弃,或者不停地查询直到可以进行操作为止。如果进程调用了write但设备没有足够缓冲区,进程阻塞。当数据被读出设备后,缓冲区中空出部分空间,则唤醒进程。(没空间可写)

Linux驱动程序设计中,可以使用等待队列来实现进程的阻塞。

Current:代表本进程

五、使用等待队列有3种方法:

1   亲自进行进程状态的改变和切换。---=====schedule

2:  使用wait_event_interruptible(dev->r_wait,flag_r!=0);需要设置flag_r---例子4globalfifo_2

3:  使用interruptible_sleep_on(&dev->r_wait);---例子4globalfifo_2

唤醒的时候都是wake_up_interruptible

流程:

1、定义并初始化一个等待队列,将进程状态改变为TASK_UNINTERRUPTIBLE(不能被信号打断)或TASK_INTERRUPTIBLE(可被信号打断),并将等待队列添加到等待队列头。

2、通过schedule()放弃CPU调度其他进程执行。

3、进程被其他地方唤醒,将等待队列移出等待对列头。

代码:

1、定义:

unsigned int current_len;//记录fifo中的数据的有效长度

wait_queue_head_t r_wait;//1阻塞读用的等待队列头

wait_queue_head_t w_wait;//1阻塞写用的等待队列头

2、初始化:

init_waitqueue_head(&globalmem_devp->r_wait);//2初始化读等待 队列头

init_waitqueue_head(&globalmem_devp->w_wait);//2初始化写等待 队列头

globalmem_devp->current_len = 0;

3、声明一个等待队列:

DECLARE_WAITQUEUE(wait,current);//current,本进程,把本进程定义 成等待队列

4、添加到等待队列:

add_wait_queue(&dev->r_wait,&wait);//4进入读等待队列头

5、判断是否可读或者可写:

if(dev->current_len == 0)//说明缓存GLOBALMEM_SIZE为0,无数据 可读

if(dev->current_len == GLOBALMEM_SIZE)//说明缓存GLOBALMEM_SIZE 为16字节,无空间进行写

6、设置成状态:

__set_current_state(TASK_INTERRUPTIBLE);//5是阻塞时改变进程状 态为睡眠

7、让出CPU,让其进入真正睡眠:

schedule();//6调度其他进程执行,让出CPU,进入休眠,程序不再执行

8、醒过来了。判断是信号唤醒的还是进程唤醒的,即判断是真的可读写还 是信号打断:
if(signal_pending(current))

9内存移动(read):

memcpy(dev->mem,dev->mem+count,dev->current_len-count);

10、唤醒:

读唤醒写:

wake_up_interruptible(&dev->w_wait);

写唤醒读:

wake_up_interruptible(&dev->r_wait);

附:使用等待队列有3种方法:

1:亲自进行进程状态的改变和切换。

2:使用wait_event_interruptible(dev->r_wait,flag_r!=0);需要设 置flag_r。

3:使用interruptible_sleep_on(&dev->r_wait);

2和3两种是不可中断的。===虽然简单,但是效率低,所以用上面方法 多。

I/O非阻塞(轮询)

一、使用非阻塞I/O,同时使用select()和poll()系统调用查询是否可对设备进行无阻塞操作访问。=========>内核,poll().

二、轮询:即不停的查询。

三、在项目中。主函数(main),即使只要检测读或者写其中一种,读和写集都必须设置.. 也就是说

FD_ZERO(&rfds)

FD_ZERO(&wfds);

FD_SET(fd, &rfds);

FD_SET(fd, &wfds);

select(fd + 1, &rfds, &wfds, NULL, NULL);及内核中的poll函数要写完整

四个都要写。缺一不可。在应用中根据实际情况需要来调用FD_ISSET及读写函数

四、项目工作原理:先把读的加到读集,写的加到写集。通过应用层select函数,与内核中的Poll进行联系。由于select在while(1)里面,所以说他会不停的来调用poll函数。而内核Poll函数通过if(dev->current_len != 0)// 有数据可读   和    if(dev->current_len != GLOBALMEM_SIZE)//数据可写。进行判断。通过返回值mask(掩码)返回给应用层的select,当返回的select是1或者2,就说明可以读或者写了。再通过应用层if(FD_ISSET(fd, &rfds))数据可读       和    if(FD_ISSET(fd, &wfds))数据可写。来判断是可读或者可写。当进入应用层read或者write时候。就证明内核函数中的read和write一定可以调用了。

struct timeval tv;===这个时间不准,有bug...

现象:一边读一边写,读完了写,写完了读。

代码:

1、poll函数中,添加到等待队列中

poll_wait(filp,&dev->r_wait,wait);

poll_wait(filp,&dev->w_wait,wait);

2、进行判断可读或者可写:

if(dev->current_len != 0)// 有数据可读

if(dev->current_len != GLOBALMEM_SIZE)//数据可写

返回掩码return mask;(即返回数据是可读还是可写)

补充:

Poll方法只是做一个登记,真正的阻塞发生在select.c 中的 do_select函数,处理流程:


1:初始化 poll_table 表
2:依次调用每个文件的 poll 方法
3:poll 方法调用的 poll_wait会把当前的进程挂到驱动提供的wait_queue_head_t中,相当于遍历了等待队列poll_wait里面是否有变化。
4:假如能读或能写或有信号,就返回
5:否则调用 schedule_timeout 睡眠

设备驱动中的poll()本身不会阻塞,但是poll()和select()系统调用(介于应用层和内核之间的那一层VFS)则会阻塞的等待文件描述符集合中的至少一个(可读,可写,或者可读可写)可访问或超时。

Pollin ---对应的read===(POLLIN | POLLRDNORM).

Pollout---对应的write===(POLLOUT | POLLWRNORM).

阅读(997) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~