百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

Linux内核原理到代码详解《内核视频教程》

off999 2025-09-19 01:10 2 浏览 0 评论


Linux内核原理-进程入门


进程

进程不仅仅是一段可执行程序的代码,通常进程还包括其他资源,比如打开的文件,挂起的信号,内核内部的数据结构,处理器状态,内存地址空间,或多个执行线程,存放全局变量的数据段等。线程是进程中活动的对象,每个线程都拥有一个独立的程序计数器,进程炸,和一组进程寄存器。内核调度的对象是线程,而不是进程。传统的Unix系统中一个进程只包含一个线程。对于linux而言,线程只不过是一种特殊的进程罢了。在linux系统中通过fork()来复制现有进程的资源和创建一个新的进程。随后调用exec这组函数创建自己的地址空间最后载入要运行的程序,在linux中fork其实是clone系统调用来实现。程序执行完毕后使用exit退出执行,父进程调用wait或waitpid来等待子进程结束,并回收其资源。

进程描述符及任务结构

在linux内核中,使用了一个task_struct结构体来描述进程信息,并且通过双向循环链表将所有的进程连接起来。一个task_struct描述了进程打开文件信息,状态信息,地址空间信息,挂起的信号,进程的状态等等。

进程之间的关联如下图:


进程描述符的分配

在linux中进程描述符task_struct是通过slab分配器来进行分配的,这样可以达到对象复用和缓存着色的效果。task_struct这个结构体本身就很大,这个结构体在内核中会不断的进行分配和释放,这样很不高效,使用了salb分配器后只需要进行分配释放是没有开销的,slab释放了task_struct只是放在其对象池中,并没有真正释放。然后在2.6内核之前,task_struct的分配和释放不是通过slab分配器,而是直接放在内核栈的栈底,这样就可以通过栈顶指针很快的计算出task_struct的地址,因为在内核中task_struct是最经常要访问的数据结构,所以需要一个机制很快的获取当前进程的task_struct结构体的地址,在x86这种体系结构中,因为寄存器的缺乏没有独立的寄存器用来存放task_struct的地址,所以就通过这种方式来快速计算,在PowerPC系列的计算机中则是使用一个寄存器来存放task_struct的地址。在2.6内核后为了避免动态内存分配和释放所带来的资源消耗,采用了slab分配器来管理task_struct结构体,但是为了快速计算task_struct的地址,linux在栈低存放了一个thread_info结构 在这个结构中第一个元素就是当前的task_struct地址,这样就可以很快的计算出task_strcut的地址,并且task_struct交由slab分配器来管理,可以避免资源消耗。

获得thread_info地址的方法




下面是进程内核栈的图示:



进程的状态

在task_struct中的state字段表示的就是进程的状态



在这里使用了volatile来修饰state变量,主要是因为state需要实时从内存访问最新的值,而不是读取寄存器中的这个值默认gcc会对其进

行优化,将state的值读入寄存器,每次访问寄存器中值,但是在多线程的环境中,state的值随时可能会改变,所以加入了volatile来修

饰。从注释可以看出 state有三个值,-1 0 或者大于0,分别表示不可运行,就绪,停止,对于停止又细分出很多种,可以看下内核中对进程状态的定义:



进程状态转化如下图:



,,内核中一些操作进程状态的函数:


注:对于内存屏障可以参考这篇博文,更多关于内存屏障的知识可以谷歌

进程的上下文

所谓的进程上下文其实就是进程的当前状态,一组状态数据而已,在进程切换的时候,保存当前进程的数据,载入要切换进程的数据,这样就可以实现进程的切换。状态数据通常包含CPU所有寄存器的值,进程的状态,堆栈中的内容等等。



