2011-10-09 09:12:44 qing_ping 阅读数 1100
  • S5PV210的时钟系统-1.6.ARM裸机第六部分

    本期课程主要讲述S5PV210的时钟系统,通过8节课的讲解和实战,希望大家能够彻底掌握S5PV210(以及类似复杂度的SoC)的时钟体系结构,理解MUX开关、DIV分频器、PLL倍频锁相工作电路等在时钟设置中的作用。

    7500 人正在学习 去看看 朱有鹏

 烧写2410-S linux 操作系统
在windows xp下进行,需要的文件在光盘中的Linux\img目录和flashvivi目录下提供。
烧写2410-S linux 操作系统包括烧写vivi,kernel,root三个步骤,除此我们还要烧写yaffs.tar,这四个文件为:
vivi ----linux操作系统启动的bootloader;
zImage----linux操作系统内核;
root.cramfs----根文件系统;
yaffs.tar----应用程序
一.烧写vivi
1.把并口线插到pc机的并口,并把并口与JTAG相连,JTAG与开发板的14针JTAT口相连,打开2410-S。
2.把整个GIVEIO目录(在flashvivi目录下)拷贝到C:\WINDOWS下,并把该目录下的giveio.sys文件拷贝到c:/windows/system32/drivers下。
3.在控制面板里,选添加硬件,点击“下一步”
选“是,我已经连接了此硬件”然后点击“下一步”
1
选中“添加新的硬件设备”然后点击“下一步”
选中“安装我手动从列表选择的硬件”然后点击“下一步”
2
选择“显示所有设备”然后点击“下一步”
选择“从磁盘安装”然后点击“下一步”
3
选择“浏览”,指定驱动为C:\WINDOWS\GIVEIO\giveio.inf文件
选择giveio.inf文件,点击“打开”
4
然后选择“确定”
点击“下一步”至“完成”即安装好驱动
5
6
4.在d盘新建一目录bootloader,把sjf2410-s(在flashvivi目录下)和要烧写的vivi拷贝到该目录下,在程序-附件-msdos下,进入该目录,运行sjf2410-s命令如下:sjf2410-s /f:vivi。然后按回车
在此后出现的三次要求输入参数,第一次是让选择Flash,选0,然后回车
7
第二次是选择jtag对flash的两种功能,也选0,然后回车

第三次是让选择起始地址,选0,然后回车,等待大约3-5分钟的烧写时间
8
当VIVI 烧写完毕后选择参数2,退出烧写。
5.烧录后关闭2410-S,拔掉JTAG与开发板的连线,并用串口线连接pc和2410-S。
6.打开超级终端,先按住pc机“Back Space”键,然后启动2410-S,进入vivi> 状态下,设置开发板IP(其IP要与服务器IP在同一网段,内核启动后将失效),其命令为:
set c 192.168.0.115
9
7.设置tftp服务器IP(启动tftp服务器的主机),其命令为:set s 192.168.0.82
8.Windows平台下tftp服务的配置:
将随机附带光盘中“\tools”目录下的tftpd32.rar文件解压到Windows的“D:\tftp32”目录下, 并新建文件夹tftpd32,将光盘中“\img”目录下文件拷贝到该目录下。
双击“D:\tftp32”目录下的tftpd32.exe文件,对Windows下的tftp服务进行配置
10
二.烧写内核
在vivi状态下,输入烧写内核的命令为:tftp flash kernel zImage
11
三.烧写根文件系统
在vivi状态下,输入烧写根文件的命令为:tftp flash root root.cramfs。
网络环境不差的话几秒种应该可以烧完。
四.烧写应用程序
用网线连接好2410-S的NIC-1口和PC机的网口,配置IP在同一网段,重启2410-s进入[/mnt/yaffs]下。如图所示进行设置开发板IP。
12
打开ftp软件(在光盘中flashvivi目录中提供),192.168.0.115,用户名:root,密码:无,连接进入ftp,
密码无,点击“OK”。
13
选择要上传的“yaffs.tar”文件,并上传“yaffs.tar”到2410-S的/var下
3分钟左右上传完毕。14
这时千万不要重启2410-S,然后转换到var文件夹下进行解压,其命令为:
tar xjvf yaffs-2410s-1.0.tar -C /mnt/yaffs --解压yaffs-2410s-1.0.tar到mnt/yaffs目录下,需3分钟左右。15
解压完成后,我们可以转换到mnt/yaffs文件夹下进行ls查看文件夹下的内容。
16

