linux里面,有一个结构体task_struct,也叫“进程描述符”的数据结构,它包含了与进程相关的所有信息,它非常复杂,每一个字段都可能与一个功能相关,所以大部分细节不在我的研究范围之内,在这篇文章里面只讲述这些数据结构的组织方式,相当于一个知识点的大的梗概或骨架,如果骨架搞明白了,那么内部的细节就可以抽丝剥茧,搞明白也非难事。

一,链表

很简单,上面所说的进程描述符以双向链接的形式组织起来,说起来很简单,但还是有一些特色在里面的

1,在Linux内核链表中,不是在链表结构中包含数据,而是在数据结构中包含链表节点。

在内核中定义了list_head的一个数据结构,struct list_head { struct list_head *next, *prev;}; 它只含有两个字段。它就组织成了一个没有数据域的双向链表,通过在task_struct中包含一个list_head数据结构,实现了task_struct的双向链接。

但是,list_head的指针只是指向list_head自己的地址,怎样通过list_head指针,来获取task_struct的地址呢?方法如下:

#define list_entry(ptr, type, member)    container_of(ptr, type, member)

#define container_of(ptr, type, member)      ({ const typeof( ((type *)0)->member ) *__mptr = (ptr);  
                                                                         (type *)( (char *)__mptr - offsetof(type,member) );})

#define offsetof(type,  member)    ((size_t) &((type *)0)-> member)

解释如下:

通过定义一个task_struct指针p,其地址指向0,然后获取p->list_head的地址,就可以获取list_head在task_struct中的偏移量,这应该是个常量。然后就用list_head的地址减去这个常量 ,就得到了task_struct的地址。

参考文献:http://www.cnblogs.com/Daniel-G/archive/2013/09/06/3305834.html

2,140个优先权队列

进程的优先权有140个,为了调度的需要,内核就组织了140个链表,每个链表代表一个优先权。这通过在task_struct中包含一个list_head字段来实现。

所有的这些链接通过一个prio_array_t的数据结构实现。如下,在里面我们看到了bitmap位图数据结构的使用。

3,等待队列

进程经常等待某些事件的发生,例如等待一个磁盘操作的终止。

当进程等待一些资源时,内核就将这个进程放到此资源对应的等待队列中。

二,哈希表

以链表的形式组织task_struct数组,特点就是灵活。但如果想通过PID获取到对应的task_struct的地址,仅仅使用链表还是不够的,O(1)神器hash_table可以解决这个问题。

内核初始化时,动态的创建4个哈希表,如下:

哈希表就不多说了,下面简单的说一下TGID哈希表的结构,如下图。

举例说明,例如现在内核要回收TGID=4351的所有进程,那么我们立即就可以得到TGID=4351的进程所在的位置,一般情况下,我们通过哈希表只得到一个节点,但内核的哈希表扩展了一下,就是将TGID=4351的所有进程都链接到一个链表中,那么遍历链表就可以获取TGID=4351的所有进程了。

三,位图

1,每个进程对有一个唯一标记PID,默认情况下最大的PID号是32767,但这个值可以更改,那么怎么做到循环使用PID呢,内核通过一个pidmap_array位图来表示当前已经分配的PID号的闲置的PID号。也就是用32767个bit就可以解决这个问题。

2,上面所讲到的优先权队列中也有bitmap的使用,用5个unsigned long型,也就是160个bit完全可以满足140个优先权的使用。

读完《深入理解linux内核》第三章后,所学到的就是上面的内容。读得也不够深入,人为的忽略了很多细节的阅读,因为我的目标也不在于细节。

有两点感受:

1,感觉内核所用的数据结构也就是我们平常使用的到的数据结构。

2,内核把性能放在了第一位,有时候可以拿一些空间来换取时间,例如上面所讲到的hash表,TGID=4351和TGID=246的所有进程完全可以放在一个链表中,然后通过遍历来拿到TGID=4351的进程,但内核还是将它们分开,代价就是需要在每一个task_struct中再增加一对指针。

