Linux基础知识

Linux启动过程中,/Linuxrc,/etc/init.d/rcS, /etc/init.d/rc.local /etc/init.d/profile这几个文件依次加载,从而完成系统初始化,设定必要信息,执行用户自启动脚本。

/Linuxrc执行init进程初始化文件。主要是把已安装根文件系统中的/etc安装为ramfs,并复制/mnt/etc/目录下所有文件到/etc,这里存放系统启动后的很多特殊文件。接着Linux重新构建文件分配表inittab,之后执行系统初始化进程/sbin/init。这个/Linuxrc文件不是必须的,如果系统中没有这个文件,则默认首先运行/sbin/init,其他的功能可以在/etc/rcS文件中实现。
/mnt/etc/init.d/rcS这个是系统必须的文件,主要是完成各个文件系统的mount,再执行/usr/etc/rc.local;通过rcS可调用dhcp程序配置网络。rcS执行完成后,init会在一个console上按照inittab的指示开一个shell,或者开getty+login,这样用户就会看到提示输入用户名的提示符。
/usr/etc/rc.local是被init.d/rcS文件调用执行的特殊文件,与Linux系统硬件平台相关,如安装核心模块,进行网络配置,运行应用程序,启动图形界面等。

#/bin/qtopia & “#”就是注释掉这一行,“&”表示在后台运行

嵌入式常用的GUI
Qtopia Core(Qt/Embedded)
MiniGUI
MicroWindows
Tiny-X

/bin 存放常用的基本命令
/sbin 系统管理员用的命令
/dev 设备文件
/etc 系统配置文件
/lib 共享库和驱动模块
/home 用户目录
/root 根用户目录
/var 存放程序运行产生的日志文件
/proc 内核临时生成的文件
/mnt 系统挂载文件
/tmp 程序运行产生的临时文件

/usr 系统种所有的应用程序和文件
/usr/bin 存放应用程序
/usr/src 存放linux源码
/usr/lib 动态链接库

文件系统:除了linux内核,让linux系统跑起来所必须的其余软件,如shell,配置文件,命令等。
1.创建文件夹 bin etc dev home lib mnt opt proc root sbin sys tmp usr var
2.用busybox完善目录内容
dev目录下创建2个设备节点
mknode console c 5 1
mknode null c 1 3

系统启动完成内核后,启动第一个进程init(/etc/init.d/rcS),此进程程ID=1,此进程根据配置文件(/etc/inittab)决定启动哪些程序。

fstab文件 说明文件的挂载位置。

通过mkyaffs2image制作文件系统为yaffs镜像文件。

S3C2440开发板创建desktop的时候
把first放到开发板的/opt/Qtopia/bin/ 下;first.png放到/opt/Qtopia/pics/下;first.desktop放到/Qtopia/apps/EmbedSky/下

系统环境变量的设置
1.在/etc/profile文件中,但是linux不推荐。
2.在/etc/profile.d目录中增加环境变量脚本文件,linux推荐。
/etc/profile在每次启动后会执行/etc/profile.d下的全部脚本文件,不管什么变量,直接删除/etc/profile.d下的shell脚本即可。
用户环境变量
1.bash_profile(推荐首选)

环境变量的脚本文件执行顺序

/etc/profile -> /etc/profile.d -> /etc/bashrc ->用户的bash_profile ->用户的.basshrc
多个脚本文件里面有相同的环境变量,则会依照最后一个为准。

PATH环境变量存放的目录,目录之间用冒号分割。
PATH缺省包含的linux命令所在目录 /usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin如果不包含这些目录,linux的命令也无法执行(需要输入绝对地址才可以)。PATH环境变量的值也叫shell的搜索路径。

HOME是用户登入后的工作目录,用户相关的配置文件一般都在这个目录。 shell会自动将 ~ 替换为当前用户的主目录。

用户的 .bash_profile中会对PATH进行扩充。
export PATH= $PATH: $HOME/bin

LANG环境变量用于设置语言,地区,字符集。
LD_LIBRARY_PATH 是C/C++动态链接库文件的搜索目录。
CLASSPATH 是JAVA语言文件库搜索的目录。

符合链接
用L表示,通过文件名指向另一个文件。可以通过ln -s创建符号链接。

嵌入式linux启动过程有2种,代表(S3C2440)arm9/arm11是一种,S5PV210是一种。
关于第一种:S3C2440 的bootloader存储在nor flash(价格贵,容量小2M-32M,属于总线设备(无需驱动程序))。
通过烧写工具JLINK 把bootloader烧写到nor flash。nand flash存放kernel和根文件系统。
上电后从bootloader运行,初始化内存控制器以及flash控制器。loader阶段把kernel(压缩后的)搬运到RAM, 把kernel启动参数传递给内核R0=板子编号(以及为不同开发板定义好的编号,用于识别加载所需要的驱动程序),R1=kernel启动参数(比如ttys波特率),R2=0。

关于第二种:S5PV210
内部有IROM(64K)存放了固化程序,用于初始化晶振,选择启动方式,把NAND flash前8K的bootloader复制到 IRAM,这前8K的bootloader用于基本的硬件初始化以及设置bootloader自加载,loader阶段把kernel复制到DDRAM。IRAM(96K)。
bootloader kernel 根文件系统都存放在NAND flash。
linux的IO包括 文件IO,标准IO,目录IO。