内核页表和进程页表,每个进程都有自己的页表,放在task_struct.pgd中,内核页表放在init_mm.pgd在保护模式下,从硬件角度看,其运行的基本对象为”进程”(或线程,而寻址则依赖于”进程页表”,在进程调度而进行上下文切换时,会进行页表的切换:即将新进程的pgd(页目录)加载到CR3寄存器中。内核页表中的内容为所有进程共享,每个进程都有自己的”进程页表”,”进程页表”中映射的线性地址包括两部分:用户态,内核态.其中内核态地址对应的相关页表项,对于所有进程来说都是相同的(因为内核空间对所有进程来说都是共享的),而这部分页表内容其实就来源于”内核页表”,即每个进程的”进程页表”中内核态地址相关的页表项都是“内核页表”的一个拷贝。

Linux内核代码详解,。早期的Linux内核引导代码只有bootsect.s、setup.s、head.s这3个文件,这三个文件都是Linus在1991年左右亲手写的。后来的代码虽然进行了加固,但是原型还是这几个。

Linux内核源代码

1. 首先要查看内核版本号:

【root@localhost ~】# uname -r // 查看内核版本号或者uname –a

如果是RHEL5的话内核应该是 2.6.18-8.el5xen

2. 已经知道自己的内核是“2.6.18-8.el5xen”,可以去此网站


http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.16.8.tar.gz 下载到符合自己系统的内核源码。

3. 用【root@localhost ~】#tar zxvf linux-2.6.16.8.tar.gz -C /usr/src

将文件解压到指定目录/usr/src。

4. 进入/usr/src目录下,用【root@localhost ~】#mv linux-2.6.18.8 linux将解压好的文件夹名“linux-2.6.18.8”改变成“linux”。

5. 进入/usr/src/linux目录下。分别运行:

make mrproper

make oldconfig

make

执行第二个命令时碰到提示一路回车就行,第三个命令如果要完全执行完的话,可能会需要几个小时,最好让它编译完毕之后,再装虚拟机工具。如果在make刚开始执行时,即使生成了version.h和utsrelease.h,若按Ctrl+C强行退出编译。在安装完VM-ware Tools后,很可能导致系统无法正常启动。

6. 编译完毕后,进入
/usr/src/linux/include/linux,用【root@localhost ~】#vi utsrelease.h (按i是插入,修改完后按Esc,然后按Shift+:,输入wq!按回车,修改完毕可以用#more utsrelease.h查看是否修改成功)将里面的版本号改成2.6.18-8.el5xen。

同上再修改version.h,在原来的基础上增加一行#define UTS_RELEASE "2.6.18-8.el5xen",保存退出。

7. 重新启动系统,如果不重启,在安装VM-ware Tools后可能会碰到一些问题

8. 重启后就可以正常安装VM-ware Tools了。

9. 假如要改变分辨率,运行
/usr/bin/vmware-config-tools.pl即可修改。


总结;关注+后台私信:资料”可免费领取 资料内容包括:C/C++,Linux,golang,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,WebRTC,ffmpeg 嵌入式 等

相关推荐

Linux 网络协议栈_linux网络协议栈

前言;更多学习资料(包含视频、技术学习路线图谱、文档等)后台私信《资料》免费领取技术点包含了C/C++,Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,Z...

揭秘 BPF map 前生今世_bpfdm

1.前言众所周知,map可用于内核BPF程序和用户应用程序之间实现双向的数据交换,为BPF技术中的重要基础数据结构。在BPF程序中可以通过声明structbpf_map_def...

教你简单 提取fmpeg 视频,音频,字幕 方法

ffmpeg提取视频,音频,字幕方法(HowtoExtractVideo,Audio,SubtitlefromOriginalVideo?)1.提取视频(ExtractVi...

Linux内核原理到代码详解《内核视频教程》

Linux内核原理-进程入门进程进程不仅仅是一段可执行程序的代码,通常进程还包括其他资源,比如打开的文件,挂起的信号,内核内部的数据结构,处理器状态,内存地址空间,或多个执行线程,存放全局变量的数据段...

Linux C Socket UDP编程详解及实例分享

1、UDP网络编程主要流程UDP协议的程序设计框架,客户端和服务器之间的差别在于服务器必须使用bind()函数来绑定侦听的本地UDP端口,而客户端则可以不进行绑定,直接发送到服务器地址的某个端口地址。...

libevent源码分析之bufferevent使用详解

libevent的bufferevent在event的基础上自己维护了一个buffer,这样的话,就不需要再自己管理一个buffer了。先看看structbufferevent这个结构体struct...

一次解决Linux内核内存泄漏实战全过程

什么是内存泄漏:程序向系统申请内存,使用完不需要之后,不释放内存还给系统回收,造成申请的内存被浪费.发现系统中内存使用量随着时间的流逝,消耗的越来越多,例如下图所示:接下来的排查思路是:1.监控系统中...

彻底搞清楚内存泄漏的原因,如何避免内存泄漏,如何定位内存泄漏

作为C/C++开发人员,内存泄漏是最容易遇到的问题之一,这是由C/C++语言的特性引起的。C/C++语言与其他语言不同,需要开发者去申请和释放内存,即需要开发者去管理内存,如果内存使用不当,就容易造成...

linux网络编程常见API详解_linux网络编程视频教程

Linux网络编程API函数初步剖析今天我们来分析一下前几篇博文中提到的网络编程中几个核心的API,探究一下当我们调用每个API时,内核中具体做了哪些准备和初始化工作。1、socket(family...

Linux下C++访问web—使用libcurl库调用http接口发送解析json数据

一、背景这两天由于一些原因研究了研究如何在客户端C++代码中调用web服务端接口,需要访问url,并传入json数据,拿到返回值,并解析。 现在的情形是远程服务端的接口参数和返回类型都是json的字符...

平衡感知调节:“系统如人” 视角下的架构设计与业务稳定之道

在今天这个到处都是数字化的时代,系统可不是一堆冷冰冰的代码。它就像一个活生生的“数字人”,没了它,业务根本转不起来。总说“技术要为业务服务”,但实际操作起来问题不少:系统怎么才能快速响应业务需求?...

谈谈分布式文件系统下的本地缓存_什么是分布式文件存储

在分布式文件系统中,为了提高系统的性能,常常会引入不同类型的缓存存储系统(算法优化所带来的的效果可能远远不如缓存带来的优化效果)。在软件中缓存存储系统一般可分为了两类:一、分布式缓存,例如:Memca...

进程间通信之信号量semaphore--linux内核剖析

什么是信号量信号量的使用主要是用来保护共享资源,使得资源在一个时刻只有一个进程(线程)所拥有。信号量的值为正的时候,说明它空闲。所测试的线程可以锁定而使用它。若为0,说明它被占用,测试的线程要进入睡眠...

Qt编写推流程序/支持webrtc265/从此不用再转码/打开新世界的大门

一、前言在推流领域,尤其是监控行业,现在主流设备基本上都是265格式的视频流,想要在网页上直接显示监控流,之前的方案是,要么转成hls,要么魔改支持265格式的flv,要么265转成264,如果要追求...

30 分钟搞定 SpringBoot 视频推拉流!实战避坑指南

30分钟搞定SpringBoot视频推拉流!实战避坑指南在音视频开发领域,SpringBoot凭借其快速开发特性,成为很多开发者实现视频推拉流功能的首选框架。但实际开发中,从环境搭建到流处理优...

取消回复欢迎 发表评论: