dump_gdt(&gdt_desc);
#include #include #include struct thread_t SECTION(".task0") ALIGN(PAGE_SIZE) task0; struct thread_t *current = &task0;static struct list_t *ptask_list = &(task0.link);
通过本课程的学习,可以达到以下目的:1、通过asm.s及trap.c的学习可以详细了解带错误码和不带错误码的硬件中断处理流程,以及这个过程中
内核
堆栈的变化过程;2、通过system_call.s及sys.c的学习,了解系统调用的过程,知道系统如何设置的72个系统调用函数;3、通过对
sched
.c的学习,了解任务调度相关的队列、时间片消耗、任务状态间的关系;4、在signal.c中我们将会学习到信号处理过程中
内核
堆栈和用户堆栈的操作过程,对sigaction函数与signal函数有更深入的理解;5、通过exit.c的学习对系统编程中的kill、waitpid函数会有更深入的理解;5、mktime.c中对系统如何构建从1970年1月1日0时开始的时间及闰年的处理有最原始的描述;6、最后,课程会介绍与
内核
打印相关的函数的实现细节。
sched
.c主要实现任务表初始化、任务调度、定时器、以及每个任务的处理。其中定时器部分直接拷贝
linux
sched
.c的
代码
。
sched
.c源
代码
:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
sched
.c:
kernel/里面一个非常重要的角色,就是它。所有进程运行都在它的管控之内,因此学习好这个.c事关重大,有些地方我个人认为是需要细致分析的,不能草率带过。为了尽量不遗漏任何一个可疑的痕迹,我们需要挨着盲扫所有的变量及其函数,即使遇到完全不懂的内容,我们也需标记下来,等后面懂了在做补充。
一、变量(define):
1. _BLO
struct task_struct ** p;
/* check alarm, wake up any interruptible tasks that have got a signal */
for(p = &amp...
#define _
SCHED
_H
#define NR_TASKS 64 // 系统中同时最多任务(进程)数。
#define HZ 100 // 定义系统时钟滴答频率(1 百赫兹,每个滴答10ms)
#define FIRST_TASK task[0] // 任务0 比较特殊,所以特意给它单独定义一个符号。
#define LAST_TASK task
写着
sched
这节却是在说红黑树,惊不惊喜意不意外。。。。因为我跑飞了。。。
AVL树: 最早的平衡二叉树之一。应用相对其他数据结构比较少。windows对进程地址空间的管理用到了AVL树。
红黑树: 平衡二叉树,广泛用在C++的STL中。如map和set都是用红黑树实现的。
B/B+树: 用在磁盘文件组织 数据索引和数据库索引。
Trie树(字典树): 用在统计和排序大量字符串,如自动机。
O(n)结构:list/栈/队列
O(1)结构:数组/hash/位图
O(logn)树
sched
.c 程序
1 功能描述
sched
.c 是
内核
中有关任务调度函数的程序,其中包括有关调度的基本函数(sleep_on、 wakeup、
sched
ule 等)以及一些简单的系统调用函数(比如
getpid())。另外 Linus 为了编程的方便,考虑到软盘驱动器程序定时的需要,也将操作软盘的
3、调度函数
sched
ule()分析
当kernel/
sched
.c:
sched
_tick()执行完,并且时钟中断返回时,就会调用kernel/
sched
.c:
sched
ule()完成进程切换。我们也可以显示调用
sched
ule(),例如在前面“
Linux
进程管理“的介绍中,进程销毁的do_exit()最后就直接调用
sched
ule(),以切换到下一个进程。
sched
ule(
#include <
linux
/kernel.h> #include <
linux
/
sched
.h> #include <
linux
/module.h> #include <
linux
/init.h> #include <
linux
/moduleparam.h> static pid_t pid=1; module_param(pid, int, 0644); static int module1_init(void) { struct task_struct *p; struct list_head *pp; struct task_struct *psibling; //当前进程的PID p = pid_task(find_vpid(pid),PIDTYPE_PID); printk("me: %d %ld %s \n",p->pid,p->state,p->comm); //父进程 if(p->parent == NULL){ printk("No Parent\n"); } else{ printk("Parent:%d %ld %s \n",p->parent->pid,p->parent->state,p->parent->comm); } //兄弟进程 list_for_each(pp,&p->parent->children) { psibling = list_entry(pp,struct task_struct,sibling); printk("Brother %d %ld %s \n",psibling->pid,psibling->state,psibling->comm); } //子进程 list_for_each(pp,&p->children) { psibling = list_entry(pp,struct task_struct,sibling); printk("Children %d %ld %s \n",psibling->pid,psibling->state,psibling->comm); } return 0; } static void module1_exit(void) { printk(KERN_ALERT"goodbye!\n"); } module_init(module1_init); module_exit(module1_exit); MODULE_LICENSE("GPL");
这是一个
Linux
内核
模块,可以获取指定进程的父进程、兄弟进程、子进程的信息,并打印输出。具体实现是通过调用
Linux
内核
中的进程任务结构体 `task_struct` 中的成员变量来获取这些信息的。
其中,`module_param` 宏用于接收命令行参数,`module_init` 和 `module_exit` 宏分别用于指定模块的初始化函数和退出函数。`pid_task` 函数用于获取指定 PID 对应的进程任务结构体指针,而 `list_for_each` 宏则用于遍历双向链表。
需要注意的是,该模块需要在
Linux
内核
源码目录下进行编译并加载,而且只能在特定的
内核
版本中运行。同时,也需要在加载时指定要查询的进程的 PID,例如:
insmod module1.ko pid=1234
这里的 `1234` 就是要查询的进程的 PID。