Linux内核设计基础(十)之内核开发与总结

(1)Linux层次结构:

(2)Linux内核组成:

主要由进程调度(SCHED)、内存管理(MM)、虚拟文件系统(VFS)、网络接口(NET)和进程间通信(IPC)等5个子系统组成。

(3)与Unix的差异:

  • Linux支持动态加载内核模块
  • 支持对称多处理(SMP)机制
  • Linux内核可以抢占
  • Linux内核并不区分线程和其他的一般进程
  • Linux提供具有设备类的面向对象的设备模型、热插拔事件,以及用户空间的设备文件系统(sysfs)

(4)内核开发的特点:

  • 内核编程时既不能访问C库也不能访问标准的C头文件
  • 内核编程时必须使用GNU C
  • 内核编程时缺乏像用户空间那样的内存保护机制
  • 内核编程时难以执行浮点运算
  • 内核给每个进程只有一个很小的定长堆栈
  • 由于内核支持异步中断、抢占和SMP,因此必须时刻注意同步和并发
  • 要考虑可移植性的重要性

(5)模块的编写及运行:

来个Hello World,程序员的老朋友了。

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

/*
 * hello_init 初始化函数,当模块装载时被调用,如果装载成功返回0,
 * 否则返回非零值
 */
static int hello_init(void)
{
	printk(KERN_ALERT "I bear a charmed life.\n");
	return 0;
}

/*
 * hello_exit 退出函数,当模块卸载时被调用
 */
