内核 订阅
内核是操作系统最基本的部分。它是为众多应用程序提供对计算机硬件的安全访问的一部分软件,这种访问是有限的,并且内核决定一个程序在什么时候对某部分硬件操作多长时间。内核的分类可分为单内核和双内核以及微内核。严格地说,内核并不是计算机系统中必要的组成部分。 展开全文
内核是操作系统最基本的部分。它是为众多应用程序提供对计算机硬件的安全访问的一部分软件,这种访问是有限的,并且内核决定一个程序在什么时候对某部分硬件操作多长时间。内核的分类可分为单内核和双内核以及微内核。严格地说,内核并不是计算机系统中必要的组成部分。
信息
外文名
kernel
发源时间
1991年10月
类    别
软件
种    类
单内核,双内核,微内核
中文名
内核
内核基本简介
内核,是一个操作系统的核心。是基于硬件的第一层软件扩充,提供操作系统的最基本的功能,是操作系统工作的基础,它负责管理系统的进程、内存、 设备驱动程序、文件和网络系统,决定着系统的性能和稳定性。 [2]  现代操作系统设计中,为减少系统本身的开销,往往将一些与硬件紧密相关的(如中断处理程序、设备驱动程序等)、基本的、公共的、运行频率较高的模块(如时钟管理、进程调度等)以及关键性数据结构独立开来,使之常驻内存,并对他们进行保护。通常把这一部分称之为操作系统的内核。 [3]  程序可以直接地被调入计算机中执行,这样的设计说明了设计者不希望提供任何硬件抽象和操作系统的支持,它常见于早期计算机系统的设计中。最终,一些辅助性程序,例如程序加载器和调试器,被设计到机器核心当中,或者固化在只读存储器里。这些变化发生时,操作系统内核的概念就渐渐明晰起来了。 [4]  (概述图片来源:)
收起全文
精华内容
参与话题
问答
  • 鉴于此,《Linux内核精髓:精通Linux内核必会的75个绝技》选取了资源管理(CPU、内存、进程等)、文件系统、网络、虚拟化、省电、调试、概要分析、追踪、内核调整等Linux内核的核心主题进行了深入剖析和讲解,总结出...
  • Linux2.6.24内核注释

    千次下载 热门讨论 2014-05-29 22:42:05
    这是半年来,在看ULA的过程中,针对Linux 2.6.24内核顺手做的一点注释。内容不多,个人觉得文件系统和USB这两个模块的注释还有一点意思。 所有注释都是中文,您可以与标准2.6.24内核进行比较,看看具体的注释内容。 ...
  • linux2.6.1内核源码注释

    万次下载 热门讨论 2014-03-10 15:21:33
    包含LINUX内核同步、信号、内存、调度、文件系统、网络系统、时钟等部分的源码注释。前后历时三年,算是干货。
  • 一开始我并不想写这个笔记,因为太过复杂,我一直想以简单的方式理解内核,只从概念,避免涉及过多的代码。实际上,我写笔记的时候,书已经看到很后面了,因为总要理解更多才能理解之前看似简短实际复杂的内容。但...
    进程切换

    一开始我并不想写这个笔记,因为太过复杂,我一直想以简单的方式理解内核,只从概念,避免涉及过多的代码。实际上,我写笔记的时候,书已经看到很后面了,因为总要理解更多才能理解之前看似简短实际复杂的内容。但最后发现实际上任何内容都没有办法跳过,即便不想看,也需要了解基本的概念,所以依旧不会拿大段代码,但总会拿少量代码。

    如果不感兴趣,我觉得也可以跳过,只需要知道一个概念即可。关于进程切换有更详细的章节。。所以这里也并没有深入更多,只是笔记,也许以后会补充更多内容。

    为了控制进程的执行,内核必须有能力挂起正在CPU上运行的进程,并恢复以前挂起的某个进程的执行。这种行为被称为进程切换(process switch)、任务切换(task switch)或上下文切换(content switch)。

    硬件上下文

    尽管每个进程都有自己的地址空间,但所有进程必须共享CPU寄存器。因此,在恢复一个进程的执行之前,内核必须确保每个寄存器装载了挂起进程时所需要的值。

    进程恢复执行前必须装入寄存器的一组数据成为硬件上下文(hardware context)。硬件上下文是进程可执行上下文的一个自己,因为可执行上下文包含进程执行时所需要的所有信息。在Linux中,进程硬件上下午的一部分存放在TSS段,而剩余部分存放在内核态堆栈中。

    在下面描述中,假定用prev局部变量表示切换出的进程描述符,next表示切换进的进程描述符。因此,我们把进程切换定义为这样的行为:保存prev硬件上下文,用next硬件上下文代替prev。因为进程切换经常发生,因此减少保存和装入硬件上下文所话费的时间是非常重要的。

    早期Linux版本利用80x86体系结构所需提供的硬件支持,并通过far jmp1指令跳到next进程TSS描述符的选择符来执行进程切换。当执行这条指令时,CPU通过自动保存原来的硬件上下文,装入新的硬件上下文来执行硬件上下文切换。但Linux2.6使用软件执行进程切换,原因有:

    1. 通过一组mov指令逐步执行切换,这样能较好地控制所装入的数据的合法性,一面被恶意用户伪造。far jmp指令不会有这样的检查。
    2. 旧方法和新方法所需时间大致相同。

    进程切换值发生在内核态,在执行进程切换之前,用户态进程使用的所有寄存器内容已保存在内核堆栈上,这也包括ss和esp这对寄存器的内容。

    任务状态段

    80x86体系结构包含了一个特殊的段类型,叫任务状态段(Task State Segment,TSS)来存放硬件上下文,尽管Linux并不使用硬件上下文切换,但是强制它为系统中每个不同的CPU创建一个TSS,这样做主要有两个理由:

    1. 当80x86的一个CPU从用户态切换到内核态时,它就从TSS中后去内核态堆栈的地址。
    2. 当用户态进程试图通过in或out指令访问一个I/O端口时,CPU需要访问存放在TSS中的I/O许可位图以检查该进程是否有访问端口的权利。

    更确切的说,当进程在用户态执行in或out指令时,控制单元执行下列操作:

    1. 检查eflags寄存器中的2位IOPL字段,如果字段的值为3,控制单元就执行I/O指令。否则,执行下一个检查。
    2. 访问tr寄存器以确定当前的TSS和相应的I/O许可权位图。
    3. 检查I/O指令中指定的I/O端口在I/O许可权位图中对应的位,如果该位清,这条指令就执行,否则控制单元产生一个异常。

    tss_struct结构描述TSS的格式,init_tss数组为系统上每个不同的CPU存放一个TSS。在每次进程切换时,内核都更新TSS的某些字段以便相应的CPU控制单元可以安全地检索到它需要的信息。因此,TSS反映了CPU上当前进程的特权级,但不必为没有在运行的进程保留TSS。

    每个TSS有它自己8字节的任务状态段描述符(Task State Segment Descriptor,TSSD)。这个描述符包括指向TSS起始地址的32位Base字段,20位Limit字段。TSSD的S标志位被清0,以表示相应的TSS时系统段的事实。

    Type字段被置位11或9以表示这个段实际上是一个TSS。在Intel的原始设计中,系统中的每个进程都应当指向自己的TSS;Type字段的第二个有效位叫Busy位;如果进程正由CPU执行,则该位置1,否则为0。在Linux的设计中,每个CPU只有一个TSS,因此Busy位总是为1.

    由Linux创建的TSSD存放在全局描述符表(GDT)中,GDT的基地址存放在每个CPU的gdtr寄存器中。每个CPU的tr寄存器包含相应TSS的TSSD选择符,也包含了两个隐藏的非编程字段:TSSD的Base字段和Limit字段。这样,处理器就能够直接TSS寻址而不需要从GDT中检索TSS地址。

    thread字段

    在每次进程切换时,被替换的进程的硬件上下文必须保存在别处。不能像Intel原始设计那样保存在TSS中,因为Linux为每个处理器而不是为每个进程使用TSS。

    因此,每个进程描述符包含一个类型为thread_structthread字段,只要进程被切换出去,内核就把其硬件上下文保存在这个结构中。随后可以看到,这个数据结构包含的字段涉及大部分CPU寄存器,但不包括eax、ebx等等这些通用寄存器。它们的值保留在内核堆栈中。

    执行进程切换

    进程切换可能只发生在精心定义的点:schedule()函数,这个函数很长,会在以后更长的篇幅里讲解。。这里,只关注内核如何执行一个进程切换。

    进程切换由两步组成:

    1. 切换页全局目录以安装一个新的地址空间。
    2. 切换内核态堆栈和硬件上下文,因为硬件上下文提供了内核执行新进程所需要的所有信息,包含CPU寄存器。

    switch_to宏

    进程切换的第二步由switch_to宏执行。它是内核中与硬件关系最为密切的例程之一,必须下很多功夫了解。

    <include/asm-generic/system.h>

    /* context switching is now performed out-of-line in switch_to.S */
    extern struct task_struct *__switch_to(struct task_struct *,
            struct task_struct *);
    #define switch_to(prev, next, last)\
        do {\
            ((last) = __switch_to((prev), (next)));\
        } while (0)

    首先,该宏有三个参数,prevnextlastprevnext的作用仅是局部变量prevnext的占位符,即它们是输入参数,分别表示被替换进程和新进程描述符的地址在内存中的位置。

    在任何进程切换中,涉及到的是三个进程而不是两个。假设内核决定暂停进程A而激活进程B,在schedule()函数中,prev指向A的描述符,而next指向B的进程描述符。switch_to宏一旦使A暂停,A的执行流就被冻结。

    随后,当内核想再次激活A,就必须暂停另一个进程C,因为这通常不是B,因为B有可能被其他进程比如C切换。于是就要用prev指向C而next指向A来执行另一个switch_to宏。当A恢复它执行的流时,就会找到它原来的内核栈,于是prev局部变量还是指向A的描述符而next指向B的描述符。此时,代表进程A执行的内核就失去了对C的任何引用。但引用对于完成进程切换是有用的,所以需要保留。

    switch_to宏的最后一个参数是输出参数,它表示宏把进程C的描述符地址写在内存的什么位置了,不过,这个是在恢复A执行之后完成的。在进程切换之前,宏把第一个输入参数prev表示的变量存入CPU的eax寄存器。在完成进程切换,A已经恢复执行时,宏把CPU的eax寄存器的内容写入由第三个参数last所指示的A在内存中的位置。因为CPU寄存器不会在切换点发生变化,所以C的描述符地址也存在内存的这个位置。在schedule()执行过程中,last参数指向A的局部变量prev,所以prev被C的地址覆盖。

    __switch_to()函数

    __switch_to()函数执行大多数开始于switch_to()宏的进程切换。这个函数作用于prev_pnext_p参数,这两个参数表示前一个进程和新进程。这个函数的调用不同于一般的函数调用。因为__switch_to()从eax和edx取参数prev_pnext_p,而不像大多数函数一样从栈中取参数。

    <arch/x86/kernel/process_32.c>

    __switch_to(
        struct task_struct *prev_p,
        struct task_struct *next_p)
    {
        struct thread_struct *prev = &prev_p->thread,
                     *next = &next_p->thread;
        int cpu = smp_processor_id();
        struct tss_struct *tss = &per_cpu(init_tss, cpu);
        bool preload_fpu;
    
        preload_fpu = tsk_used_math(next_p) && next_p->fpu_counter > 5;
    
        __unlazy_fpu(prev_p);
    
        if (preload_fpu)
            prefetch(next->xstate);
    
        load_sp0(tss, next);
    
        lazy_save_gs(prev->gs);
    
        load_TLS(next, cpu);
    
        if (get_kernel_rpl() && unlikely(prev->iopl != next->iopl))
            set_iopl_mask(next->iopl);
    
        if (unlikely(task_thread_info(prev_p)->flags 
            & _TIF_WORK_CTXSW_PREV
            || task_thread_info(next_p)->flags
            & _TIF_WORK_CTXSW_NEXT))
            __switch_to_xtra(prev_p, next_p, tss);
    
        if (preload_fpu)
            clts();
    
        arch_end_context_switch(next_p);
    
        if (preload_fpu)
            __math_state_restore();
        if (prev->gs | next->gs)
            lazy_load_gs(next->gs);
    
        percpu_write(current_task, next_p);
    
        return prev_p;
    }

    这个函数执行步骤如下:

    执行由__unlay_fpu()宏代码产生的代码,以有选择地保存prev_p进程的FPU、MMX以及XMM寄存器的内容。

    执行smp_processor_id()宏获得本地CPU的下表,即执行代码的CPU。该宏从当前进程的thread_info结构的cpu字段获得下标并保存到cpu局部变量。

    next_p->thread.esp0装入对应于本地CPU的TSS的esp0字段。其实,任何由sysenter汇编指令产生的从用户态到内核态的特权级转换将把这个地址拷贝到esp寄存器中。

    next_p进程使用的线程局部存储(TLS)段装载入本地CPU的全局描述符表。

    fsgs段寄存器的内容分别存放在prev_p->thread.fsprev_p->thread.gs中。esi寄存器指向prev_p->thread结构。

    如果fsgs段寄存器已经被prev_pnext_p进程中的任意一个使用,则将next_p进程的thread_struct描述符中保存的值装入这些寄存器。

    next_p->thread.debugreg数组内容装载dr0…dr7中的6个调试寄存器。只有在next_p被挂起时正在使用调试寄存器,这种操作才能进行。

    如果必要,则更新TSS中的I/O位图。然后终止,prev_p参数被拷贝到eax,因为缺省情况下任何C函数的返回值被传给eax寄存器。所以eax的值在调用__switch_to()的过程中被保护起来;这很重要,因为调用该函数时会假定eax总是用来存放将被替换的进程描述符地址。

    汇编语言指令ret把栈定保存的返回地址装入eip程序计数器。不过,__swtich_to()函数时通过简单的跳转被调用的。因此,ret汇编指令在栈中找到标号为1的指令地址,其中标号为1的地址是由switch_to()宏推入堆栈的。

    1. far jmp指令既修改cs寄存器,也修改eip寄存器,而简单的jmp之类值修改eip寄存器。 
      文章原帖地址:http://guojing.me/linux-kernel-architecture/posts/process-switch/

    展开全文
  • Linux系统最新内核版本升级

    万次阅读 2020-07-08 15:53:57
    linux内核版本升级 说明:在k8s中由于内核版本太低会出现很多问题,需要在部署k8s集群之前升级系统内核版本。 1、载入公钥 rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org 2、安装ELRepo rpm -Uvh ...

    linux内核版本升级

    说明:在k8s中由于内核版本太低会出现很多问题,需要在部署k8s集群之前升级系统内核版本。

    1、载入公钥

    rpm --import https://www.elrepo.org/RPM-GPG-KEY-elrepo.org
    

    2、安装ELRepo

    rpm -Uvh http://www.elrepo.org/elrepo-release-7.0-3.el7.elrepo.noarch.rpm
    

    3、载入elrepo-kernel的元数据

    yum --disablerepo=\* --enablerepo=elrepo-kernel repolist
    

    4、查看可用的rpm包

    yum --disablerepo=\* --enablerepo=elrepo-kernel list kernel*
    

    5、下载安装最新版本的kernel

    yum --disablerepo=\* --enablerepo=elrepo-kernel install -y kernel-ml.x86_64
    

    6、下载驱动

    yum --enablerepo=elrepo-kernel install kernel-ml kernel-ml-devel.x86_64
    

    7、重启,选择新版本内核进入系统。

    在这里插入图片此时,操作系统使用的内核已升级为【 5.7.7-1.el7.elrepo.x86_64】描述
    此时,操作系统使用的内核已升级为【 5.7.7-1.el7.elrepo.x86_64】

    [root@localhost ~]# uname -a
    Linux localhost.localdomain 5.7.7-1.el7.elrepo.x86_64 #1 SMP Wed Jul 1 11:53:16 EDT 2020 x86_64 x86_64 x86_64 GNU/Linux
    

    8、将内核工具包一并升级

    删除旧版本工具包
    yum remove kernel-tools-libs.x86_64 kernel-tools.x86_64
    
    安装新版本工具包
    yum --disablerepo=\* --enablerepo=elrepo-kernel install -y kernel-ml-tools.x86_64
    
    展开全文
  • 安卓编译与开发、Linux内核及驱动

    千人学习 2015-08-17 17:42:48
    三、内核讲解:内核用途、内核结构、内核职能、内核源码编译、驱动开发;四、内核开发:1、体系架构、目录结构、中断机制、内核进程控制、2、内核库文件、例子简单分析、3、内核调度流程4、内核组件工具 嘉宾介绍:...
  • Linux内核从原理到代码详解 链接: http://pan.baidu.com/s/1sj0Szj3 密码: ywyv 网盘失效的话,请加QQ: 3113533060 课程内容: 第一周 1. 初识Linux内核 1.1 认识操作系统 1.2 开放源代码的UNIX...
    Linux内核从原理到代码详解


    链接: http://pan.baidu.com/s/1sj0Szj3 密码: ywyv


    网盘失效的话,请加QQ: 3113533060


    课程内容:
    第一周
    1. 初识Linux内核
    1.1 认识操作系统
    1.2 开放源代码的UNIX/Linux操作系统
    1.3 Linux内核
    1.4 Linux内核源代码
    1.5 Linux内核模块编程入门 
    1.6 Linux 内核中链表的实现及应用
    第二周
    2. 内存寻址
    2.1 内存寻址
    2.2 段机制
    2.3 分页机制
    2.4 Linux中的分页机制
    2.5 Linux中的汇编语言
    第三周
    3章 进程
    3.1 进程介绍
    3.2 Linux系统中的进程控制块
    3.3 Linux系统中进程的组织方式
    3.4 进程调度
    3.5 进程的创建
    3.6 与进程相关的系统调用及其应用
    3.7 系统调用及应用
    第四周
    4章 内存管理
    4.1 Linux的内存管理概述
    4.2 进程的用户空间管理
    4.3 请页机制
    4.4 物理内存分配与回收
    4.5 交换机制
    4.6 内存管理实例


    第五周
    5章 中断和异常
    5.1 中断是什么
    5.2 中断描述符表的初始化
    5.3 中断处理
    5.4 中断的下半部处理机制
    5.5 中断应用——时钟中断


    第六周
    6章系统调用
    6.1 系统调用与应用编程接口、系统命令以及内核函数的关系
    6.2 系统调用基本概念
    6.3 系统调用实现
    6.4 封装例程
    6.5 添加新系统调用


    第七周
    7章内核中的同步
    7.1 临界区和竞争状态
    7.2 内核同步措施
    7.3 生产者\消费者并发实例
    7.4 内核多任务并发实例
    第八周
    8章 文件系统
    8.2 虚拟文件系统
    8.3 文件系统的注册、安装与卸载
    8.4 文件的打开与读写
    8.5 编写一个文件系统


    第九周
    9 设备驱动
    9.1 概述
    9.2 设备驱动程序框架
    9.3 I/O空间的管理
    9.4 字符设备驱动程序

    展开全文
  • 深入分析Linux内核源码.chm

    千次下载 热门讨论 2008-10-07 14:30:14
    1.3走进Linux内核 1.4 分析Linux内核的意义 1.5 Linux内核结构 1.6 Linux内核源代码 1.7 Linux内核源代码分析工具 第二章 Linux运行的硬件基础 2.1 i386的寄存器 2.2 内存地址 2.3 段机制和描述符 2.4 分页机制 2.5 ...
  • 虽然内核对象位于独立于进程之外的内核区域,我们在开发中却只能通过调用Win32 API传入HANDLE参数来操作内核对象(如SetEvent等)。然而HANDLE句柄只对当前进程有效,离开了当前进程该句柄就无效了(具体原因参考:...

    虽然内核对象位于独立于进程之外的内核区域,我们在开发中却只能通过调用Win32 API传入HANDLE参数来操作内核对象(如SetEvent等)。然而HANDLE句柄只对当前进程有效,离开了当前进程该句柄就无效了(具体原因参考:Windows内核对象(1) – 内核对象与句柄)。所以说,跨进程访问内核对象的关键在于我们怎么跨进程访问句柄HANDLE

    下面介绍几种方法来实现跨进程共享内核对象。

    一、使用句柄继承的方式

    只有进程之间有父子关系时,才可以使用句柄继承的方式。在这种情况下,父进程可以生成一个子进程,并允许子进程访问父进程的内核对象。为了使这种继承生效,父进程必须执行几个步骤:
    (1). 父进程在创建一个内核对象时,父进程必须向系统指定它希望这个内核对象的句柄是可以继承的。为了创建一个可继承的内核对象,必须分配并初始化一个SECURITY_ATTRIBUTES结构,如:

    SECURITY_ATTRIBUTES sa;
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.bInheritHandle = TRUE;  // 可继承的
    sa.lpSecurityDescriptor = NULL;
    
    HANDLE h = CreateEvent(&sa, TRUE, FALSE, NULL); 

    (2). 父进程通过CreateProcess生成子进程,且指定bInheritHandles为TRUE,从而允许子进程来继承父进程的那些“可继承的句柄”。

    // 启动子进程TestB.exe,将句柄h作为启动参数传给进程TestB
    //
    TCHAR cmd_buf[MAX_PATH];
    StringCchPrintf(cmd_buf, MAX_PATH, TEXT("TestB.exe %ld"), (long)h);
    
    STARTUPINFO si = { sizeof(si) };
    PROCESS_INFORMATION pi;
    BOOL ret = CreateProcess(
        NULL, 
        cmd_buf, 
        NULL, 
        NULL, 
        TRUE,  // 指定子进程可以继承父进程的“可继承句柄”
        0, 
        NULL, 
        NULL, 
        &si, 
        &pi
    );
    
    
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

    由于我们传给bInheritHandles参数的值是TRUE,所以系统在创建子进程时会多做一件事情:它会遍历父进程的句柄表,对它的每一项进行检查,凡是包含一个有效的“可继承的句柄”的项,都会将该项完整的复制到子进程的句柄表。在子进程的句柄表中,复制项的位置与它在父进程句柄表中的位置完全一样(包含索引),这个就意味着:在父进程和子进程中,对一个内核对象进行标识的句柄值也是完全一样的。所以我们只需要通过某种方式(如上面示例中的启动参数的方式,或者环境变量的方式等任何进程间通讯的方式)将这个值告诉子进程,子进程就可以将该值转成HANDLE,然后使用这个HANDLE来调用系统API。

    二、使用DuplicateHandle方式

    明白DuplicateHandle的工作原理,需要先了解进程句柄表,可以参考Windows内核对象(1) – 内核对象与句柄

    2.1 DuplicateHandle功能

    DuplicateHandle函数可以将指定“源进程的句柄表”中的某一项复制到“目的进程句柄表”中(除了索引),并且返回该项在目的进程句柄表中的索引(即HADNLE)。
    可以在任何时候调用DuplicateHandle函数,DuplicateHandle对源句柄是否是可继承的没有要求。

    函数声明如下:

    BOOL DuplicateHandle(
      HANDLE hSourceProcessHandle,
      HANDLE hSourceHandle,
      HANDLE hTargetProcessHandle,
      LPHANDLE lpTargetHandle,
      DWORD dwDesiredAccess,
      BOOL bInheritHandle,
      DWORD dwOptions
    );

    DuplicateHandle详细介绍可以参考MSDN:https://msdn.microsoft.com/en-us/library/windows/desktop/ms724251(v=vs.85).aspx

    2.2 支持的句柄类型

    DuplicateHandle函数不能复制所有类型的句柄,只能复制如下类型的句柄(从MSDN复制而来):

    Object Description
    Access token The handle is returned by the CreateRestrictedToken, DuplicateToken, DuplicateTokenEx, OpenProcessToken, or OpenThreadToken function.
    Change notification The handle is returned by the FindFirstChangeNotification function.
    Communications device The handle is returned by the CreateFile function.
    Console input The handle is returned by the CreateFile function when CONIN$ is specified, or by the GetStdHandle function when STD_INPUT_HANDLE is specified. Console handles can be duplicated for use only in the same process.
    Console screen buffer The handle is returned by the CreateFile function when CONOUT$ is specified, or by the GetStdHandle function when STD_OUTPUT_HANDLE is specified. Console handles can be duplicated for use only in the same process.
    Desktop The handle is returned by the GetThreadDesktop function.
    Event The handle is returned by the CreateEvent or OpenEvent function.
    File The handle is returned by the CreateFile function.
    File mapping The handle is returned by the CreateFileMapping function.
    Job The handle is returned by the CreateJobObject function.
    Mailslot The handle is returned by the CreateMailslot function.
    Mutex The handle is returned by the CreateMutex or OpenMutex function.
    Pipe A named pipe handle is returned by the CreateNamedPipe or CreateFile function. An anonymous pipe handle is returned by the CreatePipe function.
    Process The handle is returned by the CreateProcess, GetCurrentProcess, or OpenProcess function.
    Registry key The handle is returned by the RegCreateKey, RegCreateKeyEx, RegOpenKey, or RegOpenKeyEx function. Note that registry key handles returned by the RegConnectRegistry function cannot be used in a call to DuplicateHandle.
    Semaphore The handle is returned by the CreateSemaphore or OpenSemaphore function.
    Thread The handle is returned by the CreateProcess, CreateThread, CreateRemoteThread, or GetCurrentThread function
    Timer The handle is returned by the CreateWaitableTimer or OpenWaitableTimer function.
    Transaction The handle is returned by the CreateTransaction function.
    Window station The handle is returned by the GetProcessWindowStation function.

    不同的事件类型对应的dwDesiredAccess参数不同,具体参考MSDN

    2.3 使用示例

    进程TestA源码

    int main(int argc, char** argv) {
        HANDLE h = CreateEvent(NULL, TRUE, FALSE, NULL);
    
        // 启动子进程TestB.exe
        //
        TCHAR cmd_buf[MAX_PATH];
        StringCchPrintf(cmd_buf, MAX_PATH, TEXT("D:\\TestB.exe"), (long)h);
    
        STARTUPINFO si = { sizeof(si) };
        PROCESS_INFORMATION pi;
        BOOL ret = CreateProcess(NULL, cmd_buf, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
        assert(ret);
        assert(pi.hProcess);
    
        HANDLE duplicated_h = NULL;
        ret = DuplicateHandle(GetCurrentProcess(), h, pi.hProcess, &duplicated_h, 0, FALSE, DUPLICATE_SAME_ACCESS);
    
    
        WaitForSingleObject(pi.hProcess, INFINITE);
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
    
        bool has_signal = WaitForSingleObject(h, 0) == WAIT_OBJECT_0;
        assert(has_signal == true);
    
        return 0;
    }

    子进程TestB源码

    int main(int argc, char** argv)
    {
        long l = 0;
        printf("Input Handle:");
        scanf("%ld", &l);
    
        HANDLE h = (HANDLE)l;
    
        bool has_signal = WaitForSingleObject(h, 0) == WAIT_OBJECT_0;
        assert(has_signal == false);
    
        SetEvent(h);
    
        return 0;
    }
    

    在父进程TestA中创建一个不可继承的事件 -> 然后启动子进程TestB -> 调用DuplicateHandle复制句柄项到TestB进程句柄表 -> 并向TestB输入句柄值 -> TestB访问该事件句柄,将事件置为有信号状态。

    三、使用命名的内核对象的方式

    3.1 实现原理

    这种方式严格的说已经不是文章开头说到的跨进程访问句柄了,有点类似跨进程直接访问内核对象了。
    该方式实现起来比较简单,就是在调用创建内核对象的Create***函数时,通过pszName参数为内核对象取一个名字。
    如创建事件Event的函数CreateEvent

    HANDLE WINAPI CreateEvent(
      LPSECURITY_ATTRIBUTES lpEventAttributes,
      BOOL bManualReset,
      BOOL bInitialState,
      LPCTSTR lpName  // 指定名称
    );
    
    HANDLE h = CreateEvent(NULL, TRUE, FALSE, TEXT("TestA_Obj"));

    若在其他进程中要访问这个内核对象,只需要使用打开函数Open***打开该内核对象,系统就会在进程的句柄表中插入一条记录,并返回这条记录的索引,也就是句柄。需要注意的是,在打开内核对象时需要留意返回值GetLastError函数的返回值。由于内核对象是有访问权限的,有时候虽然这个名字的内核对象存在,但该进程却不见得有权限可以打开它,这个时候GetLastError函数会返回失败的原因。

    以打开事件的函数OpenEvent为例:

    HANDLE h = OpenEvent(READ_CONTROL, FALSE, TEXT("TestA_Obj"));
    if (h == NULL) {
        if (GetLastError() == ERROR_ACCESS_DENIED) { // 没有READ_CONTROL权限
    
        }
    }

    3.2 全局命令空间

    不同的会话(Session)有不同的内核对象命名空间(如windows服务程序位于Session 0,而普通的用户进程位于Session 1),要通过名称访问其他会话中的内核对象,需要在名称前面加上Session\<当前会话ID>。Windows提供了一个全局的内核对象命名空间,处于任何会话中的进程都可以访问该命名空间,将内核对象放入全局命令空间的方式很简单:只需要在内核对象名称前加入Global\即可。

    如:

    HANDLE h = CreateEvent(NULL, TRUE, FALSE, TEXT("Global\\TestA_Obj"));
    展开全文
  • Windows内核对象(1) -- 内核对象与句柄

    万次阅读 2018-01-25 16:42:52
    一、什么是内核对象 我们在windows开发中经常会遇到内核对象,如事件(Event),管道(Pipe),互斥量(Mutex),完成端口(IOCP),进程(Process),线程(Thread)等,他们都是内核对象。这些内核对象虽然通过不同的系统API...
  • 《Linux内核修炼之道》 之 高效学习Linux内核

    万次阅读 热门讨论 2010-07-15 23:10:00
    这本《Linux内核修炼之道》在卓越、当当、china-pub上也已经开卖了,虽然是严肃文学,但为了保证流畅性,大部分文字我还都是斟词灼句,反复的念几遍才写上去的,尽量考虑到写上去的每段话能够让读者产生什么疑惑,...
  • Linux内核设计与实现_第三版_中文版

    千次下载 热门讨论 2013-08-28 15:35:22
    《Linux内核设计与实现》第三版,中文版。基于Linux 2.6.34内核,本书详细介绍了Linux内核系统,覆盖了从核心内核系统的应用到内核设计与实现等各方面内容。
  • 内核,微内核,混合内核OS结构比较

    千次阅读 2013-03-28 09:15:24
  • 1.4.1 大内核和微内核

    千次阅读 2016-06-20 00:05:30
    有关这个 问题的回答,形成了两种主要的体系结构:大内核与微内核。 大内核系统将操作系统的主要内容模块都作为一个紧密联系的整体运行在核心态,从而为应用提供高性能的系统服务。因为各管理模块之间共享信息,能...
  • Linux内核

    千次阅读 2009-01-07 17:30:00
    Linux内核一、Linux内核Linux内核的源码树已经有超过20000个文件,超过600万行代码。这还是几年前的数据。需要工具、根文件系统、Linux应用程序共同建立一个可用的系统。1、内核版本当前的Linux内核版本为2.6.28。...
  • [14本经典Android开发教程] 8 Linux内核阅读心得体会 读核感悟 2 读核感悟 Linux内核启动 内核的生成 2 读核感悟 Linux内核启动 从hello world说起 3 读核感悟 Linux内核启动 BIOS 5 读核感悟 Linux内核启动 setup...
  • ubuntu16.04 查看内核,升级内核,删除内核,切换内核 1:查看内核列表 sudo dpkg --get-selections |grep linux-image linux-image-4.4.0-21-generic install linux-image-4.4.0-66-generic deinstall ...
  • 1. Linux里的每个进程都有4G的地址空间,其中0至3G是用户空间,3G至4G是内核内核被共享在每个进程的地址空间中。 2. 每个进程的地址空间内大约有4个段,即内核代码段、内核数据段、用户代码段、用户数据段。 3. 我...
  • 操作系统内核可能是微内核,也可能是单内核(后者有时称之为宏内核Macrokernel)。按照类似封装的形式,这些术语定义如下: 单内核:也称为宏内核。将内核从整体上作为一个大过程实现,并同时运行在一个...
  • 内核与第二代微内核

    千次阅读 2009-07-10 09:31:00
    第一代微内核 微内核的概念是由Richard Rashid在卡内基梅隆(Carnegie-Mellon)大学开发Mach操作系统时提出的,目标是建立一个基于消息传送(message passing)机制的最小内核,以便在此基础上建造对其它操作系统的模拟...
  • 内核与微内核、Linux内核与Unix内核的区别

    万次阅读 多人点赞 2016-05-25 10:06:42
    操作系统内核可能是微内核,也可能是单内核(后者有时称之为宏内核Macrokernel)。按照类似封装的形式,这些术语定义如下: 单内核:也称为宏内核。将内核从整体上作为一个大过程实现,并同时运行在一个单独的地址...
  • 编译Android内核

    千次阅读 2015-08-20 14:10:11
    首先需要知道自己android内核的版本,我们android系统是android 4.0.1,内核版本为2.6.29.由于我们在下载android源代码的时候默认是不带内核源码的,因为他内置了一个编译好的zImage内核镜像,所以,如果要编译内核...
  • 内核和宏内核

    千次阅读 2013-11-23 00:36:42
    关于操作系统自然的做法:凡是为进程服务的模块就应放在操作系统的内核中。例如:文件管理模块是为进程服务的,所以应放在内核中;设各驱动模块是为进程服务的,所以要放在内核中;进程管理模块当然也要放在内核中。...
  • 内核OS与微内核OS结构比较

    千次阅读 2013-03-28 09:06:42
  • CentOS7 更新最新内核 内核下载地址:https://elrepo.org/linux/kernel/el7/x86_64/RPMS/ 内核选择 kernel-lt(lt=long-term)长期有效 kernel-ml(ml=mainline)主流版本 安装过程 1.下载内核 wget ...
  • 谈谈Tomcat内核

    千次阅读 2017-08-21 18:26:10
    ========广告时间========鄙人的新书《Tomcat内核设计剖析》已经在京东销售了,有需要的朋友可以到 https://item.jd.com/12185360.html 进行预定...为什么写《Tomcat内核设计剖析》=========================欢迎关注:
  • 更新Ubuntu内核到最新版本

    万次阅读 2018-04-16 15:35:33
    想起自己多年前玩Linux的时候知道了两个命令: sudo apt-get update sudo apt-get upgrade ...2.拖动到底下看看Ubuntu的最新内核版本(最底下的最新)。 3.在自己的Ubuntu终端中输入uname -r查看...

空空如也

1 2 3 4 5 ... 20
收藏数 341,448
精华内容 136,579
关键字:

内核