1、Linux内核的主要功能
(1)资源抽象:用软件接口抽象不同硬件资源的,简化对其的操作。如设备驱动程序。
(2)资源分配:把抽象出来的各种资源分配给各个进程并负责取回这些系统资源。经编译后的目标程序只有放入内存(RAM)才能执行,目标程序执行时的CPU操作抽象为进程。
(3)资源共享:处理资源竞争情况

2、Linux属于单内核,内核包含:内存管理、设备驱动、系统调用。微内核中这些则是由内核上层系统进程实现的(OS各层之间调用会产生消耗)。Linux采用“模块”来弥补单内核不易移植,模块能在运行时动态链接到内核。注意:模块依然在内核模式下执行。非抢占式,内核不会被其他程序抢占。

3、重新编译内核
(1)去www.kernel.org/pub/linux/kernel下载内核源码,如下载linux-2.6.tar.bz2
解压:tar -xjvf linux-2.6.22.6.tar.bz2
(2)
cd linux-2.6.22.6
清除目录下所有配置文件和先前生成的中间文件
make mrproper

配置:
make config 基于文本的传统配置界面
make menuconfig 基于文本的选单式配置界面
make xconfig 基于图形窗口模式的配置界面
‘Y’该功能编译进内核
‘N’不编译进内核
‘M’编译成可动态插入的模块

(3)
make clean 清除目标文件,确保所有相关文件处于最新状态
make bzImage 产生压缩形式的内核文件,位于/linux-2.6.22.6/arch/i386/boot下,这里编译的CPU架构为Intel 80x86

make modules_install 对选择的模块进行编译,并安装到标准模块目录(主机的lib/modules/下,lsmod查看当前内核已经装载了那些模块)

(4)Linux系统引导后从/boot目录下读取内核映像到内存,想使用自己编译的内核就要把它拷到/boot下。需要拷bzImage和System.map(记录内核镜像中符号和其对应地址,一般调试时会用到)。最后修改启动管理程序(如lilo和grup)的配置选项。

4、虚拟文件系统/proc,它存于内存中,通过它里面的一些文件可以获得系统状态信息并且修改系统的配置信息。很多显示系统信息的工具都是通过读取/proc下的文件实现的。
命令procinfo:显示系统整体信息
文件/proc/meminfo :内存信息

5、读取命令行参数
GUN/Linux遵循统一的命令行格式:
(1)短格式:一个‘-’,如‘-l’
(2)长格式:两个‘- -’,如‘- -help’
GNU C库提供getopt_long函数处理命令行,需要包含头文件getopt.h

6、程序

#include <stdio.h>
#include <getopt.h>
#include <stdlib.h>
#include <sys/time.h>

const char *program_name;
struct timeval now;
FILE *fp;
char buf[50];
int main(int argc, char *argv[])
{
        int return_option;
        const char *const short_option="hl";
        const struct option long_option[]={
                {"time",0,NULL, 't'},
                {"hostname",0,NULL,'h'},
                {NULL,0,NULL,0}//结尾必须加的一行
        };

        program_name = argv[0];
        do{
                return_option = getopt_long(argc,argv,short_option,long_option,NULL);
                switch(return_option)
                {
                        case 't':
                                gettimeofday(&now,NULL);
                                printf("Kernel Status Report at %s",ctime(&(now.tv_sec)));
                        case 'h':
                                fp=fopen("/proc/sys/kernel/hostname","r");
                                fgets(buf,40,fp);
                                printf("Machine hostname is:%s",buf);
                                fclose(fp);
                        case -1:
                                break;
                        case '?':
                                printf("error\n");
                        default:
                                abort();
                }

        }while(return_option != -1);

        return 0;
}

$ ./a.out -t
Kernel Status Report at Mon Nov 13 17:19:53 2017

6、函数解释

短格式     长格式     含义
-t      --time      打印时间
-h      --hostname  打印主机名

int getopt_long(int argc, char * const argv[],const char *optstring, const struct option *longopts,int *flag);

optstring:  短格式如“ht”//某个选项后面有参数,则在该字符后面加上“:”
longopts:   长格式如
const struct option *longopts[]={
{"time",0,NULL,'t'},
//第二个参数:0无参数,1有参数,2参数可选
//第三个参数:决定返回值,NULL返回最后一项的字符,否则返回0
{"hostname",0,NULL,'h'}
{NULL,0,NULL,0}
};

flag:决定返回值,如果flag是null,则函数会返回与该项option匹配的val值;如果flag不是NULL,则将val值赋予flag所指向的内存,并且返回值设置为0。
当getopt_long()将命令行所有参数全部解析完成后,返回-1。
无定义选项,返回‘?’

int gettimeofday(struct timeval*tv, struct timezone *tz);
其参数tv是保存获取时间结果的结构体,参数tz用于保存时区结果:
struct timezone{
int tz_minuteswest;/*格林威治时间往西方的时差*/
int tz_dsttime;/*DST 时间的修正方式*/
}
timezone 参数若不使用则传入NULL即可。
而结构体timeval的定义为:
struct timeval{
long int tv_sec; // 秒数
long int tv_usec; // 微秒数
}

FILE * fopen(const char * path, const char * mode);
返回值:文件顺利打开后,指向该流的文件指针就会被返回。如果文件打开失败则返回 NULL

7、调试gdb
(1)启动gdb

//编译加入调试信息
gcc -g getopt.c -o getopt
//启动
gdb getopt

(2)列出源代码

list

(3)断点

break n     //某行设置断点
break fun   //函数名前设置断点
delete n    //删除断点
step        //单步,进入函数
next        //单步,执行完函数

(4)观察变量

print return_option //打印变量值
whatis return_option    //打印变量类型