2011-03-17 20:14:00 hope_fu 阅读数 623
  • S5PV210的时钟系统-1.6.ARM裸机第六部分

    本期课程主要讲述S5PV210的时钟系统,通过8节课的讲解和实战,希望大家能够彻底掌握S5PV210(以及类似复杂度的SoC)的时钟体系结构,理解MUX开关、DIV分频器、PLL倍频锁相工作电路等在时钟设置中的作用。

    7500 人正在学习 去看看 朱有鹏

烧写2410-S linux 操作系统:

在windows xp下进行,需要的文件在光盘中的img目录和flashvivi目录下提供。

烧写2410-S linux 操作系统包括烧写vivi,kernel,root三个步骤,除此我们还要烧写yaffs.tar,这四个文件在img目录中。

vivi ----linux操作系统启动的bootloader;      
zImage----linux操作系统内核;   
root.cramfs----根文件系统;     
yaffs.tar----应用程序

一.烧写vivi。
1.把并口线插到pc机的并口,并把并口与JTAG相连,JTAG与开发板的14针JTAT口相连,打开2410-S.
2.把整个GIVEIO目录(在flashvivi目录下)拷贝到C:/WINDOWS下,并把该目录下的giveio.sys文件拷贝到c:/windows/system32/drivers下。
3.在控制面板里,选添加硬件>下一步>选-是我已经连接了此硬件>下一步>选中-添加新的硬件设备>下一步>选中安装我手动从列表选择的硬件>下一步>选择-显示所有设备>选择-从磁盘安装-浏览,指定驱动为C:/WINDOWS/GIVEIO/giveio.inf文件,点击确定,安装好驱动
4.在d盘新建一目录bootloader,把sjf2410-s(在flashvivi目录下)和要烧写的vivi拷贝到该目录下,在程序-附件-msdos下,进入该目录,运行sjf2410-s命令如下:sjf2410-s /f:vivi
在此后出现的三次要求输入参数,第一次是让选择Flash,选0;第二次是选择jtag对flash的两种功能,也选0;第三次是让选择起始地址,选0此后就等待大约3-5分钟的烧写时间,当VIVI 烧写完毕后选择参数2,退出烧写。
5.烧录后关闭2410-S,拔掉JTAG与开发板的连线,并用串口线连接pc和2410-S;
6.打开超级终端,先按住pc机“Back Space”键,然后启动2410-S,进入vivi> ,按照以下命令重新分区:
  vivi>bon part 0 128k 192k 1216k 4288k:m 64704k(64M flash1208)
7.这时已格式化flash,千万不要重启2410-S,
  vivi>load flash vivi x  回车
  当出现Ready for downloading using xmodem...
        Waiting...
        ...这时点击超级终端任务栏上“传送”下拉菜单中的“发送文件”,选择好镜像文件vivi,协议为Xmodem,点击“发送"通过串口  重新烧录一遍,至此你的vivi就烧写到flash里了

二.烧写内核zImage(kernel)
   vivi>load flash kernel x   回车
   当出现Ready for downloading using xmodem...
         Waiting...
         ...
   点击超级终端任务栏上“传送”下拉菜单中的“发送文件”,选择好镜像文件zImage,Enter,协议为Xmodem,点击“发送”,4分钟左右zImage烧写完毕;

三.烧写根文件系统(root)
   vivi>load flash root x   回车
   当出现Ready for downloading using xmodem...
         Waiting...
         ...
   点击超级终端任务栏上“传送”下拉菜单中的“发送文件”,选择好镜像文件root.cramfs,协议为Xmodem,点击“发送" ,8分钟左右    root.cramfs烧写完毕;