static void hello_exit(void)
{
	printk(KERN_ALERT "Out, out, brief candle!\n");
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Qiushan");
MODULE_DESCRIPTION("A Hello, World Module");

这是最简单的内核模块,hello_init()是模块的入口点,通过module_init()注册到系统,在被装载时被调用。另外所有模块初始化函数必须符合下面的形式:

int my_init(void);

下面是Makefile的示例:

obj-m := hello.o

make -C /kernel/source/location SUBDIRS=$PWD modules

然后执行

sudo make modules_install

sudo insmod hello.ko //装载

sudo rmmod hello //卸载

(6)移植要注意对齐:

如果一个变量的内存地址正好是它长度的整数倍,那它就自然对齐。如,对于一个32位类型的数据,如果它在内存中的地址刚好可以被4整除(也就是最低两位为0),那它就自然对齐。对于RISC,载入未对齐的数据会导致处理器陷入

对齐原则:

  • 对于标准数据类型,地址只要是其长度的整数倍就对齐了。
  • 对于数组,只要按照基本数据类型进行对齐就可以了,随后的所有元素自然能够对齐。
  • 对于联合体,只要它包含的长度最大的数据类型能够对齐就可以了。
  • 对于结构体,只要结构体中每个元素能够正确对齐就可以了。

对于结构体,这里介绍一个例子:

struct animal_struct {
	char dog;                   /* 1 byte */
	unsigned long cat;    /* 4 bytes */
	unsigned short pig;  /* 2 bytes */
	char fox;                  /* 1 byte */
};

这可不是每个元素正确对齐。实际上编译器会作如下变动:

struct animal_struct {
	char dog;                   /* 1 byte */
	u8 __pad0[3];            /* 3 bytes */
	unsigned long cat;     /* 4 bytes */
	unsigned short pig;   /* 2 bytes */
	char fox;                    /* 1 byte */
	u8 __pad1;               /* 1 byte */
};

第一个填充__pad0是为了保证cat可以按照4字节对齐,这样自动使其它小对象都对齐了,最后一个填充__pad1是为了填补struct本身的大小,是这个结构体长度能被4整除,这样,由该结构体组成的数组中,每个数组项也就会自然对齐了。

struct animal_struct {
	unsigned long cat;     /* 4 bytes */
	unsigned short pig;   /* 2 bytes */
	char dog;                    /* 1 byte */
	char fox;                     /* 1 byte */
};

Linux内核设计基础(十)之内核开发与总结,布布扣,bubuko.com

时间: 2024-10-12 19:06:29

Linux内核设计基础(十)之内核开发与总结的相关文章

Linux系统管理之十二---内核编译升级

一.内核基础 1.内核下载地址www.kernel.org 2.内核核心存于:/boot/vmlinuz-version, 用uname  -r命令查询版本号.   内核模块存于:/lib/modules/version 3.linux内核设计:   单内核+模块 4.用户空间访问.监控内核的方式:通过修改/proc, /sys,这两个目录中文件的内容,来访问.修改.监控内核的特性. /proc  :大部分是只读的.     /proc/sys:大多数是可读写的.  设定内核数值的方法::   

Linux学习笔记&lt;十八&gt;——内核编译

内核由核心和内核模块两部分组成 核心:/boot/vmlinuz-version 内核模块(ko):/lib/modules/version/ 查看内核版本 uname -r 主版本号.次版本号(偶数表示稳定版本,奇数表示测试版本).修订版本号(修订的次数) 用户空间访问.监控内核是通过访问修改/proc,/sys目录下的文件(即设定内核的参数值)实现的 /proc/sys:此目录中的文件很多是可读写的 /sys:某些文件可写 设定内核参数值的方法: 1.echo VALUE > /proc/s

Linux内核设计基础(九)之进程管理和调度

在Linux中进程用结构体task_struct来管理一个进程所需的所有信息(所以一般较大,在32位机上,大约有1.7KB).为了提高效率,Linux使用了一些卓越的技术. 通过slab分配task_struct结构 Linux创建进程迅速,正是因为slab分配器预先分配和重复使用task_struct,这样就避免了动态分配和释放所带来的资源消耗(毕竟一个task_struct较大,而且内核中进程的创建和消除很频繁). 将task_struct放置在内核栈的尾端 这样做是为了让那些像x86那样寄

Linux内核设计基础(六)之块I/O层

块设备是指能随机访问固定大小数据片的设备,如硬盘:字符设备(如串口和键盘)是按照字符流的方式有序访问.区别在于是否可以随机访问数据--也就是能否在访问设备时随意地从一个位置跳转到另一个位置.我们可以感觉到块设备的控制要比字符设备复杂多,实际上内核在块设备上下了大工夫--块I/O层. 基础概念 块设备中最小的可寻址单元是扇区. 文件系统的最小寻址单元是块. 所谓的缓冲区是块在内存中的表示. 对于一个缓冲区(块),内核需要知道它的控制信息,这时需要一个结构进行描述--缓冲区头. I/O调度机制 首先

Linux内核设计基础(四)之虚拟文件系统

先来看一下写文件函数write的执行过程: ret = write(fd, buf, len); write适用于各种文件系统,它首先执行sys_write(),而正是这个sys_write()进行实际文件系统类型的判别并执行该类型文件系统下的写操作.我们可以看出在多种多样的文件系统上抽象出了一个通用接口性质的虚拟文件系统. 我们这里非常关心Linux 2.6是如何去实现VFS的.先来看一下VFS中的四个主要的对象类型: 超级块对象,它代表一个具体的已安装文件系统. 索引节点对象,它代表一个具体

Linux内核设计基础(八)之内核数据结构

我个人比较喜欢学习数据结构,而Linux内核中实现的数据结构会是我们去学习.理解和应用数据结构的一个很好途径.这里介绍内核中广泛应用的四种数据结构:链表.队列.映射和二叉树. 链表: Linux内核讲求高效精简,所以有时需要我们动态去创建和分配内存,这时就要借助链表,我们根据实际情况分配内存后,只需修改链表的指针,仍能索引到刚分配的内存区.链表分单向链表.双向链表和循环链表. 单向链表 struct list_element { void *data; struct list_element *

十天学Linux内核之第一天---内核探索工具类

原文:十天学Linux内核之第一天---内核探索工具类 寒假闲下来了,可以尽情的做自己喜欢的事情,专心待在实验室里燥起来了,因为大二的时候接触过Linux,只是关于内核方面确实是不好懂,所以十天的时间里还是希望能够补充一下Linux内核相关知识,接下来继续待在实验室里想总结一下Linux内核编程,十天肯定完全掌握不了Linux内核,这里我也只是把自己认为不是很好懂并且很重要的难点疑点写出来,和大家一起分享,希望大家改正互相学习. Linux的具体概述这里就不多说了,今天主要讲的是Linux内核中

Linux内核设计基础(七)之系统调用

我理解的系统调用就是内核提供的一组用户进程与内核进行交互的接口.除异常和陷入外,系统调用是内核唯一的合法入口.像/proc也是通过系统调用进行访问的. 系统调用的意义: 让用户进程受限地访问硬件设备 为用户空间提供一种硬件的抽象借口 提供了创建新进程并与已有进程进行通信的机制 提供了申请操作系统其他资源的能力 保证系统稳定可靠,避免应用程序恣意妄为 系统调用的基本原理: 系统调用通常的入口是C库中定义的函数,也可以是自定义的函数(通过syscall进行调用).每个系统调用被赋予一个系统调用号,通

Linux内核设计基础(五)之内存管理

我感觉学习操作系统首先要从内存分配和管理入手.首先我们应该知道现代操作系统是以页为单位进行内存管理的,32位体系结构支持4KB的页,而64位体系结构支持8KB的页.页是用来分配的,如何才能进行高效和充分的利用,这是内存管理单元(MMU)应当仔细考虑的. 页分配 内核用结构体struct page表示每个物理页.内核用这一结构来管理系统中所有的页,因为内核需要知道一个页是否空闲(也就是页有没有被分配),如果页已经被分配,内核需要知道谁拥有这个页,拥有者可能是用户空间进程.动态分配的内核数据.静态内