static void init_thread(struct thread_t *t, void (* entry)(uint32_t), uint32_t args, priority_t p, int detached) memset((char*)t, 0, sizeof(thread_t)); t->stack_top=t->stack+STACK_SIZE - 1; /*align the stack_top*/ if((current==NULL)||detached) t->pid=0; t->pid=current->id;   /*put the parent id*/ current->num_child++; t->id=new_tid(); t->prio=p; thread_stack_push(t,args); thread_stack_push(t,(uint32_t)entry); thread_stack_push(t,(uint32_t)0); /*push a fake return address for thread func*/ t->stack_top -= sizeof(struct pt_regs); struct pt_regs *context = (struct pt_regs *)t->stack_top; context->gs = KERNEL_DS_SEL;//USER_DS_SEL; context->fs = KERNEL_DS_SEL;//USER_DS_SEL; context->es = KERNEL_DS_SEL;//USER_DS_SEL; context->ds = KERNEL_DS_SEL;//USER_DS_SEL; context->edi=0; context->esi=0; context->ebp=0; context->esp=(uint32_t)t->stack_top; context->ebx=0; context->edx=0; context->ecx=0; context->eax=0; context->eip=(uint32_t)thread_run; //tt->err_code=0x; context->cs=KERNEL_CS_SEL;//USER_CS_SEL; context->eflags=0x0200; t->state=CREATED; thread_t *create_thread(void (* entry)(uint32_t),uint32_t args, priority_t p, int detached) thread_t *t=kmalloc(sizeof(thread_t)); if(!t) KPRINTF("Insufficient memory for Task creation\n"); return NULL; init_thread(t, entry, args, p, detached); task_add(t); return t; static void thread_init() gdt_ptr_t gdt_desc; store_gdt(&gdt_desc); 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。
通过编译,最终会有3个执行文件被生成,adbd和两个adb程序。 adbd是设备终端的守护进程; adb一个是windows、linux、darwin或freebsd运行的程序,另一个是目标机上运行的程序。 Currently, a single 'adb' binary is used for both the server and client.