linux内核数据结构--进程相关的更多相关文章

  1. 24小时学通Linux内核之进程

    都说这个主题不错,连我自己都觉得有点过大了,不过我想我还是得坚持下去,努力在有限的时间里学习到Linux内核的奥秘,也希望大家多指点,让我更有进步.今天讲的全是进程,这点在大二的时候就困惑了我,结果那 ...

  2. (笔记)Linux内核中内存相关的操作函数

    linux内核中内存相关的操作函数 1.kmalloc()/kfree() static __always_inline void *kmalloc(size_t size, gfp_t flags) ...

  3. 深入Linux内核架构——进程管理和调度(上)

    如果系统只有一个处理器,那么给定时刻只有一个程序可以运行.在多处理器系统中,真正并行运行的进程数目取决于物理CPU的数目.内核和处理器建立了多任务的错觉,是通过以很短的间隔在系统运行的应用程序之间不停 ...

  4. Linux内核之进程地址空间

    Linux内核之进程地址空间 内核中的函数以相当直接了当的方式获得动态内存: __get_free_pages 或 alloc_pages从分区页框分配器中获得页框; kmem_cache_alloc ...

  5. (转)Linux内核之进程和系统调用

    Linux内核之进程和系统调用 什么是系统调用 在Linux的世界里,我们经常会遇到系统调用这一术语,所谓系统调用,就是内核提供的.功能十分强大的一系列的函数.这些系统调用是在内核中实现的,再通过一定 ...

  6. linux内核数据结构之链表

    linux内核数据结构之链表 1.前言 最近写代码需用到链表结构,正好公共库有关于链表的.第一眼看时,觉得有点新鲜,和我之前见到的链表结构不一样,只有前驱和后继指针,而没有数据域.后来看代码注释发现该 ...

  7. 分析Linux内核中进程的调度(时间片轮转)-《Linux内核分析》Week2作业

    1.环境的搭建: 这个可以参考孟宁老师的github:mykernel,这里不再进行赘述.主要是就是下载Linux3.9的代码,然后安装孟宁老师编写的patch,最后进行编译. 2.代码的解读 课上的 ...

  8. linux内核数据结构学习总结

    目录 . 进程相关数据结构 ) struct task_struct ) struct cred ) struct pid_link ) struct pid ) struct signal_stru ...

  9. Linux内核分析--进程创建,执行,切换

    学号:351 原创作品转载请注明出处本实验来源 https://github.com/mengning/linuxkernel/ 实验要求 从整理上理解进程创建.可执行文件的加载和进程执行进程切换,重 ...

随机推荐

  1. mac下Apache + MySql + PHP网站开发

    最近接了个小活,做一个使用PHP语言和MySql数据库的动态网站.之前做过类型的网站,是在windows系统下做的,开发环境使用的是 AppServ 的PHP开发套件.现在有了我的大MAC,所以找了M ...

  2. Kivy中文显示

    Win7系统 下载 DroidSansFallback.ttf字体(android设备上自带了) 源代码第一行增加#-*- coding:utf-8 -*- 创建widget值定font_name s ...

  3. python【第十八篇】Django基础

    1.什么是Django? Django是一个Python写成的开源Web应用框架.python流行的web框架还有很多,如tornado.flask.web.py等.django采用了MVC的框架模式 ...

  4. C# 在SQLite数据库中存储图像 z

    C# 在SQLite数据库中存储图像 更多 0 C# SQLite   建表语句 CREATE TABLE [ImageStore]([ImageStore_Id] INTEGER NOT NULL ...

  5. C# 两时间,时间间隔

    #region 返回时间差        public static string DateDiff(DateTime DateTime1, DateTime DateTime2)        {  ...

  6. Redis总录

    设计 选择合适的数据对象来存储对象:String,List,Hash(Entity角色对象),Set,Zset(需要排序): 选择存储是全局的,还是局部的: 机制 批处理(pipeline) 事务(w ...

  7. IEngineEditor与IWorkspaceEdit,以及相关的事件监听

    转自原文 IEngineEditor与IWorkspaceEdit,以及相关的事件监听 IEngineEditor适用于直接在图层上的编辑,例如使用"要素编辑"工具菜单上的&quo ...

  8. java项目打成jar包时引用了第三方jar,此时我们该如何解决呢

    Web项目做多了,反而对单纯的java项目陌生了,今天我们在开发项目的过程中,碰到一个这样的需求:需要将java项目放到linux系统上跑起来,当然这个javaSE项目是带main方法的.我们知道在I ...

  9. 第 15 章 组合模式【Composite Pattern】

    以下内容出自:<<24种设计模式介绍与6大设计原则>> 大家在上学的时候应该都学过“数据结构”这门课程吧,还记得其中有一节叫“二叉树”吧,我们上 学那会儿这一章节是必考内容,左 ...

  10. Solve Longest Path Problem in linear time

    We know that the longest path problem for general case belongs to the NP-hard category, so there is ...