CN115098244A - 内核栈的分配方法、电子设备、芯片及存储介质 - Google Patents
内核栈的分配方法、电子设备、芯片及存储介质 Download PDFInfo
- Publication number
- CN115098244A CN115098244A CN202210600560.5A CN202210600560A CN115098244A CN 115098244 A CN115098244 A CN 115098244A CN 202210600560 A CN202210600560 A CN 202210600560A CN 115098244 A CN115098244 A CN 115098244A
- Authority
- CN
- China
- Prior art keywords
- stack
- kernel
- page
- thread
- pages
- Prior art date
- Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
- Granted
Links
- 238000000034 method Methods 0.000 title claims abstract description 120
- 238000009826 distribution Methods 0.000 title claims abstract description 18
- 238000003860 storage Methods 0.000 title claims abstract description 12
- 238000012545 processing Methods 0.000 claims abstract description 63
- 230000006870 function Effects 0.000 claims abstract description 57
- 230000002159 abnormal effect Effects 0.000 claims abstract description 47
- 230000008569 process Effects 0.000 claims description 51
- 238000004590 computer program Methods 0.000 claims description 17
- 230000005856 abnormality Effects 0.000 claims description 15
- 238000013507 mapping Methods 0.000 claims description 6
- 239000013598 vector Substances 0.000 abstract description 25
- 238000001514 detection method Methods 0.000 abstract description 10
- 239000002699 waste material Substances 0.000 description 11
- 230000007246 mechanism Effects 0.000 description 10
- 238000010586 diagram Methods 0.000 description 8
- 238000013461 design Methods 0.000 description 5
- 238000013519 translation Methods 0.000 description 5
- 230000008878 coupling Effects 0.000 description 3
- 238000010168 coupling process Methods 0.000 description 3
- 238000005859 coupling reaction Methods 0.000 description 3
- 238000005516 engineering process Methods 0.000 description 3
- 238000012360 testing method Methods 0.000 description 3
- 230000009286 beneficial effect Effects 0.000 description 2
- 238000004891 communication Methods 0.000 description 2
- 230000006872 improvement Effects 0.000 description 2
- 238000005111 flow chemistry technique Methods 0.000 description 1
- 230000003993 interaction Effects 0.000 description 1
- 230000002452 interceptive effect Effects 0.000 description 1
- 238000005259 measurement Methods 0.000 description 1
- 230000003287 optical effect Effects 0.000 description 1
- 238000005457 optimization Methods 0.000 description 1
- 230000002093 peripheral effect Effects 0.000 description 1
- 238000003825 pressing Methods 0.000 description 1
- 230000004044 response Effects 0.000 description 1
- 238000006467 substitution reaction Methods 0.000 description 1
- 230000001360 synchronised effect Effects 0.000 description 1
- 230000001960 triggered effect Effects 0.000 description 1
Images
Classifications
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F9/00—Arrangements for program control, e.g. control units
- G06F9/06—Arrangements for program control, e.g. control units using stored programs, i.e. using an internal store of processing equipment to receive or retain programs
- G06F9/46—Multiprogramming arrangements
- G06F9/50—Allocation of resources, e.g. of the central processing unit [CPU]
- G06F9/5005—Allocation of resources, e.g. of the central processing unit [CPU] to service a request
- G06F9/5011—Allocation of resources, e.g. of the central processing unit [CPU] to service a request the resources being hardware resources other than CPUs, Servers and Terminals
- G06F9/5016—Allocation of resources, e.g. of the central processing unit [CPU] to service a request the resources being hardware resources other than CPUs, Servers and Terminals the resource being the memory
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F2209/00—Indexing scheme relating to G06F9/00
- G06F2209/50—Indexing scheme relating to G06F9/50
- G06F2209/5018—Thread allocation
Landscapes
- Engineering & Computer Science (AREA)
- Software Systems (AREA)
- Theoretical Computer Science (AREA)
- Physics & Mathematics (AREA)
- General Engineering & Computer Science (AREA)
- General Physics & Mathematics (AREA)
- Memory System Of A Hierarchy Structure (AREA)
Abstract
本申请提供了一种内核栈的分配方法、电子设备、芯片及存储介质,涉及计算机技术领域。通过该方案,在修改fork创建线程时,使用vmalloc接口申请内核栈,并将vmap区域进行4倍栈大小对齐处理,并初始分配一个页面或部分栈顶页面。通过内核栈内存空间的对齐处理,支持内核栈溢出检测。在不影响异常向量正常处理流程和内核栈溢出检测功能的情况下,实现内核栈按需动态分配,节省内存。
Description
技术领域
本申请涉及计算机技术领域,尤其涉及一种内核栈的分配方法、电子设备、芯片及存储介质。
背景技术
在Linux环境下,Linux内核会为每个运行的线程分配线程运行所需的栈,称为内核栈,Linux的内核栈不仅负责为函数调用过程中的局部变量提供存储空间,还负责在任务调度、异常处理提供保存上下文所需的内存空间。内核栈在每个线程被创建的时候分配好,并挂接到与线程相关的数据结构中。内核栈的大小受芯片体系以及操作系统的位宽等因素影响。在ARM64架构上,内核栈的大小默认是16KB。即内核在创建每个线程的时候,都会为其分配16KB的栈。
然而,在系统实际运行时,绝大部分线程对栈的使用都很少,远达不到16KB的水平,内核栈出现了极大的浪费。
发明内容
本申请提供一种内核栈的分配方法、电子设备、芯片及存储介质,可以在不影响异常向量正常处理流程和内核栈溢出检测功能的情况下,实现内核栈按需动态分配,节省内存。
为达到上述目的,本申请采用如下技术方案:
第一方面,本申请提供一种内核栈的分配方法,该方法包括:创建第一线程;为第一线程申请内核栈,该内核栈包括初始分配页和可分配页,该初始分配页和可分配页的总和为S个页面(S=2N,N为大于或等于2的整数);对内核栈的内存空间进行2k×S个页面对齐处理(其中k为大于或等于2的整数);当第一线程在内核空间发生异常事件,且内核栈溢出时,从可分配页中为第一线程分配页面。
通过该方案,在创建线程后为线程申请内核栈,将内核栈的内存空间进行2k×S个页面对齐处理(即2k倍栈大小对齐处理),并初始分配一个页面或部分栈顶页面,未初始分配的页面可在需要进行动态分配。通过内核栈内存空间的对齐处理,支持内核栈溢出检测。这样在不影响异常向量正常处理流程和内核栈溢出检测功能的情况下,实现内核栈按需动态分配,节省内存。
在一些可能实现方式中,S取4,k取2。在此情况下,可以对内核栈的内存空间进行16个页面的对齐处理。其中,每个页大小可以为4KB。通过本方案,可以对内核栈内存空间的4倍栈大小对齐处理,在不影响正常流程的情况下,实现内核栈内存按需分配,减少内存浪费。
示例性地,以栈大小为4个页面为例的可能分配方式包括:方式一,初始分配1个页,其他3个页在需要时再分配。方式二,初始分配2个页,其他2个页在需要时再分配。方式三,初始分配3个页,其他1个页在需要时再分配。方式四,初始分配4个页,兼容相关技术的全部分配策略。也就是说,在S取4的情况下,内核栈的初始分配页为1个,可分配页为3个;或者,内核栈的初始分配页为2个,可分配页为2个;或者,内核栈的初始分配页为3个,可分配页为1个。
在一些可能实现方式中,方法还包括:当第一线程在内核空间发生异常事件,且内核栈未溢出时,将第一线程的上下文数据压入内核栈中;并通过初始分配页处理该异常事件。可以理解,在内核栈未溢出的情况下,在内核栈中压栈,保存上下文寄存器信息,并进行常规处理,然后返回到异常前现场继续执行即可。
在一些可能实现方式中,上述从可分配页中为第一线程分配页面,包括:根据所述异常事件的异常类型,确定所述异常事件对应的页面分发策略;并在异常事件为内核栈访问异常的情况下,根据该异常事件对应的页面分发策略,从可分配页中为第一线程分配页面。
在一些可能实现方式中,上述从可分配页中为第一线程分配页面,包括:从可分配页中获取一个页面;将该一个页面与第一线程建立映射关系。然后,可以利用分配的该一个页面完成对异常事件的处理。
可选地,先向第一线程初始分配一个页面(以每个页大小为4KB为例),供第一线程使用,占用内存空间4KB。当初始分配一个页面不满足第一线程的需求(即内核栈访问异常、内核栈溢出)时,可以从可分配页中为第一线程分配一个页面,此时供第一线程可使用的页面为2个,占用内存空间8KB。由此可以实现内核栈内存按需分配,减少内存浪费。
可选地,在两个页面不满足第一线程的需求(即内核栈访问异常、内核栈溢出)时,可以继续从可分配页中为第一线程分配一个页面,此时供第一线程可使用的页面为3个,占用内存空间12KB。由此可以实现内核栈内存按需分配,减少内存浪费。
可选地,如果三个页面不满足第一线程的需求(即内核栈访问异常、内核栈溢出),那么可以继续从可分配页中为第一线程分配再一个页面,此时供第一线程可使用的页面为4个,占用内存空间16KB。由此可以实现内核栈内存按需分配,减少内存浪费。
在一些可能实现方式中,本申请实施例提供的方法应用于电子设备,该电子设备包括内核栈,并且还包括第一栈(也称为异常栈,或者异常栈寄存器)。在上述从可分配页中为第一线程分配页面之前,该方法还包括:将栈指针从内核栈切换到第一栈;将第一线程的上下文数据压入第一栈中。
通过本申请方案,当出现异常且内核栈溢出时,可以将栈指针从内核栈切换到第一栈,将上下文数据压入第一栈中,然后处理异常事件,避免了由于内核栈溢出而导致无法压栈及无法处理异常的情况发生。
在一些可能实现方式中,上述将第一线程的上下文数据压入第一栈中,包括:在第一栈未溢出的情况下,将第一线程的上下文数据压入第一栈中。
在一些可能实现方式中,上述方法还包括:在第一栈溢出的情况下,将栈指针从第一栈切换到第二栈(也称为溢出栈或者溢出栈寄存器),并将第一线程的上下文数据压入第二栈中,然后调用panic函数进行复位处理(系统重启)。
也就是说,当第一线程在内核空间发生异常事件,且内核栈溢出时,可以先判断第一栈是否溢出,然后执行对应的处理策略。具体地,在第一栈未溢出的情况下将第一线程的上下文数据压入第一栈中并进行异常处理;在第一栈溢出的情况下将第一线程的上下文数据压入第二栈中并进行复位处理。
在一些可能实现方式中,在从可分配页中为第一线程分配页面之后,该方法还包括:根据第一线程的上下文数据,从第一栈出栈并返回到内核栈。需要说明的是,在异常处理中使用第一栈先保存异常现场。当异常发生时,异常现场会被压到内核栈,当异常处理结束,需要返回到内核栈并恢复现场,将这些保存的异常现场值恢复到通用寄存器中。
在一些可能实现方式中,经过对齐处理后,所述内核栈的内存空间包括所述内核栈的初始分配页、可分配页以及对齐保留页;其中,所述对齐保留页、可分配页以及初始分配页按照从栈基向栈顶的方向排列。通过本方案,通过对内核栈内存空间进行对齐处理,在不影响正常流程和内核栈溢出检测功能的情况下,实现内核栈内存按需分配,减少内存浪费。
在一些可能实现方式中,异常事件可能为同步异常,也可能为中断。
在一些可能实现方式中,上述创建第一线程,包括:通过fork函数创建第一线程。
在一些可能实现方式中,上述为第一线程申请内核栈,包括:通过vmap机制,调用vmalloc接口函数为第一线程申请内核栈。
在本申请实施例中,可以动态使能/关闭内核栈按需分配,提高系统健壮性。
第二方面,本申请提供一种内核栈的分配装置,该装置包括用于执行上述第一方面中的方法的单元。该装置可对应于执行上述第一方面中描述的方法,该装置中的单元的相关描述请参照上述第一方面的描述,为了简洁,在此不再赘述。
其中,上述第一方面描述的方法可以通过硬件实现,也可以通过硬件执行相应的软件实现。硬件或软件包括一个或多个与上述功能相对应的模块或单元。例如,处理模块或单元、分配模块或单元等。
第三方面,本申请提供一种电子设备,所述电子设备包括处理器,处理器与存储器耦合,存储器用于存储计算机程序或指令,处理器用于执行存储器存储的计算机程序或指令,使得第一方面中的方法被执行。例如,处理器用于执行存储器存储的计算机程序或指令,使得该装置执行第一方面中的方法。
第四方面,本申请提供一种计算机可读存储介质,其上存储有用于实现第一方面中的方法的计算机程序(也可称为指令或代码)。例如,该计算机程序被计算机执行时,使得该计算机可以执行第一方面中的方法。
第五方面,本申请提供一种芯片,包括处理器。处理器用于读取并执行存储器中存储的计算机程序,以执行第一方面及其任意可能的实现方式中的方法。可选地,所述芯片还包括存储器,存储器与处理器通过电路或电线连接。
第六方面,本申请提供一种芯片系统,包括处理器。处理器用于读取并执行存储器中存储的计算机程序,以执行第一方面及其任意可能的实现方式中的方法。可选地,所述芯片系统还包括存储器,存储器与处理器通过电路或电线连接。
第七方面,本申请提供一种计算机程序产品,所述计算机程序产品包括计算机程序(也可称为指令或代码),所述计算机程序被计算机执行时使得所述计算机实现第一方面中的方法。
可以理解的是,上述第二方面至第七方面的有益效果可以参见上述第一方面中的相关描述,在此不再赘述。
附图说明
图1为本申请实施例提供的虚拟地址空间和物理地址空间之间的对应关系图;
图2为相关技术中提供的内核栈的结构示意图;
图3为本申请实施例提供的一种内核栈的分配方法的流程示意图;
图4为本申请实施例提供的内核栈的分配方法中利用fork函数创建线程的流程示意图;
图5为本申请实施例提供的内核栈的结构示意图;
图6为相关技术中提供的判断栈是否溢出以及对应的处理策略的流程示意图;
图7为本申请实施例提供的内核栈的分配方法中判断栈是否溢出以及对应的处理策略的流程示意图;
图8为本申请实施例提供的在发生缺页异常时按需动态分配内核栈的流程示意图;
图9为本申请实施例提供的检测线程栈页池是否需要填充的流程示意图。
具体实施方式
为使本申请实施例的目的、技术方案和优点更加清楚,下面将结合本申请实施例中的附图,对本申请实施例中的技术方案进行清楚、完整地描述,显然,所描述的实施例是本申请一部分实施例,而不是全部的实施例。基于本申请中的实施例,本领域普通技术人员在没有做出创造性劳动前提下所获得的所有其他实施例,都属于本申请保护的范围。
本文中术语“和/或”,是一种描述关联对象的关联关系,表示可以存在三种关系,例如,A和/或B,可以表示:单独存在A,同时存在A和B,单独存在B这三种情况。本文中符号“/”表示关联对象是或者的关系,例如A/B表示A或者B。
本文中的说明书和权利要求书中的术语“第一”和“第二”等是用于区别不同的对象,而不是用于描述对象的特定顺序。在本申请实施例中,“示例性的”或者“例如”等词用于表示作例子、例证或说明。本申请实施例中被描述为“示例性的”或者“例如”的任何实施例或设计方案不应被解释为比其它实施例或设计方案更优选或更具优势。确切而言,使用“示例性的”或者“例如”等词旨在以具体方式呈现相关概念。
在本申请实施例中,电子设备包括硬件层、运行在硬件层之上的操作系统层,以及运行在操作系统层上的应用层。层与层之间相互协作,处理各项任务,实现电子设备的基本功能。
其中,硬件层可以包括中央处理器(central processing unit,CPU)、内存管理单元(memory management unit,MMU)和内存(也称为主存)等硬件。
其中,操作系统层的操作系统(operating system,OS)可以是任意一种或多种通过进程(process)实现业务处理的计算机操作系统,例如,Linux操作系统、Unix操作系统、Android操作系统、iOS操作系统或Windows操作系统等。其中,一个可执行程序在执行时被称为一个进程。
其中,应用层可以包含浏览器、通讯录、文字处理软件、即时通信软件等应用程序以及交互界面。
为便于理解本申请实施例,以下对本申请实施例的部分用语进行解释说明,以便于本领域技术人员理解。
(1)内核(kernel):在操作系统设计中,为减少系统本身的开销,往往将一些与硬件紧密相关的(如中断处理程序、设备驱动程序等)、基本的、公共的、运行频率较高的模块(如时钟管理、进程调度等)以及关键性数据结构独立开来,使之常驻内存,并对之进行保护。通常将这一部分称之为操作系统的内核。内核负责管理操作系统的进程、内存、设备驱动程序、文件和网络系统,决定着操作系统的性能和稳定性。可以理解,内核是操作系统最基本的部分,提供操作系统的最基本的功能。
具体地,内核是为众多应用程序提供的对计算机硬件安全访问的一部分软件。内核可以决定一个应用程序在什么时候对某部分硬件操作多长时间。
(2)内核栈(kernel stack):内核在创建进程时,在创建任务结构(task_struct)的同时会为进程创建相应的堆栈(stack)。堆栈用于保存临时数据,局部变量和中断/调用子程序程序的返回地址。例如,线程在初始化时,系统会为其分配线程堆栈,用于存储局部变量、函数调用时的参数等,还用于存储当前线程的上下文。
堆栈是按照“先进后出”(即先进入堆栈的数据后移出堆栈)的原则存取数据。处理器架构通常设置有栈指针(stack pointer,SP)寄存器以及特定的硬件指令来完成入栈/出栈的操作。例如,对于ARM64,栈指针SP是一个64位寄存器,指向当前栈地址,压栈操作时栈地址从高向低变化,SP初值一般指向栈顶。
随着线程函数的执行,线程函数中会逐渐添加局部变量的定义或调用其他函数;此时,这些直接在线程函数中定义的局部变量和被调用函数的参数(实参)就从栈顶开始压入线程栈。在压栈的过程中,系统会按需逐步深入地(向栈底方向移动)为线程栈中的页面调拨物理存储器。
(3)线程(thread):是操作系统能够进行运算调度或者程序执行的最小单位。线程被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,各条线程并行执行不同的任务。
目前操作系统可以同时运行多个线程。示例性地,如下表1所示,安卓(Android)系统在启动时的线程数量超过4000个,内核栈的内存总量超过60MB,即内核栈占用60MB;并且,在系统长时间使用之后,由于数据缓存导致后台APP的线程数量甚至接近10000个,内核栈的内存总量甚至接近150M,即内核栈占用150MB。
表1
线程数量(个) | 内核栈内存总量(KB) | 内存总量(MB) |
<u>4366</u> | 69856 | <u>68.22</u> |
6292 | 100672 | 98.31 |
7879 | 126064 | 123.11 |
8288 | 132608 | 129.50 |
9251 | 148016 | 144.55 |
9557 | 152912 | 149.33 |
9866 | 157856 | 154.16 |
9569 | 153104 | 149.52 |
9919 | 158704 | 154.98 |
8926 | 142816 | 139.47 |
<u>9001</u> | 144016 | <u>140.64</u> |
(4)页(page):是Linux内核管理物理内存的最小单位。内核将整个物理内存按照页对齐方式划分成千上万个页(称为物理页,page frame)进行管理。为了管理这些物理页,内核将每个物理页抽象成struct page(称为虚拟内存页)结构。
举例来说,当前Linux内核可配置使用VMAP_STACK机制(也称为vmap机制)分配内核栈,该VMAP_STACK机制采用vmalloc()接口函数向内核申请栈内存,内核栈大小以页(page)为单位,这些内存页在物理上可能是不连续的,但这些物理不连续的内存页可以映射到虚拟地址连续的空间内。
如图1所示,内核采用物理地址空间和虚拟地址空间映射的方式进行管理,物理地址空间包括多个物理页(page frame),例如每个物理页大小可以为4K。虚拟地址空间包括多个虚拟内存页(struct page)。一个物理页page frame对应一个虚拟内存页structpage。
下面说明目前Linux内核栈内存初始分配以及内核栈对齐的可能方式。
Linux内核通常采用栈内存固定分配的方式,例如Linux内核在初始分配固定大小(例如4KB或者8KB或者16KB)的内核栈内存空间。示例性地,针对32位系统分配的内核栈内存通常为8KB;针对64位系统分配的内核栈内存通常为16KB。
在配置VMAP_STACK机制时有如下要求:栈页数S对齐N(N=2k,k为正整数),即栈大小为N;栈基地址(stack_base)对齐2*N。举例来说,假设k取2,N为4,栈页数S对齐4,即内核栈大小为4个页面,并且对内核栈的页面起始位置(栈基地址)进行2倍栈大小对齐,即内核栈的页面起始位置对齐8(S*2=8)。
举例来说,以分配16KB为例进行说明,图2示出了Linux内核现有内核栈内存分配的示意图。如图2所示,VMAP_STACK机制通过vmalloc申请16KB内核栈内存空间,相应地会分配物理内存;其中,内核栈大小(记为S)为4个页面,每个页面大小(记为P)为4KB,初始分配16KB。
其中sp的有效范围用十六进制可以表示为[0x8000,0xC000),对应地,用二进制可以表示[1000 0000 0000 0000,1100 0000 0000 0000)。需要说明的是,为了图示清楚简洁,图2示意性地简化示出了初始分配的四个页面,分别采用p1000,p1001,p1010,p1011表示,其中加p前缀表示页索引的二进制,这四个页面分别对应十进制8,9,10,11。如图2所示,栈基所在页对应8,栈顶所在页对应11,每个页面大小4KB。由此可知,内核栈的页面起始位置(栈基)已经对齐8,采用1000表示。可以理解的是,对于初始分配的四个页面,栈基所在页第12bit至15bit可以表示为p1000或者p1000,其中最低位为0bit。需要说明的是,这里为了便于说明,这里以p1000为例进行示例性说明,在页索引二进制表示时省略了其他bit的数值。
然而这种固定分配方式存在下述优点和缺点。
一方面,Linux内核在初始分配较大内核栈内存空间(例如16K),可以一定程度上避免出现堆栈溢出的现象,然而这种分配方式会出现内存浪费的问题。示例性地,下面的表2示出了在为线程内核栈固定分配16KB物理内存的情况下线程内核栈的使用情况。
表2
如表2可知,在为线程内核栈分配16KB物理内存的情况下,线程内核栈大部分情况下的使用量都低于4KB,如表中下划线标识的已使用字节所示,只有极少数情况下使用量会高于4KB,大部分情况下剩余较多字节未被使用,例如剩余12KB甚至更多字节未被使用,因此线程内核栈的物理内存未被充分利用,浪费比较多。也就是说,由于大部分线程使用内核栈的内存空间远远低于16KB,因此现有方案存在内存浪费的问题。
另一方面,在Linux内核初始分配内核栈内存空间较小(例如4KB或者8KB)的情况下,尽管可以节省内核栈内存空间,但是会存在下述问题:当内核函数调用层级比较多,或者有比较大的局部变量导致内核栈使用量超过内核栈内存空间时,Linux内核会根据异常向量判断出内核栈溢出,并调用panic函数进行复位处理,而复位处理会触发电子设备重新启动。
鉴于此,本申请实施例提供了一种内核栈的分配方法,通过该方法,在修改fork创建线程时,使用vmalloc接口申请内核栈,并将vmap区域进行4倍栈大小对齐,并初始分配一个页面或部分栈顶页面,在不影响异常向量正常处理流程和内核栈溢出检测功能的情况下,实现内核栈按需动态分配,节省内存。
本申请实施例并未对本申请实施例提供的方法的执行主体的具体结构进行特别限定,只要能够通过运行记录有本申请实施例提供的方法的代码的程序,以根据本申请实施例提供的方法进行内核栈按需动态分配即可。例如,本申请实施例提供的内核栈的分配方法的执行主体可以为上述的电子设备,也可以为该电子设备中能够实现该内核栈的分配方法的功能模块和/或功能实体(例如Linux内核),并且本申请方案能够通过硬件和/或软件的方式实现,具体的可以根据实际使用需求确定,本申请实施例不作限定。下面以Linux内核为例,结合附图对本申请实施例提供的内核栈的分配方法进行示例性的说明。
图3是本申请实施例提供的内核栈的分配方法的流程示意图。参照图3所示,该方法包括下述的步骤S101-S103。
S101,通过fork函数创建线程。
其中,fork函数用于创建进程或线程。在一个线程(父线程)中,可以用fork()函数创建一个子线程。当该子线程创建时,该子线程从fork()指令的下一条(或者说从fork()函数的返回处)开始执行与父线程相同的代码。
首先说明在用户空间(用户态)和内核空间(内核态)之间切换的场景或者时机:
场景一,用户进程如果想要主动的执行一些特权操作,如读/写某个设备文件时,便会通过各种系统调用陷入内核空间,完成对应操作后会再次返回用户空间。
场景二,当用户进程运行在用户空间时,如果此时发生某个外设中断,会马上陷入内核空间,执行相应的中断处理程序,执行完后会再次返回用户空间;该机制可保证系统对外部事件(如键盘、鼠标)的快速响应,提升系统交互性能。
上述的两种场景其实都属于异常。不同之处在于:系统调用属于同步异常,除此之外还有数据中止、指令中止和调试异常等;中断属于异步异常,除此之外还有系统错误等。这些异常都会导致用户空间与内核空间的切换。
以上场景都是用户进程陷入内核空间然后返回用户空间的模式,所有的用户进程都是父进程或者其子进程fork出来的,Linux系统初始化时创建的都是内核线程。
下面结合图4示出的流程图示例性地说明利用fork()函数创建线程的过程。如图4所示,Linux内核在创建一个新线程时,可以先通过fork()函数触发sys_fork系统调用,然后sys_fork系统调用会执行do_fork(),具体会在do_fork()中执行copy_process()来复制父线程的资源给子线程。copy_process()是复制线程的描述符,在copy_process()中包含有dup_task_struct()、copy_file()和copy_thread()等各种函数,用于复制初始化工作,例如可以调用dup_task_struct()为子线程获取线程描述符。在完成复制初始化工作之后,会执行ret_from_fork(),从而完成fork创建子线程的过程。
可以理解,ret_from_fork可以作为子线程的起点。当执行ret_from_fork时,会返回一个指向子线程的指针,并开始执行该子线程。对于用户任务可以通过ret_to_user从内核空间返回至用户空间。对于fork系统调用,父线程可以按照系统调用返回路径从内核态返回用户态(即用户空间),子线程可以通过ret_from_fork跳转到ret_to_user返回到用户态。
S102,调用vmalloc接口函数为该线程申请内核栈,并根据预设的内核栈初始分配页数对栈内存页面进行初始化,并对内核栈内存空间进行4倍栈大小对齐处理。
其中,预设的内核栈初始分配页数为1或2或3。需要说明的是,按需动态分配内核栈依赖vmap机制,内核栈初始化需要分配至少一个页面。线程创建后首先在内核态运行,使用内核栈,系统调用和异常处理也使用内核栈处理,内核栈初始化时至少要分配一个页面以满足基本运行,其他页面在需要时再分配。
示例性地,下面给出了以栈大小为4个页面为例的可能分配方式:
方式一,初始分配1个页,其他3个页在需要时再分配。
方式二,初始分配2个页,其他2个页在需要时再分配。
方式三,初始分配3个页,其他1个页在需要时再分配。
方式四,初始分配4个页,兼容相关技术的全部分配策略。
再示例性地,下面给出了以栈大小为8个页面为例的可能分配方式:
方式一,初始分配1个页,其他7个页在需要时再分配。
方式二,初始分配2个页,其他6个页在需要时再分配。
方式三,初始分配3个页,其他5个页在需要时再分配。
方式四,初始分配4个页,其他4个页在需要时再分配。
方式五,初始分配5个页,其他3个页在需要时再分配。
方式六,初始分配6个页,其他2个页在需要时再分配。
方式七,初始分配7个页,其他1个页在需要时再分配。
方式八,初始分配8个页,兼容相关技术的全部分配策略。
需要说明的是,本申请实施例通过修改vmalloc接口函数,使得支持初始化时只分配部分物理页,其他物理页按需动态分配。
其中,通过调用vmalloc接口函数,可以申请可用的虚拟内存(具体为虚拟地址)和物理内存(具体为物理页),并在虚拟地址与物理页之间建立映射关系。通过vmalloc接口函数可以申请虚拟内存中连续但在物理内存中不一定连续的内存。如上所述,vmap机制可以将不连续的物理页映射到连续的虚拟地址空间中,通过vmap机制调用vmalloc接口函数,可以为线程申请内核栈。
为了便于说明,将栈内存页面初始化后得到的栈区域可称为vmap区域(vmap_area)。在一些实施例中,对内核栈内存空间进行4倍栈大小对齐处理,具体可以是对vmap区域进行4倍栈大小对齐处理。通过栈对齐处理,能够用尽可能少的指令实现异常向量处理。
需要说明的是,这里是以4倍栈大小对齐处理为例进行示例性说明,可以理解,在实际实现时,可以根据实际使用需求对内核栈内存空间进行2k倍栈大小对齐处理,其中k为大于1的整数。例如,当k取2时,即可以对内核栈内存空间进行4倍栈大小对齐处理;当k取3时,即可以对内核栈内存空间进行8倍栈大小对齐处理;具体2k的取值可以根据实际使用需求确定,本申请实施例对此不作限定。
在本申请实施例中,预设的内核栈初始分配页数可以根据实际使用需求确定。例如,以内核栈大小S=4个页面,每个页面大小为4KB为例,在创建子线程的内核栈时,预设的内核栈初始分配页数可以为1,或者为2,或者为3,相应地可以配置可动态分配页,在需要时按需动态分配,实现内核栈内存按需分配,节省内存。可以理解的是,当预设的内核栈初始分配页数为4时,初始分配全部页面,无可动态分配页。为了便于说明,本申请下述实施例中以栈大小为4个页面为例进行示例性说明。
示例性地,以初始分配1个页面为例,图5中的(a)示出了初始化分配1个页面的内核栈内存分布示意图。p11000为初始分配的1个页面,并且在内核栈配置有可按需动态分配的3个页面p10101、p10110和p10111。其中,栈顶所在页为p11000,栈基所在页为p10101。
可以理解的是,初始分配了1个页面,仅占用内核栈内存4KB,后续可以根据需求进行页面动态分配,例如从可按需动态分配页中动态分配1个或者2个或者3个可用页面。在实际使用时,占用内核栈内存可能仅需4KB,也可能仅需8KB,还可能仅需12KB,或者需要16KB。也就是说,本申请方案通过初始化分配1个页面,通过按需动态分配页面,实现内核栈内存按需分配,从而节省内存。
如图5中的(a)所示,本申请在初始分配1个页面的情况下对内核栈内存空间进行了4倍栈大小对齐处理,使得vmap区域的地址范围为[0x10000,0x1800F],对应的页包括p10000至p11000。其中,p11000为初始分配页,p10101、p10110、p10111为按需动态分配页,p10000至p10100为对齐保留部分。对齐保留部分为不可访问区域,由MMU进行设置。另外p01111和p11001均为不可访问区域,同样由MMU进行设置。
需要说明的是,在本申请实施例中,p10101、p10110、p10111、p11000等前缀加p的字符均为页索引的二进制表示。
再示例性地,以初始分配2个为例,图5中的(b)示出了初始化分配2个页面的内核栈内存分布示意图。p11001和p11000为初始化分配的2个页面,并且在内核栈配置有可按需动态分配的两个页面p10110和p10111。其中,栈顶所在页为p11001,栈基所在页为p10110。
可以理解的是,初始分配了2个页面,仅占用内核栈内存8KB,后续可以根据需求进行页面动态分配,例如从可按需动态分配页中动态分配1个或者2个可用页面。在实际使用时,占用内核栈内存可能仅需8KB,也可能仅需12KB,或者需要16KB。也就是说,本申请方案通过初始化分配2个页面,通过按需动态分配页面,实现内核栈内存按需分配,从而节省内存。
如图5中的(b)所示,本申请在初始分配2个页面的情况下对内核栈内存空间进行了4倍栈大小对齐处理,使得vmap区域对应的页包括p10000至p11001。其中,p11000和p11001为初始分配页,p10110和p10111为按需动态分配页,p10000至p10101为对齐保留部分。对齐保留部分为不可访问区域,由MMU进行设置。另外p01111和p11010均为不可访问区域,同样由MMU进行设置。
又示例性地,以初始分配3个为例,图5中的(c)示出了初始化分配3个页面的内核栈内存分布示意图。p11000、p11001、p11010为初始化分配的3个页面,并且在内核栈配置有可按需动态分配的1个页面p10111。其中,栈顶所在页为p11010,栈基所在页为p10111。
可以理解的是,初始分配了3个页面,仅占用内核栈内存12KB,后续可以根据需求进行页面动态分配,例如从可按需动态分配页中动态分配1个可用页面。在实际使用时,占用内核栈内存可能仅需12KB,或者需要16KB。也就是说,本申请方案通过初始化分配3个页面,通过按需动态分配页面,实现内核栈内存按需分配,从而节省内存。
如图5中的(c)所示,本申请在初始分配3个页面的情况下对内核栈内存空间进行了4倍栈大小对齐处理,使得vmap区域对应的页包括p10000至p11010,其中,p11000、p11001和p11010为初始分配页,p10111为按需动态分配页,p10000至p10110为对齐保留部分。对齐保留部分为不可访问区域,由MMU进行设置。另外p01111和p11011均为不可访问区域,同样由MMU进行设置。
示例性地,以初始分配4个为例,图5中的(d)示出了初始化分配4个页面的内核栈内存分布示意图。p11000至p11011为初始化分配的4个页面(即全部页面),在此情况下没有可动态分配的页面。其中,栈顶所在页为p11011,栈基所在页为p11000。其中p10111和p11100均为不可访问区域,由MMU进行设置。
由此可知,本申请实施例可以初始分配1个页面,也可以初始分配2个页面,还可以初始分配3个页面,然后根据实际使用场景,内核栈内存可以按需动态分配,节省内存资源。需要说明的是,为了便于说明,以下实施例中以初始分配1个页面为例进行示例性说明。
可以理解的是,本申请上述实施例将内核栈内存空间进行4倍栈大小对齐处理(S*4=16),vmap区域的页起始位置被配置为p10000,初始分配页起始位置均被配置为p11000,可以确保初始分配页起始位置2倍栈大小对齐(S*2=8)。这样,便于在异常向量入口内核栈全部分配时可以采用相同的一条指令来判断是否需要切换栈进行异常处理。
需要说明的是,如果初始分配4个页面,即分配全部页面,在此情况下只需要对内核栈内存空间进行2倍栈大小(S*2=8)对齐处理即可。在此情况下,初始分配页起始位置同样配置为p11000,可以保证初始分配页起始位置2倍栈大小(4×2=8)对齐,兼容相关技术中初始分配4个页面的处理方案。
在一些实施例中,可以在原有代码基础上新增代码,用于对内核栈动态按需分配的使能(即启用)或关闭进行配置。通过运行该新增代码部分,即可动态配置使能或关闭内核栈动态按需分配的功能。本申请实施例可以动态使能/关闭内核栈按需动态分配,可以动态配置初始化页数。并且,在使能内核栈按需动态分配功能时,Linux系统异常向量正常流程处理兼容相关技术正常流程。
需要说明的是,每个用户进程都拥有自己的用户栈和内核栈,需要进行栈的切换,完成中断任务;并且在内核空间发生异常且栈溢出时,通常会切换到溢出栈,完成复位处理。每个用户进程都有进程地址空间,进程地址空间包括用户地址空间和内核地址空间,所有进程(包括内核线程)共享内核地址空间。地址空间就是一套用于翻译虚拟地址到物理地址的页表,全局页目录基地址存放在特定寄存器中(el0与el1对应不同的寄存器),因此需要切换硬件MMU翻译时读取的页表基址寄存器。用户进程在进入内核空间,然后返回用户空间时需要恢复之前的状态继续执行,因此需要存储和恢复硬件上下文信息,比如处理器状态,pc指针等。
S103,在内核空间发生异常且栈溢出时,分配一个页面。
在本申请实施例中,内核栈初始化分配至少一个页面,例如可以初始分配1个或2个或3个页面,每个页大小为4KB。线程创建后首先在内核态运行并使用内核栈;系统调用和异常处理也使用内核栈处理。这样,内核栈初始化时至少分配一个页面以满足基本运行,其他页面在需要时再分配。
在内核空间发生异常时,根据异常类型和异常地址判断是否栈溢出时,在栈溢出时从内核栈切换到异常栈,分配一个页,然后返回异常前场景。
举例来说,下面以初始分配1个页,其他3个页在需要时再分配为例进行示例性说明。
结合图5中的(a)所示,内核栈初始分配1个页(p11000)。在内核空间发生异常时,若判断栈溢出,则从内核栈切换到异常栈,分配1个页(p10111),然后返回异常前场景。此时异常栈剩余2个页(p10110和p10101)可以继续按需分配。
进一步地,如果内核空间再次发生异常,若栈溢出则从内核栈切换到异常栈,再次分配1个页(p10110),然后返回异常前场景。此时异常栈还剩余1个页(p10101)可以继续按需分配。
进一步地,如果内核空间又一次发生异常,若栈溢出则从内核栈切换到异常栈,再次分配1个页(p10101),然后返回异常前场景。
由此可见,在本申请方案中,通过内核栈初始化时分配一个页面以满足基本运行,其他页面在需要时再分配,可以实现内核栈被充分利用,节省内存。
再示例性地,下面以初始分配2个页,其他2个页在需要时再分配为例进行示例性说明。结合图5中的(b)所示,内核栈初始分配2个页(p10001和p11000)。在内核空间发生异常时,若判断栈溢出,则从内核栈切换到异常栈,分配1个页(p10111),然后返回异常前场景。此时异常栈剩余1个页(p10110)可以继续按需分配。进一步地,如果内核空间再次发生异常,若栈溢出则从内核栈切换到异常栈,再次分配1个页(p10110),然后返回异常前场景。由此可见,在本申请方案中,通过内核栈初始化时分配2个页面以满足基本运行,其他页面在需要时再分配,可以实现内核栈被充分利用,节省内存。
又示例性地,下面以初始分配3个页,其他1个页在需要时再分配为例进行示例性说明。结合图5中的(c)所示,内核栈初始分配3个页(p10010、p10001和p11000)。在内核空间发生异常时,若判断栈溢出,则从内核栈切换到异常栈,分配1个页(p10111),然后返回异常前场景。由此可见,在本申请方案中,通过内核栈初始化时分配3个页面以满足基本运行,其他页面在需要时再分配,可以实现内核栈被充分利用,节省内存。
通过本申请实施例提供的方案,在修改fork创建线程时,使用vmalloc接口申请内核栈,并将vmap区域进行4倍栈大小对齐,并初始分配一个页面或部分栈顶页面,在不影响异常向量正常处理流程和内核栈溢出检测功能的情况下,实现内核栈按需动态分配。
上述图3中步骤S103中的具体实现方式可以通过下述的图7、图8和图9中的步骤来实现。
本申请技术方案是在相关技术方案的基础上所做的改进。为了更清楚地区分本申请技术方案相对于相关技术方案的改进以及有益效果,下面在本申请异常向量处理策略之前,先介绍相关技术的异常向量处理策略。
相关技术方案
在相关技术方案中,以栈大小为16KB,栈大小位数占14位(bit)为例进行说明,其中,16KB=16384B=214,1千字节(KB)为1024字节(B)。可以根据异常向量中第14bit数值来判断栈是否溢出。在sp有效范围内,sp第14bit为0,栈未溢出。若sp第14bit为1,则超出有效范围,即表示栈溢出。
图6示出了相关技术方案中在异常向量处理过程中的处理策略。如图6所示,该相关技术方案的处理策略包括S201-S209。
S201,检测到异常(el1_sync)。
可以理解,在内核空间发生同步异常或中断时,会跳转到el1_sync(对应于同步异常)或el1_irq(对应于中断)。由此基于el1_sync或el1_irq可确定发生异常。下面以el1_sync处理流程为例进行示例性说明。
S202,调用字段sub sp,sp,#S_FRAME_SIZE。
S203,判断内核栈是否溢出。
例如,根据sp第14bit判断内核栈是否溢出。通常,如果存在内核栈溢出,就会发生DA异常。下面示例性地给出了ARM64的一段异常向量处理的代码(也称为异常向量表或异常向量入口):
sub sp,sp,#S_FRAME_SIZE//sp=sp-S_FRAME_SIZE
#ifdef CONFIG_VMAP_STACK
/*
*测试sp栈寄存器是否溢出.
*任务内核栈和中断栈对齐(1<<THREAD_SHIFT).
*/
add sp,sp,x0 //sp’=sp+x0
sub x0,sp,x0 //x0’=sp’-x0=(sp+x0)-x0=sp
tbnz x0,#THREAD_SHIFT,0f//判断栈合法性
sub x0,sp,x0 //x0’=sp’-x0’=(sp+x0)-sp=x0
sub x0,sp,x0 //sp”=sp’-x0=(sp+x0)-x0=sp
b el\()\el\()_\label//跳转到对应级别的异常处理函数kernel_entry 1
当异常发生时,会自动跳转到异常向量表中,然后通过异常向量表中的跳转命令跳转到相应的异常处理。
根据上述代码可知,完成任务内核栈和中断栈的对齐处理,并且可以根据异常向量入口处的跳转命令“tbnz x0,#THREAD_SHIFT,0f”来判断栈(sp=sp–S_FRAME_SIZE)是否溢出,并根据判断结果来执行相应的异常处理。若溢出则切换到溢出栈(overflow_stack)进行复位处理,若未溢出则保存上下文寄存器后继续处理。
一方面,若第14bit为0,表示sp未溢出,则继续执行下述的S204-S207,即在内核栈中执行异常处理(称为常规流程)。
S204,调用kernel_entry 1函数入栈,在内核栈中记录任务上下文信息。
在此情况下会调用regsize和el1_stk等相关参数,其中参数regsize缺省64,el1_stk缺省0,即regsize=64,el1_stk=0。
S205,调用el1_sync_handler函数进行分发处理。
S206,调用kernel_exit 1出栈。
S207,返回内核态继续执行。
可以理解,在栈未溢出情况下,保存上下文寄存器信息,并进行常规处理,然后返回到异常前现场继续执行。
另一方面,若第14bit为1,表示sp溢出,则继续执行下述的S208-S209,进行复位处理。
S208,调用overflow_stack函数,切换到溢出栈。
S209,调用panic函数进行复位处理。
在相关技术方案中,初始分配固定的栈大小(例如16KB,4个页面)的内核栈,由于大部分线程对栈的使用都很少,远达不到16KB的水平,存在内存浪费的问题;当发生了内核栈溢出时,将栈切换到溢出栈overflow_stack,进行复位处理(系统重启)。
本申请技术方案
在本申请技术方案中,内核栈初始化分配例如1个页面,其他3个页面在需要时动态分配,每个页大小为4KB。线程创建后首先在内核态运行并使用内核栈;系统调用和异常处理也使用内核栈处理。可以理解,内核栈初始化时分配一个页面以满足基本运行,在发生异常且栈溢出时根据需要进行再分配其他页面,下面说明本申请在发生异常以及判断栈溢出后的处理策略。
图7示出了本申请技术方案中在异常向量处理过程中的处理策略。如图7所示,本申请技术方案的处理策略包括S301-S314。
S301,检测到异常(el1_sync)。
在用户态运行时,发生异常或中断时CPU自动切换到内核栈,此时内核栈在栈顶,空间足够使用。异常处理(如el0_sync/el0_irq)在内核态运行,若发生内核栈访问异常,则触发el1_sync。
可以理解,在内核空间发生同步异常时,会跳转到el1_sync;在内核空间发生中断时,会跳转到el1_irq。由此基于el1_sync可确定发生同步异常,基于el1_irq可确定发生中断异常。下面以el1_sync处理流程为例进行示例性说明,el1_irq处理流程类似于el1_sync处理流程,此处不予赘述。
需要说明的是,在异常处理中使用栈先保存异常现场。当异常发生时,异常的现场会被压到内核栈,当异常处理结束,需要恢复现场,将这些保存的值恢复到通用寄存器中。
还需要说明的是,用户态运行时发生异常或中断,内核栈在栈顶,不存在内核栈越界场景,不需要处理。这里以2^14=16K栈大小进行举例说明,当线程或异常在内核态运行时,可能发生内核栈数据访问异常(data abort,DA),此时通过判断sp的第14bit即可判断sp是否在栈顶页,即可以判断栈是否溢出。
S302,调用字段sub sp,sp,#S_FRAME_SIZE。
关于字段sub sp,sp,#S_FRAME_SIZE的相关异常向量处理代码可参见在上述对步骤b中的举例说明,此处不再赘述。
S303,根据sp第14bit的取值判断栈是否溢出。
例如,根据sp第14bit是否为1,判断内核栈是否溢出。
若S303中判断出第14bit为0,表示sp在栈顶页,内核栈未溢出,则继续执行下述的S304-S307,此时无需切换到异常栈,按照常规处理方式来处理异常。
S304,调用kernel_entry 1函数压栈,在内核栈中记录任务上下文信息。
S305,调用el1_sync_handler函数,在内核栈中执行异常处理,即分发处理。
S306,调用kernel_exit 1函数出栈。
S307,返回内核态继续执行。
可以理解,在第14bit为0的情况下,sp指针在栈顶页,按照常规流程处理,即保存上下文寄存器,并在内核栈中执行异常处理(恢复运行)。
需要说明的是,在本申请技术方案中,通过内核栈空间对齐处理,上述异常向量处理的正常流程(S301至S307)与上述相关技术方案中的常规流程(S201至S207)保持一致。与相关技术方案相比,本申请技术方案的不同之处在于下述的S308至S312以及S307。
若S303中判断出第14bit为1,表示sp不在栈顶页,内核栈溢出,则继续执行下述的S308-S312。即切换到异常栈,采用本申请实施例提供的新流程进行异常处理。
线程或异常在内核态运行时使用内核栈可能发生DA异常,需要保存上下文寄存器并恢复运行。具体地,访问未分配物理页的线程内核栈会触发异常,此时内核栈sp不能访问,不能保存上下文寄存器,需要一个新的可用栈,由于溢出栈overflow_stack只有4KB,不满足线程内核态正常运行,且溢出栈overflow_stack不满足线程内核栈对齐要求,因此本申请增加了异常栈el1_stack,提供按需动态分配页的相应功能。
示例性地,内核栈初始分配了1个页面时,其他3个页面会存在异常栈,这3个页面可在需要时按需分配。内核栈初始分配了2个页面时,其他2个页面会存在异常栈,这2个页面可在需要时按需分配。内核栈初始分配了3个页面时,其他1个页面会存在异常栈,这1个页面可在需要时按需分配。
S308,调用switch_el1_stack函数,将sp切换到per_cpu的异常栈。
当切换到异常栈时,通过异常栈的动态分配页来保存任务上下文寄存器并进行异常处理。
需要说明的是,线程在内核态运行时,发生中断后进入异常向量,此时内核栈sp也可能刚好不能访问,需要切换。切换栈之前至少需要使用一个特殊寄存器保存通用寄存器。在切换栈的过程中不能破坏上下文寄存器(要保存正确的寄存器)。切换栈需要两个通用寄存器(或一个通用寄存器和sp),两个通用寄存器在完成栈切换后要恢复到发生异常时的值并保存在栈中。下面给出了两种可能的实现方式:
方式一,两个通用寄存器可以保存在其他特殊寄存器,如tpidr_el0、tpidrro_el0、sp_el0这些特殊寄存器在内存中都有备份,在切换栈后保存上下文寄存器现场后可以从内存恢复。
方式二,两个通用寄存器可以保存在内存中,而获取内存地址又需要至少一个通用寄存器,这个通用寄存器也需要一个特殊寄存器才能保存并恢复。
S309,根据sp第13bit和第12bit判断栈是否溢出。
示例性地,根据sp第13bit判断sp是否溢出,若未溢出则支持分配一个页面。若sp第13bit判断sp溢出,则可以进一步根据sp第12bit判断sp是否溢出,若未溢出则支持分配一个页面。
当S309中判断出sp未溢出时,继续执行下述的S308至S312以及S307。
S310,寄存器压栈(kernel_entry 1,64,el1_stk)。
S311,调用el1_sync_handler函数,在异常栈中执行异常处理,即分发处理。
S312,寄存器出栈(kernel_exit 1,el1_stk)。
然后执行S307,即返回异常前现场。
可以理解,在第13bit为1的情况下,sp指针不在栈顶页,那么将sp的值保存在可从线程(thread)数据中恢复的特殊寄存器(tpidrro_el0),并借助线程上下文(thread.context)做临时内存,保存通用寄存器的值,将sp切换到per_cpu的异常栈,恢复通用寄存器,再将通用寄存器以及tpidrro_el0保存的sp值保存在异常栈中继续异常处理。
当S309中判断出sp溢出(此时4个页面全部分配完)时,继续执行下述的S313-S314。
S313,调用overflow_stack,切换到溢出栈。
S314,调用panic函数进行复位处理。
与上述相关技术方案中在栈溢出时直接复位处理相比较,本申请方案能够实现按需动态分配内存,在发生内核栈溢出时,能够在异常向量入口使用当前栈的动态分配页保存任务上下文寄存器,然后继续进行异常处理,直到异常栈的可用页全部分配完,sp溢出时才会调用panic复位。
需要说明的是,针对上述的S311,在el1_sync_hander中,可以根据异常类型进行分发,其中可以在地址转换异常(do_translation_fault)中增加下述判断逻辑:判断当前异常是否为访问内核栈导致的异常(即缺页异常),如果判断是访问内核栈导致的异常,那么从预先分配好的页池中获取一个页并建立虚拟地址到物理页的映射。具体流程可以参见图8,如图8所示,该流程可以包括S3111至S3116。
S3111,检测到地址转换异常(do_translation_fault)。
S3112,判断是否为访问内核栈导致的缺页异常。
在一些实施例中,可以通过调用object_is_on_stack检测指针sp是否在栈上。如果指针sp在栈上,那么重新分配内存;如果指针sp不在栈上,那么可以重用该内存。
若当前异常为访问内核栈导致的缺页异常,则继续执行步骤S3113至S3115。若当前异常不是访问内核栈导致的缺页异常,则继续执行S3116。
S3113,调用vmap_stack_alloc_page_atomic,内核栈按需动态分配。
S3114,调用vmap_stack_get_page,在内核栈获取可用页。
S3115,调用vmalloc_map_page_atomic,进行页面映射。
S3116,调用do_bad_area,重用栈内存。
在一些实施例中,在页池耗尽的情况下,在访问内核栈异常时无法获取可用页,无法继续处理,因此要确保页池内有空闲页。在上述的S3114之前,可以执行下述步骤:在任务切换时检查是否页池耗尽,并在页池耗尽的情况下填充线程栈页池,以保证有可用页。具体流程可以参见图9,如图9所示,该流程可以包括S401至S406。
S401,调用_schedule函数进行任务切换。
S402,调用stack_need_fill检测线程栈页池是否需要填充?
若判断线程栈页池不需要填充,则继续执行下述的S403至S405。若判断线程栈页池需要填充,则继续执行下述的S406。
S403,调用pick_next_task,选取下一个将要执行的进程。
S404,调用context_switch,进程上下文切换。
S405,调用balance_callback回调函数。
S406,调用vmap_stack_fill_page_pool_work,填充线程栈页池。
在S406之后,确保页池内有空闲页,因此可以继续执行上述S3114,即在内核栈获取可用页。通过本申请实施例提供的方案,在修改fork创建线程时,使用vmalloc接口申请内核栈,并将vmap区域进行4倍栈大小对齐,并初始分配一个页面或部分栈顶页面,在不影响异常向量正常处理流程和内核栈溢出检测功能的情况下,实现内核栈按需动态分配。
本申请实施例提供的运行Linux系统的Android设备均可使用。
相比于相关技术中内核栈占用150MB(16KB)的场景,通过本申请内核栈的分配方法,如果初始分配4KB内核栈内存空间,节省12KB内存空间,12KB/16KB=75%,如果不再需要分配新的页面,那么理论上最多可节省75%的内核栈内存,即可以节省约112.5MB内存空间。
在本申请实施例中,理论上可优化75%,实测优化约60%,在Android手机启动时可以节省40MB内存,在Android手机运行时可以节省80MB内存。具体可以参见表3。
表3
表4是内核栈按需动态分配时手机启动时和测试过程中内核栈分别分配1个页,2个页,3个页,4个页的线程数量。
表4
场景 | 线程数量 | 1个页 | 2个页 | 3个页 | 4个页 |
启动时 | 4294 | 3207 | 666 | 1 | 420 |
测试中 | 8207 | 4481 | 3353 | 2 | 371 |
在本申请实施例中,通过对内核栈内存空间的4倍栈大小对齐处理,在不影响正常流程和内核栈溢出检测功能的情况下,实现内核栈内存按需分配,减少内存浪费。
在本申请实施例中,可以动态使能/关闭内核栈按需分配,提高系统健壮性。
也需要说明的是,在本申请实施例中,“大于”可以替换为“大于或等于”,“小于或等于”可以替换为“小于”,或者,“大于或等于”可以替换为“大于”,“小于”可以替换为“小于或等于”。
上文主要从方法步骤的角度对本申请实施例提供的方案进行了描述。可以理解的是,为了实现上述功能,实施该方法的电子设备包含了执行各个功能相应的硬件结构和/或软件模块。本领域技术人员应该可以意识到,结合本文中所公开的实施例描述的各示例的单元及算法步骤,本申请能够以硬件或硬件和计算机软件的结合形式来实现。某个功能究竟以硬件还是计算机软件驱动硬件的方式来执行,取决于技术方案的特定应用和设计约束条件。专业技术人员可以对每个特定的应用来使用不同方法来实现所描述的功能,但是这种实现不应认为超出本申请的保护范围。
可选地,在一些实施例中,本申请提供一种芯片,该芯片与存储器耦合,该芯片用于读取并执行存储器中存储的计算机程序或指令,以执行上述各实施例中的方法。
可选地,在一些实施例中,本申请提供一种电子设备,该电子设备包括芯片,该芯片用于读取并执行存储器存储的计算机程序或指令,使得各实施例中的方法被执行。
本申请实施例中的电子设备可以为移动终端,也可以为非移动终端。示例性的,移动终端可以为手机、平板电脑、笔记本电脑、掌上电脑、车载终端、可穿戴设备、超级移动个人计算机(ultra-mobile personal computer,UMPC)、上网本或者个人数字助理(personaldigital assistant,PDA)等,非移动终端可以为个人计算机(personal computer,PC)、电视机(television,TV)、柜员机或者自助机等,本申请实施例不作具体限定。
可选地,在一些实施例中,本申请实施例还提供了一种计算机可读存储介质,该计算机可读存储介质存储有程序代码,当计算机程序代码在计算机上运行时,使得计算机执行上述各实施例中的方法。
可选地,在一些实施例中,本申请实施例还提供了一种计算机程序产品,该计算机程序产品包括计算机程序代码,当计算机程序代码在计算机上运行时,使得计算机执行上述各实施例中的方法。
本领域普通技术人员可以意识到,结合本文中所公开的实施例描述的各示例的单元及步骤,能够以电子硬件、或者计算机软件和电子硬件的结合来实现。这些功能究竟以硬件还是软件方式来执行,取决于技术方案的特定应用和设计约束条件。专业技术人员可以对每个特定的应用来使用不同方法来实现所描述的功能,但是这种实现不应认为超出本申请的保护范围。
所属领域的技术人员可以清楚地了解到,为描述的方便和简洁,上述描述的系统、装置和单元的具体工作过程,可以参考前述方法实施例中的对应过程,在此不再赘述。
在本申请所提供的几个实施例中,应该理解到,所揭露的系统、装置和方法,可以通过其它的方式实现。例如,以上所描述的装置实施例仅仅是示意性的,例如,所述单元的划分,仅仅为一种逻辑功能划分,实际实现时可以有另外的划分方式,例如多个单元或组件可以结合或者可以集成到另一个系统,或一些特征可以忽略,或不执行。此外,所显示或讨论的相互之间的耦合或直接耦合或通信连接可以是通过一些接口,装置或单元的间接耦合或通信连接,可以是电性,机械或其它的形式。
所述功能如果以软件功能单元的形式实现并作为独立的产品销售或使用时,可以存储在一个计算机可读取存储介质中。基于这样的理解,本申请的技术方案本质上,或者说对现有技术做出贡献的部分,或者该技术方案的部分,可以以计算机软件产品的形式体现出来,该计算机软件产品存储在一个存储介质中,该计算机软件产品包括若干指令,该指令用以使得一台计算机设备(可以是个人计算机,服务器,或者网络设备等)执行本申请各个实施例所述方法的全部或部分步骤。前述的存储介质可以包括但不限于:U盘、移动硬盘、ROM、RAM、磁碟或者光盘等各种可以存储程序代码的介质。
除非另有定义,本文所使用的所有的技术和科学术语与属于本申请的技术领域的技术人员通常理解的含义相同。本文中在本申请的说明书中所使用的术语只是为了描述具体的实施例的目的,不是旨在于限制本申请。
以上所述,仅为本申请的具体实施方式,但本申请的保护范围并不局限于此,任何熟悉本技术领域的技术人员在本申请揭露的技术范围内,可轻易想到变化或替换,都应涵盖在本申请的保护范围之内。因此,本申请的保护范围应以所述权利要求的保护范围为准。
Claims (14)
1.一种内核栈的分配方法,其特征在于,包括:
创建第一线程;
为所述第一线程申请内核栈,所述内核栈包括初始分配页和可分配页,所述初始分配页和所述可分配页的总和为S个页面,S=2N,N为大于或等于2的整数;
对所述内核栈的内存空间进行2k×S个页面对齐处理,其中k为大于或等于2的整数;
当所述第一线程在内核空间发生异常事件,且所述内核栈溢出时,从所述可分配页中为所述第一线程分配页面。
2.根据权利要求1所述的方法,其特征在于,所述方法还包括:
当所述第一线程在内核空间发生异常事件,且所述内核栈未溢出时,将所述第一线程的上下文数据压入所述内核栈中;
通过所述初始分配页处理所述异常事件。
3.根据权利要求1或2所述的方法,其特征在于,所述从所述可分配页中为所述第一线程分配页面,包括:
根据所述异常事件的异常类型,确定所述异常事件对应的页面分发策略;
在所述异常事件为所述内核栈访问异常的情况下,根据所述异常事件对应的页面分发策略,从所述可分配页中为所述第一线程分配页面。
4.根据权利要求3所述的方法,其特征在于,所述从所述可分配页中为所述第一线程分配页面,包括:
从所述可分配页中获取一个页面;
将所述一个页面与所述第一线程建立映射关系。
5.根据权利要求1至4中任一项所述的方法,其特征在于,应用于电子设备,所述电子设备包括所述内核栈,并且还包括第一栈;
在所述从所述可分配页中为所述第一线程分配页面之前,所述方法还包括:
将栈指针从所述内核栈切换到所述第一栈;
将所述第一线程的上下文数据压入所述第一栈中。
6.根据权利要求5所述的方法,其特征在于,所述将所述第一线程的上下文数据压入所述第一栈中,包括:
在所述第一栈未溢出的情况下,将所述第一线程的上下文数据压入所述第一栈中。
7.根据权利要求6所述的方法,其特征在于,在所述从所述可分配页中为所述第一线程分配页面之后,所述方法还包括:
根据所述第一线程的上下文数据,从所述第一栈出栈并返回到所述内核栈。
8.根据权利要求5或6所述的方法,其特征在于,所述方法还包括:
在所述第一栈溢出的情况下,将栈指针从所述第一栈切换到第二栈,并将所述第一线程的上下文数据压入所述第二栈中;
调用panic函数进行复位处理。
9.根据权利要求1至8中任一项所述的方法,其特征在于,S取4,k取2;
所述方法还包括:
当栈指针第14bit的数值为1时,判断所述内核栈溢出;或者,
当所述栈指针第14bit的数值为0时,判断所述内核栈未溢出。
10.根据权利要求1至9中任一项所述的方法,其特征在于,S取4,k取2;
所述方法还包括:
当栈指针第13bit的数值为1时,判断第一栈溢出;或者,
当所述栈指针第13bit的数值为0时,判断所述第一栈未溢出。
11.根据权利要求1至10中任一项所述的方法,其特征在于,所述异常事件为同步异常或者中断。
12.一种电子设备,其特征在于,包括处理器,所述处理器与存储器耦合,所述处理器用于执行所述存储器中存储的计算机程序或指令,以使得所述电子设备实现如权利要求1至11中任一项所述的方法。
13.一种芯片,其特征在于,包括处理器,所述处理器与存储器耦合,所述处理器用于执行所述存储器中存储的计算机程序或指令,以使得所述芯片实现如权利要求1至11中任一项所述的方法。
14.一种计算机可读存储介质,其特征在于,所述计算机可读存储介质存储有计算机程序,当所述计算机程序在电子设备上运行时,使得所述电子设备执行如权利要求1至11中任一项所述的方法。
Priority Applications (1)
Application Number | Priority Date | Filing Date | Title |
---|---|---|---|
CN202210600560.5A CN115098244B (zh) | 2022-05-30 | 2022-05-30 | 内核栈的分配方法、电子设备、芯片及存储介质 |
Applications Claiming Priority (1)
Application Number | Priority Date | Filing Date | Title |
---|---|---|---|
CN202210600560.5A CN115098244B (zh) | 2022-05-30 | 2022-05-30 | 内核栈的分配方法、电子设备、芯片及存储介质 |
Publications (2)
Publication Number | Publication Date |
---|---|
CN115098244A true CN115098244A (zh) | 2022-09-23 |
CN115098244B CN115098244B (zh) | 2024-04-05 |
Family
ID=83289744
Family Applications (1)
Application Number | Title | Priority Date | Filing Date |
---|---|---|---|
CN202210600560.5A Active CN115098244B (zh) | 2022-05-30 | 2022-05-30 | 内核栈的分配方法、电子设备、芯片及存储介质 |
Country Status (1)
Country | Link |
---|---|
CN (1) | CN115098244B (zh) |
Citations (4)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN107491373A (zh) * | 2017-08-09 | 2017-12-19 | 杭州迪普科技股份有限公司 | 一种任务栈溢出监测方法及系统 |
CN109857677A (zh) * | 2018-12-28 | 2019-06-07 | 晶晨半导体(上海)股份有限公司 | 内核栈的分配方法及装置 |
CN110096871A (zh) * | 2019-05-10 | 2019-08-06 | 南京大学 | 一种基于硬件虚拟化的多核环境进程内核栈保护方法 |
CN111858363A (zh) * | 2020-07-24 | 2020-10-30 | Oppo广东移动通信有限公司 | 栈溢出的识别方法、装置、终端及存储介质 |
-
2022
- 2022-05-30 CN CN202210600560.5A patent/CN115098244B/zh active Active
Patent Citations (4)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN107491373A (zh) * | 2017-08-09 | 2017-12-19 | 杭州迪普科技股份有限公司 | 一种任务栈溢出监测方法及系统 |
CN109857677A (zh) * | 2018-12-28 | 2019-06-07 | 晶晨半导体(上海)股份有限公司 | 内核栈的分配方法及装置 |
CN110096871A (zh) * | 2019-05-10 | 2019-08-06 | 南京大学 | 一种基于硬件虚拟化的多核环境进程内核栈保护方法 |
CN111858363A (zh) * | 2020-07-24 | 2020-10-30 | Oppo广东移动通信有限公司 | 栈溢出的识别方法、装置、终端及存储介质 |
Also Published As
Publication number | Publication date |
---|---|
CN115098244B (zh) | 2024-04-05 |
Similar Documents
Publication | Publication Date | Title |
---|---|---|
JP4639233B2 (ja) | プロセッサ・リソースの仮想化のためのシステムおよび方法 | |
US8949295B2 (en) | Cooperative memory resource management via application-level balloon | |
US11481221B2 (en) | Separate branch target buffers for different levels of calls | |
US20210294686A1 (en) | Fast memory mapped io support by register switch | |
CN115016894A (zh) | 一种线程的内存访问方法、装置、设备及存储介质 | |
US7818558B2 (en) | Method and apparatus for EFI BIOS time-slicing at OS runtime | |
EP1429246A1 (en) | Apparatus and method for switching mode in a computer system | |
US6138210A (en) | Multi-stack memory architecture | |
US6895583B1 (en) | Task control block for a computing environment | |
Wiseman et al. | Eliminating the threat of kernel stack overflows | |
JP2021531583A (ja) | メモリ・システム内に記憶されている制御テーブルのための二分探索手順 | |
WO2009123873A1 (en) | Sharing operating system sub-processes across tasks | |
US7934073B2 (en) | Method for performing jump and translation state change at the same time | |
US6058457A (en) | Method for storing method frames in multiple stacks | |
CN115098244B (zh) | 内核栈的分配方法、电子设备、芯片及存储介质 | |
US9405470B2 (en) | Data processing system and data processing method | |
US7444636B2 (en) | Method and system of determining attributes of a functional unit in a multiple processor computer system | |
US11960420B2 (en) | Direct memory control operations on memory data structures | |
US6067602A (en) | Multi-stack-caching memory architecture | |
US6915408B2 (en) | Implementation of thread-static data in multi-threaded computer systems | |
US6092152A (en) | Method for stack-caching method frames | |
US20120054773A1 (en) | Processor support for secure device driver architecture | |
Wiseman et al. | Safer Operating System for Vehicle Telematics | |
US9110793B2 (en) | Inner process | |
US11995218B2 (en) | Processor with a configurable distribution of privileged resources and exceptions between protection rings |
Legal Events
Date | Code | Title | Description |
---|---|---|---|
PB01 | Publication | ||
PB01 | Publication | ||
SE01 | Entry into force of request for substantive examination | ||
SE01 | Entry into force of request for substantive examination | ||
GR01 | Patent grant | ||
GR01 | Patent grant |