嵌入式实时操作系统复习提纲
一、基本概念
Linux内核主要是由进程调度、内存管理、虚拟文件系统、网络接口和进程间通信等组成。
3.Linux用户进程:
Linux系统定义了五种状态进程状态
从Linux的调度来看,支持非实时(普通)和实时两种进程。
5.考虑到中断处理的效率,Linux的中断处理程序分为两个部分:上半部(top half)和下半部(bottom half)。由外部设备引发的中断叫外部中断,处理器响应中断请求而执行的程序模块叫中断服务例程
6.交换机制:将不用或暂不用的页框中的页移出,装上新的页面;linux三级分页结构
7.进程的通信与同步机制有管道、信号、消息队列、共享内存和信号量集等el 中。Linux的管道有:匿名管道和命名管道;从信号的可靠性方面,信号可以分为:可靠信号和不可靠信号。
8.linux设备驱动注册的基本参数有设备名称,设备驱动的数据结构、设备号
和 次设备号。lsmod 把现在 kernel 中已经安装的modules 列出来;insmod 把某个 module 安装到 kernel.
二、基本原理和方法
基于虚拟内存技术的程序执行两次映射:
Buddy算法-伙伴算法
Slab分配器思想
Linux 内核的主要组成部分
Linux的中断处理程序
Linux系统进程调度的总体思想。
实时进程优先于普通进程,实时进程以进程的紧急程度为优先顺序,普通进程以进程平等占用CPU时间为基本调度原则。
Linux提供了两种实时调度策略SCHED_FIFO和SCHED_RR
linux进程调用shmget(Shared Memory GET,获取共享内存)来分配一个共享内存块。shmat(SHared Memory Attach,绑定到共享内存)。shmctl("Shared Memory Control",控制共享内存)函数会返回一个共享内存块的相关信息。同时 shmctl 允许程序修改这些信息。
(5)信号量
(6)套接字(socket)
三、Linux调度程序理解
1. Linux使用内核函数goodness()对进程进行加权处理:
Static inline goodness (struct task_struct * pint this_cpu, struct mm_struct *this_mm)
{Int weight;
Weight=-1;
If (p->policy & SCHED_YIELD)// /*判断如果任务的调度策略被置为SCHED_YIELD的话,则置权值为-1,返回。
goto out;
If (p->policy==SCHED_OTHER) /*先对普通进程进行处理(由于多数是普通进程,这样做有利于提高系统效率)*/
{weight=p->counter; /*返回权值为进程的counter值*/
If (! weight)
Goto out;
#Ifdef CONFIG_SMP
If (p->processor==this_cpu)
Weight+=PROC_CHANGE_PENALTY;
#Endif
If (p->mm==this_mm||! p->mm)
Weight+=1; /*对进程权值进行微调,如果进程的内存空间使用当前正在运行的进程的内存空间,则权值额外加1*/
Weight+=20-p->nice; /*将权值加上20与进程优先级nice的差。普通进程的权值主要由counter值和nice值组成*/
Goto out;
}
Weight=1000+p->rt_priority; //对实时进程进行处理,返回权值为rt_priority+1000,确保优先级高于普通进程*/
Out:
return weight;}
#include<stdio.h>
#include<unistd.h>
int main()
{
int n,fd[2]; // 这里的fd是文件描述符的数组,用于创建管道做准备的
pid_t pid;
char line[100];
if(pipe(fd)<0) // 创建管道
printf("pipe create error/n");
if((pid=fork())<0) //利用fork()创建新进程
printf("fork error/n");
else if(pid>0){ //这里是父进程,先关闭管道的读出端,然后在管道的写端写入“hello world"
close(fd[0]);
write(fd[1],"hello word/n",11);
}
else{
close(fd[1]); //这里是子进程,先关闭管道的写入端,然后在管道的读出端读出数据
n= read(fd[0],line,100);
write(STDOUT_FILENO,line,n);
}
exit(0);
}
工作队列(work queue)是Linux kernel中将工作推后执行的一种机制。这种机制和BH或Tasklets不同之处在于工作队列是把推后的工作交由一个内核线程去执行,因此工作队列的优势就在于它允许重新调度甚至睡眠。
工作队列是2.6内核开始引入的机制,在2.6.20之后,工作队列的数据结构发生了一些变化,数据结构:
struct work_struct {
unsigned long pending; pending是用来记录工作是否已经挂在队列上;
struct list_head entry; entry是循环链表结构;
void (*func)(void *); func作为函数指针,由用户实现;
void *data; data用来存储用户的私人数据,此数据即是func的参数;
void *wq_data; wq_data一般用来指向工作者线程(工作者线程参考下文);
struct timer_list timer; timer是推后执行的定时器。
};
工作队列(work queue)API:
1、INIT_WORK(_work, _func, _data);初始化指定工作,目的是把用户指定的函数_func及_func需要的参数_data赋给work_struct的func及data变量。
2、schedule_work(struct work_struct *work)对工作进行调度,即把给定工作的处理函数提交给缺省的工作队列和工作者线程。工作者线程本质上是一个普通的内核线程,在默认情况下,每个CPU均有一个类型为“events”的工作者线程,当调用schedule_work时,这个工作者线程会被唤醒去执行工作链表上的所有工作。
3、schedule_delayed_work(struct work_struct *work, unsigned long delay);延迟执行工作,与schedule_work类似。
4、flush_scheduled_work(void);刷新缺省工作队列。此函数会一直等待,直到队列中的所有工作都被执行。
5、cancel_delayed_work(struct work_struct *work);并不取消任何延迟执行的工作,因此,如果要取消延迟工作,应该调用cancel_delayed_work。
针对Linux内核,如下机制严重地影响了实时性
Linux实时改造后的系统实时性较好,典型代表有:
Kurt-Linux,RED-Linux,RT-Linux、RTAI和Xenomai等。
RT-Linux中的实时任务在运行过程当中总是处于以下三种状态之一:
安装RT-Linux的方法和步骤
在基于Adeos的系统中,存在着A、B、C、D四种类型的交互。Linux内核和xenomai分别作为Adeos中的一个域存在。Linux内核负责非实时任务的调度,而xenomai采用不同于Linux的精度更高的定时中断来调度实时任务,实现更小的调度延时。另外,xenomai域的优先级高于Linux域。
Xenomai除了在内核层利用Adeos实现了硬实时外,它在用户空间也有很好的实时性。
xenomai的补丁及配置移植步骤
RT-Linux的实时内核的主要API
1)硬中断API
2)软中断API
3)内核实时线程编程API,主要有以下几个(在rtl_sched.h中声明):
4)要使用共享内存通信,需要在内核中插入mbuff.o模块,可以使用mubff_alloc() 和mbuff_free()函数申请和释放共享内存
5)RT-Linux提供的操作实时FIFO的API主要有(在rtl_fifo.h中声明):
几类常用的Xenomai 的native API
1、任务管理
Xenomai 本身提供的一系列多任务调度机制,主要有以下一些函数:
2、内存堆服务
3、信息管道服务
1. 获取文件的信息:stat(char* filename, struct stat* buf); struct stat { dev_t st_dev; /* 设备 */ ino_t st_ino; /* 节点 */ mode_t st_mode; /* 形式 */ nlink_t st_nlink; /* 硬连接 */ uid_t st_uid; /* 用户ID */ gid_t st_gid; /* 组ID */ dev_t st_rdev; /* 设备类型 */ off_t st_off; /* 文件字节数 */ unsigned long st_blksize; /* 块大小 */ unsigned long st_blocks; /* 块数 */ time_t st_atime; /* 最后一次访问时间 */ time_t st_mtime; /* 最后一次修改时间 */ time_t st_ctime; /* 最后一次改变时间(指属性) */ }; struct statfs { long f_type; /* 文件系统类型 */ long f_bsize; /* 块大小*/ long f_blocks; /* 块多少*/ long f_bfree; /* 闲暇的块()*/ long f_bavail; /* 可用块 */ long f_files; /* 总文件节点 */ long f_ffree; /* 闲暇文件节点 */ fsid_t f_fsid; /* 文件系统id */ long f_namelen; /* 文件名的最大长度 */ long f_spare[6]; /* spare for later */ }; stat(char* filename, struct stat* buf); struct stat { dev_t st_dev; /* 设备 */ ino_t st_ino; /* 节点 */ mode_t st_mode; /* 形式 */ nlink_t st_nlink; /* 硬连接 */ uid_t st_uid; /* 用户ID */ gid_t st_gid; /* 组ID */ dev_t st_rdev; /* 设备类型 */ off_t st_off; /* 文件字节数 */ unsigned long st_blksize; /* 块大小 */ unsigned long st_blocks; /* 块数 */ time_t st_atime; /* 最后一次访问时间 */ time_t st_mtime; /* 最后一次修改时间 */ time_t st_ctime; /* 最后一次改变时间(指属性) */ }; struct statfs { long f_type; /* 文件系统类型 */ long f_bsize; /* 块大小*/ long f_blocks; /* 块多少*/ long f_bfree; /* 闲暇的块()*/ long f_bavail; /* 可用块 */ long f_files; /* 总文件节点 */ long f_ffree; /* 闲暇文件节点 */ fsid_t f_fsid; /* 文件系统id */ long f_namelen; /* 文件名的最大长度 */ long f_spare[6]; /* spare for later */ }; 2. 获取文件访问权限或许判定文件是否存在: int access(char* filename, int mode); 3. 获取当前时间: time_t t;char* asctime(localtime(&t)); 或许 time(&t);char* ctime(&t); 得到的字符串形式为:Wed Mar 12 10:07:53 2003 4. 计算两个时刻之间的时间差 double difftime(time_t time2, time_t time1); 5. 删除某文件: int unlink(char* pathname); int remove(char* pathname); 6. 删除某目录: int rmdir(const char* pathname); 7. 获妥当前所在
目录名: char * getcwd(char *buf,size_t size); buf将会返回目前途径名称。8. 获取目录信息:DIR * opendir(const char * pathname); int closedir(DIR *dir); struct dirent * readdir(DIR *dir); struct dirent { long d_ino; /* inode number */ off_t d_off; /* offset to this dirent */ unsigned short d_reclen; /* length of this d_name */ char d_name [NAME_MAX+1]; /* file name (null-terminated) */ }; DIR * opendir(const char * pathname); int closedir(DIR *dir); struct dirent * readdir(DIR *dir); struct dirent { long d_ino; /* inode number */ off_t d_off; /* offset to this dirent */ unsigned short d_reclen; /* length of this d_name */ char d_name [NAME_MAX+1]; /* file name (null-terminated) */ };9. strerror(errno);函数会返回一个指定的错误号的错误信息的字符串. 10.得到当前途径下面一切的文件(蕴含目录)的个数 struct dirent **namelist; int num = scandir(".",&namelist,0,alphasort) 11./etc/ld.so.conf:蕴含共享库的搜索位置 检查执行文件调用了哪些共享库 shell>ldd a.out 共享库治理工具,一般在更新了共享库之后要运行该命令 shell>ldconfig 12.检查文件执行的速度 shell>time ./a.out 13.改变文件访问权限 int chmod(const char* path, mode_t mode); 14.改变文件大小 int chsize(int handle, long size); 15.把一个浮点数转换为字符串 char ecvt(double value, int ndigit, int *decpt, int *sign); 16.检测文件结束 int eof(int *handle); 17.检测流上的文件结束符 int feof(FILE *stream); 18.检测流上的错误 int ferror(FILE *stream); 19.装入并运行其它程序的函数int execl(char *pathname, char *arg0, arg1, ..., argn, NULL); int execle(char *pathname, char *arg0, arg1, ..., argn, NULL, char *envp[]); int execlp(char *pathname, char *arg0, arg1, .., NULL); int execple(char *pathname, char *arg0, arg1, ..., NULL, char *envp[]); int execv(char *pathname, char *argv[]); int execve(char *pathname, char *argv[], char *envp[]); int execvp(char *pathname, char *argv[]); int execvpe(char *pathname, char *argv[], char *envp[]); int execl(char *pathname, char *arg0, arg1, ..., argn, NULL); int execle(char *pathname, char *arg0, arg1, ..., argn, NULL, char *envp[]); int execlp(char *pathname, char *arg0, arg1, .., NULL); int execple(char *pathname, char *arg0, arg1, ..., NULL, char *envp[]); int execv(char *pathname, char *argv[]); int execve(char *pathname, char *argv[], char *envp[]);
int execvp(char *pathname, char *argv[]); int execvpe(char *pathname, char *argv[], char *envp[]);20.指数函数double exp(double x); 21. struct sockaddr{ unsigned short sa_family; /* address family, AF_xxx */ char sa_data[14]; /* 14 bytes of protocol address */ }; struct sockaddr_in { short int sin_family; /* Address family */ unsigned short int sin_port; /* Port number */ struct in_addr sin_addr; /* Internet address */ unsigned char sin_zero[8]; /* Same size as struct sockaddr */ }; struct in_addr { unsigned long s_addr; }; s_addr遵照网络字节顺序存储IP地址 sin_zero是为了让sockaddr与sockaddr_in两个数据结构保持大小雷同而保留的空字节。 使用的例子: struct sockaddr_in sa; sa.sin_family = AF_INET; sa.sin_port = htons(3490); sa.sin_addr.s_addr = inet_addr("132.241.5.10"); bzero(&(sa.sin_zero), 8); 注意:如果sa.sin_addr.s_addr = INADDR_ANY,则不指定IP地址(用于Server程序) { unsigned short sa_family; /* address family, AF_xxx */ char sa_data[14]; /* 14 bytes of protocol address */ }; struct sockaddr_in { short int sin_family; /* Address family */ unsigned short int sin_port; /* Port number */ struct in_addr sin_addr; /* Internet address */ unsigned char sin_zero[8]; /* Same size as struct sockaddr */ }; struct in_addr { unsigned long s_addr; }; s_addr遵照网络字节顺序存储IP地址 sin_zero是为了让sockaddr与sockaddr_in两个数据结构保持大小雷同而保留的空字节。 使用的例子: struct sockaddr_in sa; sa.sin_family = AF_INET; sa.sin_port = htons(3490); sa.sin_addr.s_addr = inet_addr("132.241.5.10"); bzero(&(sa.sin_zero), 8); 注意:如果sa.sin_addr.s_addr = INADDR_ANY,则不指定IP地址(用于Server程序) 22. #define UNIX_PATH_MAX 108 struct sockaddr_un { sa_family_t sun_family; /* AF_UNIX */ char sun_path[UNIX_PATH_MAX]; /* 途径名 */ }; 23. IP地址转换函数: unsigned long inet_addr (const char *cp); inet_addr将一个点分十进制IP地址字符串转换成32位数字表示的IP地址(网络字节顺序) char* inet_ntoa (struct in_addr in); inet_ntoa将一个32位数字表示的IP地址转换成点分十进制IP地址字符串。 这两个函数互为反函数 字节顺序转换: htons()--"Host to Network Short" htonl()--"Host to Network Long" ntohs()--"Network to Host Short" ntohl()--"Network to Host Long" 24. 获取当前
机器的CPU、内存使用状况 getrusage 25. open的使用中常用的flag和mode参数 int FILE_FLAG = O_WRONLY|O_APPEND|O_CREAT; int FILE_MODE = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH; 26. makefile中常用的符号: 预定义变量 含意 $* 不蕴含扩展名的目标文件名称。 $@ 目标的完整名称 $% 如果目标是归档成员,则该变量表示目标的归档成员名称。例如,如果目标名称 为 mytarget.so(image.o),则 $@ 为 mytarget.so,而 $% 为 image.o。 $+ 一切的依靠文件,以空格分开,并以涌现的先后为序,能够蕴含重复的依靠文件。 $< 第一个依靠文件的名称。 $? 一切的依靠文件,以空格分开,这些依靠文件的修改日期比目标的创立日期晚 $^ 一切的依靠文件,以空格分开,不蕴含重复的依靠文件。 AR 归档维护程序的名称,默认值为 ar。 ARFLAGS 归档维护程序的选项。 AS 汇编程序的名称,默认值为 as。 ASFLAGS 汇编程序的选项。 CC C 编译器的名称,默认值为 cc。 CCFLAGS C 编译器的选项。 CPP C 预编译器的名称,默认值为 $(CC) -E。 CPPFLAGS C 预编译的选项。 CXX C++ 编译器的名称,默认值为 g++。 CXXFLAGS C++ 编译器的选项。 FC FORTRAN 编译器的名称,默认值为 f77。 FFLAGS FORTRAN 编译器的选项。 用变量object表示一切的.o文件: objects := $(wildcard *.o) make -n或许--just-print表示只是显示命令,但不会执行命令 make -s或许--slient表示片面阻止命令的显示 make -i或许--ignore-errors表示Makefile中一切命令都会疏忽错误 make -k或许--keep-going表示如果某规矩中的命令出错了,那么就终止该规矩的执行,但继续执行其它规矩 在makefile中直接利用shell获取变量PLAT 使用make中的一种用变量来定义变量的方法。这种方法使用的是“:=”操作符 PLAT := $(shell uname -a) 咱们要定义一个变量,其值是一个空格,那么咱们能够这样来: nullstring := space := $(nullstring) # end of the line FOO ?= bar含意是: 如果FOO没有被定义过,那么变量FOO的值就是“bar”,如果FOO先前被定义过,那么这条语将什么也不做,其等价于: ifeq ($(origin FOO), undefined) FOO = bar endif foo := a.o b.o c.o bar := $(foo:.o=.c) 咱们先定义了一个“$(foo)”变量,而第二行的意思是把“$(foo)”中一切以“.o”字串“结尾”整个交换成“.c”,所以咱们的“$(bar)”的值就是“a.c b.c c.c”。 你想在Makefile中设置参数值,你能够使
用“override”指示符。其语法是: override <variable> = <value> override <variable> := <value> 当然,你还能够追加: override <variable> += <more text> make运行时的系统环境变量能够在make开始运行时被载入到Makefile文件中, 然而如果Makefile中已定义了这个变量,或是这个变量由make命令行带入, 那么系统的环境变量的值将被覆盖。 如果make指定了“-e”参数,那么,系统环境变量将覆盖Makefile中定义的变量
一嵌入式系统原理与应用课程总结这个学期我学习了嵌入式原理与应用这门课程虽然这个学期马上就要结束了对嵌入式的学习也要告一段落了但是我…
1什么是嵌入式系统嵌入式系统是嵌入式计算机系统的简称是一种嵌入在设备或系统内部的特定应用而设计开发的专用的计算机系统英国电气工程师…
嵌入式总结1嵌入式系统的定义以应用为中心以计算机技术为基础软件硬件可裁剪适应应用系统对功能可靠性成本体积功耗严格要求的专用计算机系…
第一章1嵌入式系统定义以应用为中心以计算机技术为基础软件硬件可裁剪对功能可靠性成本体积功耗严格要求的专用计算机系统2四个基本要素1…
嵌入式系统总结嵌入式计算机嵌入式系统是专用计算机以核心部件的形式出现在各种装置设备产品和系统中例如监控设备移动电话家电机器人视听设…
第一章嵌入式系统概述1、嵌入式系统的定义、特点1)定义以应用为中心,以计算机技术为基础,软硬件可裁剪,适应应用系统对功能、可靠性、…
学习嵌入式系统心得说实在话在没有学习之前,以及在学之前通过一些口中得知这是一门很不错,很有意思的一门课。而且目前是十分吃香的一门课…
一为什么学习嵌入式1就业前景近几年嵌入式系统产品日臻完善并在全世界各行业得到广泛应用嵌入式系统产品的研制和应用已经成为我国信息化带…
嵌入式总结1嵌入式的定义广义的说嵌入式系统就是一个具有特定功能或用途的计算机软硬件集合体从狭义上说嵌入式系统紧紧指装入另一个设备并…
重庆航天技术职业学院题目嵌入式系统Android选题性质设计报告其他院系电子系专业物联网班级120xx071学号20xx0027学…