四.烧写应用程序:用网线连接好2410-S的NIC-1口和PC机的网口,配置IP在同一网段,重启2410-s进入[/mnt/yaffs]下。
[/mnt/yaffs]ifconfig                               --查看IP
[/mnt/yaffs]ifconfig eth0 192.168.0.111            --配置eth0 ip
[/mnt/yaffs]inetd                                  --启动ftp
    打开ftp软件(在光盘中flashvivi目录中提供),192.168.0.111,用户名:root,密码:无,连接进入ftp,上传“yaffs.tar”到2410-S的/var下,3分钟左右上传完毕。
这时千万不要重启2410-S,
[/mnt/yaffs]cd ..                                  --转换到/mnt下
[/mnt]rm -rf yaffs/*                              --删除/yaffs下文件
[/mnt]cd /var                                      --转到var目录下
[/var]tar xjvf yaffs-2410s-1.0.tar -C /mnt/yaffs   --解压yaffs-2410s-1.0.tar到mnt/yaffs目录下,需3分钟左右

2012-03-02 15:38:00 a13393665983 阅读数 1
  • S5PV210的时钟系统-1.6.ARM裸机第六部分

    本期课程主要讲述S5PV210的时钟系统,通过8节课的讲解和实战,希望大家能够彻底掌握S5PV210(以及类似复杂度的SoC)的时钟体系结构,理解MUX开关、DIV分频器、PLL倍频锁相工作电路等在时钟设置中的作用。

    7500 人正在学习 去看看 朱有鹏

HTTP协议之Chunked解析_zkheartboy's Linux life_百度空间

HTTP协议之Chunked解析
2007-11-30 15:42
在网上找了好一会,始终没发现有解析Chunked编码的文章,那就自己写一个吧,呵呵。

网上使用Chunked编码的网站似乎并不是很多,除了那些使用GZip压缩的网站,例:google.com,还有就是大部分打开GZip压缩的PHP论坛。

根据本人的理解,使用Chunked编码的主要好处就在于一些程序的运算出过程中,可以动态的输出内容。

例如,要在后台处理一个小时的运算,但又不希望用户等一个小时才能看到结果。这时就可采用Chunked编码将内容分块输出,用户随时都可以接收到最新的处理结果。

ASP关闭了缓存的输出模式,就是Chunked编码的。(Response.Buffer = false)

而每一次的Response.Write,都是一个Chunked,所以不要使用的太频繁哦,否则Chunk数量太多,额外的数据太浪费空间了。

若想了解Chunked的具体编码结构,用ASP关闭缓存调试蛮方便的。:)



我们先来看看RFC2616中对Chunked的定义:

Chunked-Body = *chunk

last-chunk

trailer

CRLF



chunk = chunk-size [ chunk-extension ] CRLF

chunk-data CRLF

chunk-size = 1*HEX

last-chunk = 1*("0") [ chunk-extension ] CRLF



chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )

chunk-ext-name = token

chunk-ext-val = token | quoted-string

chunk-data = chunk-size(OCTET)

trailer = *(entity-header CRLF)



我们来模拟一下数据结构:

[Chunk大小][回车][Chunk数据体][回车][Chunk大小][回车][Chunk数据体][回车][0][回车]



注意chunk-size是以十六进制的ASCII码表示的,比如86AE(实际的十六进制应该是:38366165),计算成长度应该是:34478,表示从回车之后有连续的34478字节的数据。

跟踪了www.yahoo.com的返回数据,发现在chunk-size中,还会多一些空格。可能是固定长度为7个字节,不满7个字节的,就以空格补足,空格的ASCII码是0x20。



以下是解码过程的伪代码:

length := 0//用来记录解码后的数据体长度

read chunk-size, chunk-extension (if any) and CRLF//第一次读取块大小

while (chunk-size > 0) {//一直循环,直到读取的块大小为0

read chunk-data and CRLF//读取块数据体,以回车结束

append chunk-data to entity-body//添加块数据体到解码后实体数据

length := length + chunk-size//更新解码后的实体长度

read chunk-size and CRLF//读取新的块大小

}

read entity-header//以下代码读取全部的头标记

while (entity-header not empty) {

append entity-header to existing header fields

read entity-header

}

Content-Length := length//头标记中添加内容长度

Remove "chunked" from Transfer-Encoding//头标记中移除Transfer-Encoding





有空再研究一下GZip+Chunked是如何编码的,估计是每个Chunk块进行一次GZip独立压缩。



使用了Chunked,自然会在性能上稍微打点折扣,因为比正常的数据体多出了一些额外的消耗。

但是有一些情况下,必需要使用分块输出,这也是不得已而为之~^_^
posted on 2012-03-02 15:38 lexus 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/lexus/archive/2012/03/02/2377303.html

2015-04-15 16:30:25 winlerman 阅读数 1198
  • S5PV210的时钟系统-1.6.ARM裸机第六部分

    本期课程主要讲述S5PV210的时钟系统,通过8节课的讲解和实战,希望大家能够彻底掌握S5PV210(以及类似复杂度的SoC)的时钟体系结构,理解MUX开关、DIV分频器、PLL倍频锁相工作电路等在时钟设置中的作用。

    7500 人正在学习 去看看 朱有鹏

解释linux 文件 s 权限。


s权限的作用:表示对文件具用可执行权限的用户将使用文件拥有者的权限或文件拥有者所在组的权限在对文件进行执行。

s权限的设置:4,用户拥有者的执行权限位, 6,用户组的执行权限位, 2, 两者都设置,  0, 两者都不设置。

假设有文件a

-rw-rw---- 1 tony tony 4 Apr 10 21:27 a

    tony用户拥有此文件,文件权限如上行。

有程序如下test.cpp:

#include<fstream>
#include<iostream>
using namespace std;
int main()
{
    fstream s("./a", ios::in|ios::out);
    s<<"123"<<endl;
}
可执行文件为test, 其权限为
-rwxrwx--x 1 tony tony 13712 Apr 10 21:11 test

tony@ubuntu:~/test$ su shw
Password: 
shw@ubuntu:/home/tony/test$ ls
a  test  test.cpp
shw@ubuntu:/home/tony/test$ ls -l test
-rwxrwx--x 1 tony tony 13712 Apr 15 16:11 test
shw@ubuntu:/home/tony/test$ 

现切换到用户shw, 此用户不在tony组,对于test具有可执行权限,对a没有任何权限。

此时用shw来执行test会发生什么呢?

执行后查看文件 a,发现a 没有被写会任何内容。

     也就是说shw虽然对test有可执行权限,但是shw对a没有写的权限,故执行失败。


这时有三个办法来解决:

      1.  用超级用户来执行,           不安全

      2.  使用test对a具有相应权限,         但如何test操作了n个文件 , 则需要对这n个文件都修改权限。

      3.   s权限。


现在来设置s权限,使shw在执行test时使用tony的权限。


tony@ubuntu:~/test$ chmod 4771 test
tony@ubuntu:~/test$ ls -l
total 24
-rw-rw---- 1 tony tony     4 Apr 15 16:27 a
-rwsrwx--x 1 tony tony 13712 Apr 15 16:11 test
-rw-rw-r-- 1 tony tony   133 Apr 15 16:11 test.cpp
tony@ubuntu:~/test$ 

此时test的执行权限位为s。

再使用shw来执行test, 查看文件a , 发现123已写入。

2016-07-01 20:44:33 qq_21593899 阅读数 1882
  • S5PV210的时钟系统-1.6.ARM裸机第六部分

    本期课程主要讲述S5PV210的时钟系统,通过8节课的讲解和实战,希望大家能够彻底掌握S5PV210(以及类似复杂度的SoC)的时钟体系结构,理解MUX开关、DIV分频器、PLL倍频锁相工作电路等在时钟设置中的作用。

    7500 人正在学习 去看看 朱有鹏

Linux进程状态解析之R、S、D、T、Z、X;Linux是一个多用户,多任务的系统,可以同时运;众所周知,现在的分时操作系统能够在一个CPU上运;在linux系统中,每个被运行的程序实例对应一个;Linux进程状态:R(TASK_RUNNING;只有在该状态的进程才可能在CPU上运行;很多操作系统教科书将正在CPU上执行的进程定义为;Linux进程状态:S

Linux进程状态解析之R、S、D、T、Z、X

Linux是一个多用户,多任务的系统,可以同时运行多个用户的多个程序,就必然会产生很多的进程,而每个进程会有不同的状态。

众所周知,现在的分时操作系统能够在一个CPU上运行多个程序,让这些程序表面上看起来是在同时运行的。linux就是这样的一个操作系统。

在linux系统中,每个被运行的程序实例对应一个或多个进程。linux内核需要对这些进程进行管理,以使它们在系统中“同时”运行。linux内核对进程的这种管理分两个方面:进程状态管理,和进程调度。


【1】Linux进程状态:R (TASK_RUNNING),可执行状态。

只有在该状态的进程才可能在CPU上运行。而同一时刻可能有多个进程处于可执行状态,这些进程的task_struct结构(进程控制块)被放入对应CPU的可执行队列中(一个进程最多只能出现在一个CPU的可执行队列中)。

进程调度器的任务就是从各个CPU的可执行队列中分别选择一个进程在该CPU上运行。

很多操作系统教科书将正在CPU上执行的进程定义为RUNNING状态、而将可执行但是尚未被调度执行的进程定义为READY状态,这两种状态在linux下统一为 TASK_RUNNING状态。 只要可执行队列不为空,其对应的CPU就不能偷懒,就要执行其中某个进程。一般称此时的CPU“忙碌”。对应的,CPU“空闲”就是指其对应的可执行队列为空,以致于CPU无事可做。 有人问,为什么死循环程序会导致CPU占用高呢?因为死循环程序基本上总是处于TASK_RUNNING状态(进程处于可执行队列中)。除非一些非常极端情况(比如系统内存严重紧缺,导致进程的某些需要使用的页面被换出,并且在页面需要换入时又无法分配到内存??),否则这个进程不会睡眠。所以 CPU的可执行队列总是不为空(至少有这么个进程存在),CPU也就不会“空闲”。


【2】Linux进程状态:S (TASK_INTERRUPTIBLE),可中断的睡眠状态。

处于这个状态的进程因为等待某某事件的发生(比如等待socket连接、等待信号量),而被挂起。这些进程的task_struct结构被放入对应事件的等待队列中。当这些事件发生时(由外部中断触发、或由其他进程触发),对应的等待队列中的一个或多个进程将被唤醒。 通过ps命令我们会看到,一般情况下,进程列表中的绝大多数进程都处于TASK_INTERRUPTIBLE状态(除非机器的负载很高)。毕竟CPU就这么一两个,进程动辄几十上百个,如果不是绝大多数进程都在睡眠,CPU又怎么响应得过来。


【3】Linux进程状态:D (TASK_UNINTERRUPTIBLE),不可中断的睡眠状态。

与TASK_INTERRUPTIBLE状态类似,进程处于睡眠状态,但是此刻进程是不可中断的。不可中断,指的并不是CPU不响应外部硬件的中断,而是指进程不响应异步信号。绝大多数情况下,进程处在睡眠状态时,总是应该能够响应异步信号的。否则你将惊奇的发现,kill -9竟然杀不死一个正在睡眠的进程了!于是我们也很好理解,为什么ps命令看到的进程几乎不会出现TASK_UNINTERRUPTIBLE状态,而总是TASK_INTERRUPTIBLE状态。

而TASK_UNINTERRUPTIBLE状态存在的意义就在于,内核的某些处理流程是不能被打断的。如果响应异步信号,程序的执行流程中就会被插入一段用于处理异步信号的流程(这个插入的流程可能只存在于内核态,也可能延伸到用户态),于是原有的流程就被中断了。(参见《linux内核异步中断浅析》)在进程对某些硬件进行操作时(比如进程调用read系统调用对某个设备文件进行读操作,而read系统调用最终执行到对应设备驱动的代码,并与对应的物理设备进行交互),可能需要使用TASK_UNINTERRUPTIBLE状态对进程进行保护,以避免进程与设备交互的过程被打断,造成设备陷入不可控的状态。这种情况下的TASK_UNINTERRUPTIBLE状态总是非常短暂的,通过ps命令基本上不可能捕捉到。

linux系统中也存在容易捕捉的TASK_UNINTERRUPTIBLE状态。执行vfork系统调用后,父进程将进入TASK_UNINTERRUPTIBLE状态,直到子进程调用exit或exec(参见《神奇的vfork》)。通过下面的代码就能得到处于TASK_UNINTERRUPTIBLE状态的进程:

#include <unistd.h>

void main()

 {

        if (!vfork()) sleep(100);

}

编译运行,然后ps一下:

kouu@kouu-one:~/test$ ps -ax | grep a\.out

4371 pts/0 D+ 0:00 ./a.out

4372 pts/0 S+ 0:00 ./a.out

4374 pts/1 S+ 0:00 grep a.out

然后我们可以试验一下TASK_UNINTERRUPTIBLE状态的威力。不管kill还是kill -9,这个TASK_UNINTERRUPTIBLE状态的父进程依然屹立不倒。



【4】Linux进程状态:T (TASK_STOPPED or TASK_TRACED),暂停状态或跟踪状态。

向进程发送一个SIGSTOP信号,它就会因响应该信号而进入TASK_STOPPED状态(除非该进程本身处于TASK_UNINTERRUPTIBLE状态而不响应信号)。(SIGSTOP与SIGKILL信号一样,是非常强制的。不允许用户进程通过signal系列的系统调用重新设置对应的信号处理函数。)向进程发送一个SIGCONT信号,可以让其从TASK_STOPPED状态恢复到TASK_RUNNING状态。

当进程正在被跟踪时,它处于TASK_TRACED这个特殊的状态。“正在被跟踪”指的是进程暂停下来,等待跟踪它的进程对它进行操作。比如在gdb中对被跟踪的进程下一个断点,进程在断点处停下来的时候就处于TASK_TRACED状态。而在其他时候,被跟踪的进程还是处于前面提到的那些状态。

对于进程本身来说,TASK_STOPPED和TASK_TRACED状态很类似,都是表示进程暂停下来。而TASK_TRACED状态相当于在TASK_STOPPED之上多了一层保护,处于TASK_TRACED状态的进程不能响应SIGCONT信号而被唤醒。只能等到调试进程通过ptrace系统调用执行PTRACE_CONT、PTRACE_DETACH等操作(通过ptrace系统调用的参数指定操作),或调试进程退出,被调试的进程才能恢复TASK_RUNNING状态。



【5】Linux进程状态:Z (TASK_DEAD - EXIT_ZOMBIE),退出状态,进程成为僵尸进程。 进程在退出的过程中,处于TASK_DEAD状态。

在这个退出过程中,进程占有的所有资源将被回收,除了task_struct结构(以及少数资源)以外。于是进程就只剩下task_struct这么个空壳,故称为僵尸。之所以保留task_struct,是因为task_struct里面保存了进程的退出码、以及一些统计信息。而其父进程很可能会关心这些信息。比如在shell中,$?变量就保存了最后一个退出的前台进程的退出码,而这个退出码往往被作为if语句的判断条件。当然,内核也可以将这些信息保存在别的地方,而将task_struct结构释放掉,以节省一些空间。但是使用task_struct结构更为方便,因为

在内核中已经建立了从pid到task_struct查找关系,还有进程间的父子关系。释放掉task_struct,则需要建立一些新的数据结构,以便让父进程找到它的子进程的退出信息。 父进程可以通过wait系列的系统调用(如wait4、waitid)来等待某个或某些子进程的退出,并获取它的退出信息。然后wait系列的系统调用会顺便将子进程的尸体(task_struct)也释放掉。子进程在退出的过程中,内核会给其父进程发送一个信号,通知父进程来“收尸”。这个信号默认是SIGCHLD,但是在通过clone系统调用创建子进程时,可以设置这个信号。 通过下面的代码能够制造一个EXIT_ZOMBIE状态的进程:

#include <unistd.h>

void main() {

if (fork())

while(1) sleep(100);

}

编译运行,然后ps一下:

ps -ax | grep a\.out

10410 pts/0 S+ 0:00 ./a.out

10411 pts/0 Z+ 0:00 [a.out] <defunct>

10413 pts/1 S+ 0:00 grep a.out

只要父进程不退出,这个僵尸状态的子进程就一直存在。那么如果父进程退出了呢,谁又来给子进程“收尸”?当进程退出的时候,会将它的所有子进程都托管给别的进程(使之成为别的进程的子进程)。托管给谁呢?可能是退出进程所在进程组的下一个进程(如果存在的话),或者是1号进程。所以每个进程、每时每刻都有父进程存在。除非它是1号进程。 1号进程,pid为1的进程,又称init进程。linux系统启动后,第一个被创建的用户态进程就是init进程。它有两项使命:1、执行系统初始化脚本,创建一系列的进程(它们都是init进程的子孙);2、在一个死循环中等待其子进程的退出事件,并调用waitid系统调用来完成“收尸”工作;init进程不会被暂停、也不会被杀死(这是由内核来保证的)。它在等待子进程退出的过程中处于TASK_INTERRUPTIBLE状态,“收尸”过程中则处于TASK_RUNNING状态。


【6】Linux进程状态:X (TASK_DEAD - EXIT_DEAD),退出状态,进程即将被销毁。

而进程在退出过程中也可能不会保留它的task_struct。比如这个进程是多线程程序中被detach过的进程(进程?线程?参见《linux线程浅析》)。或者父进程通过设置SIGCHLD信号的handler为SIG_IGN,显式的忽略了SIGCHLD信号。(这是posix的规定,尽管子进程的退出信号可以被设置为SIGCHLD以外的其他信号。)此时,进程将被置于EXIT_DEAD退出状态,这意味着接下来的代码立即就会将该进程彻底释放。所以EXIT_DEAD状态是非常短暂的,几乎不可能通过ps命令捕捉到。

进程的初始状态

进程是通过fork系列的系统调用(fork、clone、vfork)来创建的,内核(或内核模块)也可以通过kernel_thread函数创建内核进程。这些创建子进程的函数本质上都完成了相同的功能——将调用进程复制一份,得到子进程。(可以通过选项参数来决定各种资源是共享、还是私有。)那么既然调用进程处于TASK_RUNNING状态(否则,它若不是正在运行,又怎么进行调用?),则子进程默认也处于TASK_RUNNING状态。另外,在系统调用调用clone和内核函数kernel_thread也接受CLONE_STOPPED选项,从而将子进程的初始状态置为 TASK_STOPPED。

进程状态变迁

进程自创建以后,状态可能发生一系列的变化,直到进程退出。而尽管进程状态有好几种,但是进程状态的变迁却只有两个方向——从TASK_RUNNING状态变为非TASK_RUNNING状态、或者从非TASK_RUNNING状态变为TASK_RUNNING状态。也就是说,如果给一个TASK_INTERRUPTIBLE状态的进程发送SIGKILL信号,这个进程将先被唤醒(进入TASK_RUNNING状态),然后再响应SIGKILL信号而退出(变为TASK_DEAD状态)。并不会从TASK_INTERRUPTIBLE状态直接退出。

进程从非TASK_RUNNING状态变为TASK_RUNNING状态,是由别的进程(也可能是中断处理程序)执行唤醒操作来实现的。执行唤醒的进程设置被唤醒进程的状态为TASK_RUNNING,然后将其task_struct结构加入到某个CPU的可执行队列中。于是被唤醒的进程将有机会被调度执行。

而进程从TASK_RUNNING状态变为非TASK_RUNNING状态,则有两种途径:1、响应信号而进入TASK_STOPED状态、或TASK_DEAD状态;2、执行系统调用主动进入TASK_INTERRUPTIBLE状态(如nanosleep系统调用)、或TASK_DEAD状态(如exit系统调用);或由于执行系统调用需要的资源得不到满足,而进入TASK_INTERRUPTIBLE状态或TASK_UNINTERRUPTIBLE状态(如select系统调用)。显然,这两种情况都只能发生在进程正在CPU上执行的情况下。

.进程的三种基本状态

进程在运行中不断地改变其运行状态。通常,一个运行进程必须具有以下三种基本状态。 就绪(Ready)状态

当进程已分配到除CPU以外的所有必要的资源,只要获得处理机便可立即执行,这时的进程状态称为就绪状态。

执行(Running)状态

当进程已获得处理机,其程序正在处理机上执行,此时的进程状态称为执行状态。 阻塞(Blocked)状态

正在执行的进程,由于等待某个事件发生而无法执行时,便放弃处理机而处于阻塞状态。引起进程阻塞的事件可有多种,例如,等待I/O完成、申请缓冲区不能满足、等待信件(信号)等。

2.进程三种状态间的转换

一个进程在运行期间,不断地从一种状态转换到另一种状态,它可以多次处于就绪状态和执行状态,也可以多次处于阻塞状态。图3_4描述了进程的三种基本状态及其转换。

(1) 就绪→执行处于就绪状态的进程,当进程调度程序为之分配了处理机后,该进程便由就绪状态转变成执行状态。

(2) 执行→就绪处于执行状态的进程在其执行过程中,因分配给它的一个时间片已用完而不得不让出处理机,于是进程从执行状态转变成就绪状态。

(3) 执行→阻塞正在执行的进程因等待某种事件发生而无法继续执行时,便从执行状态变成阻塞状态。

(4) 阻塞→就绪处于阻塞状态的进程,若其等待的事件已经发生,于是进程由阻塞状态转变为就绪状态。

例:

题目:某系统的状态转换图如图所示。

(1)分别说明引起状态转换1、2、3、4的原因,并各举一个事件。(2)为什么在转换图中没有就绪到阻塞和阻塞到运行的转换方向?(3)一个进程的状态变换能够引起另一个进程的状态变换,说明下列因果变迁是否可能发生,原因是什么?(a)3→1(b)2→1(c)3→2(d)3→4(e)4→1

答: (1)1:就绪->执行, 当前运行进程阻塞,调度程序选一个优先权最高的进程占有处理机;2:执行->就绪, 当前运行进程时间片用完;3:执行->阻塞,当前运行进程等待键盘输入,进入了睡眠状态。4:阻塞->就绪,I/O操作完成,被中断处理程序唤醒。

(2)就绪进程没有占有处理机,也即没有经过运行,其状态就不会改变。阻塞状态进程唤醒后先要进入就绪队列,才会被调度程序选中,进入了执行状态。

(3)(a) 3→1: 可能,当前运行进程阻塞,调度程序选一个优先级最高的进程占有处理机。(b)2→1:可能,当前运行进程优先级下降,调度程序选一个优先级最高的进程占有处理机。(c)3→2: 不可能,占有CPU的一个进程不能同时进入两个状态;在单CPU的系统中,状态3发生后,cpu没有执行进程,故不会发生状态转换2。(d)3→4:一般不可能,不相干的两个事件。状态转换3是由于运行进程等待资源而发生的,这并不会使得阻塞队列中的进程得到资源而进入就绪队列。但在Unix中,当系统的0#进程因runin标志而睡眠时,有(在内存)进程睡眠,就会唤醒0#进程,使其进入就绪状态,以便将该进程和在盘交换区就绪进程交换位置。(e)4→1:一般无关,但当就绪队列为空时,一个进程被唤醒转入就绪队列后,调度程序使该进程占有处理机(但是同一个进程)。


linux 内核编译手记

阅读数 822

没有更多推荐了,返回首页