文件IO:内核向用户提供的IO,
read ,
write,
open(char *路径,flag打开方式,mode文件权限),成功返回文件描述符,错误返回-1。
若是flag包含O_CREAT,则需要设置第三个参数,文件权限 0666(读写),前面的0代表8进制。
close

linux下监听多个设备:
如果一个应用程序去处理多个设备,例如应用程序读取网路数据,按键,串口,一般能想到的有三种方法:
方法1:
串行+阻塞的方式读取:
while(1) {
read(标准输入);
read(网络);
}
缺点:每当阻塞读取标准输入时,如果用户不进行标准输入的操作,而此时客户端给服务器发送数据,导致服务器无法读取客户端发送来的数据!

方法2:
采用多线程或者多进程机制来实现读取:
开辟多个线程,每一个线程处理一个设备,不会导致的数据的无法读取,但是系统的开销相比方法1要大!

方案3:采用linux系统提供的高级IO的处理机制
select/poll:两者一样,主进程能够利用select或者poll能够对多个设备进行监听!
其原理好像:方法1相当于有一个保安,看十户房子,如果小偷进来从第十户开始偷,保安却从第一户挨个检查,没有小偷确还在第一家等。
方法3相当于买了10套监控设备,一个保安看监控录像,有情况报警


select函数原型:
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
函数功能:
主进程利用此函数能够对多个设备进行监听,一旦发现监听的设备都不可用(不可读、也不可写、也没有异常),那么主进程进入休眠状态,一旦监听的设备中,只要有一个设备可用(可读或者可写或者有异常)都会唤醒休眠的主进程,select也就会返回。

注意这个函数仅仅起到一个监听的功能,数据的后续处理,例如读写都是通过read,write,ioctl来进行!

参数说明:
nfds:
对设备的访问永远先open获取fd;
监听的设备中,最大的文件描述符fd+1;
数据类型fd_set:文件描述符集合,用来保存描述监听的设备,里面存放是被监听设备的文件描述符;如果select要监听某一个设备,必须把这个设备的fd添加到对应的文件描述符集合中!

readfds:读文件描述符集合指针,如果select要监听设备是否可读,需将设备的fd添加到这个集合中!

writefds:写文件描述符集合指针,如果select要监听设备是否可写,需将设备的fd添加到这个集合中!

exceptfds:异常文件描述符集合指针,如果select要监听设备是否有异常,需将设备的fd添加到这个集合中!

注意:一个设备的fd可以同时添加到三个集合中!

timeout:指定监听的超时时间,如果此参数指定了一个时间,例如5秒钟,select发现设备不可用,主进程进入休眠状态,如果5秒之内设备还不可用,5秒到期,主进程主动唤醒;如果此参数指定为NULL,休眠为永久休眠!

返回值:有三种
如果等于0:表明是超时;
如果小于0:表明系统出错;
如果大于0:表明设备可用(至少是一个设备,或者全部);

文件描述符集合操作的方法:
fd_set rfds; //定义读文件描述符集合

//从集合中解除对fd设备的监听
void FD_CLR(int fd, fd_set *set);

//判断是否是设备fd引起的主进程的唤醒,如果是返回true,否则返回false
int FD_ISSET(int fd, fd_set *set);

//添加一个新的被监听的设备
void FD_SET(int fd, fd_set *set);

//清空文件描述符集合
void FD_ZERO(fd_set *set);

注意:如果要重复监听,需要再次清空集合和添加监听设备!


以上是应用程序层面上的函数调用

其在内核层面上:

在sys_select中做休眠,poll不引起休眠
select系统调用过程:
1.应用程序调用select,首先调用C库的select函数实现;

2.C库的select保存select系统调用号到R7寄存器中,调用SVC(新的
)或者SWI(老的)触发软中断,至此由用户空间陷入内核空间,ARM
的工作模式由用户模式转变为SVC管理模式;

3.跳转到内核准备好的异常向量表的入口地址,根据R7保存的系统调
用号,以它为索引在系统调用表中找到对应的实现函数sys_select

4.sys_select要完成:
1.把被监听的设备对应驱动程序的poll函数挨个调用一遍,
被监听的设备都不可用时,它们的驱动的poll函数都返回0;
2.判断是否是驱动主动唤醒,还是超时唤醒,还是接收到信号唤醒;
3.如果即没有驱动主动唤醒,也没有超时唤醒,没有接收到信号,
sys_select调用poll_schedule_timeout主动让进程进入休眠;
4.假设被监听的设备中,有一个设备可用(可读或者可写或者异常
,硬件通过中断来判断),都会唤醒休眠的主进程;
5.sys_select的poll_schedule_timeout函数返回,不再休眠
6.再次把被监听的设备驱动的poll函数挨个调用一遍,此时可用
的设备对应的驱动poll函数会返回非0;
7.if (ret || time_out || …) //ret = 1,立即返回到用户空
间,返回值为ret值

总结:
1.明确本来应该底层驱动的poll函数利用等待队列机制让进程休眠,
但是等待队列休眠9步骤并不都是驱动的poll来编写,有一部分是有内
核sys_select来实现;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值