结合AliOS Things谈嵌入式系统通用问题定位方法(2):内核相关基础

简介: 内核提供的任务创建接口,会存在参数指定当前任务创建完立即运行还是需要显示调用start运行,需要注意。如果在创建任务时指定了立即执行,而在创建任务后去设置任务参数,可能是不生效的。(尤其posix的pthread接口经常遇到这种问题)

1、任务

1.1、任务创建

  • 任务自启动参数:

内核提供的任务创建接口,会存在参数指定当前任务创建完立即运行还是需要显示调用start运行,需要注意。如果在创建任务时指定了立即执行,而在创建任务后去设置任务参数,可能是不生效的。(尤其posix的pthread接口经常遇到这种问题)

  • 任务的栈参数:

任务的栈大小是由用户来指定的,一定要确认开栈大小是否满足自身需求。OS虽然有栈溢出检测,但是不是100%能检测出来的。引起的问题会非常混乱。

1.2、任务的调度策略

目前rhino内核提供的几种调度策略包括:

  • 优先级;
  • RR时间片;
  • CFS公平调度

需要注意的是,在前两种调度的任务中,如果用户任务内在死循环,且没有主动退出的动作,如sleep或者其他Pend动作,那这个任务会一直运行,直到中断的到来,才可能切换到更高优先级的任务,且低优先级任务永远无法运行。

1.3、任务和中断关联

任务执行中,如果不关中断,中断会随时打断任务上下文现场;

中断退出时,会发生任务调度,可能会有任务切换。

1.4、任务退出

需要关注的是,用户的任务处理函数内结束后,任务即会自动退出;

不需要用户手动调用删除任务接口;

也不能在任务自己退出后,还在使用任务的资源;

2、内存

2.1、内存空间管理

内存的堆一般是在ld链接脚本中预留的,通过固定的数据结构告诉OS。

链接脚本中定义堆空间:


  1. PROVIDE ( heap_start = __stack) ; //end of stack
  2. heap_end = ORIGIN( RAM) + LENGTH( RAM) ;
  3. PROVIDE ( heap_len = heap_end - heap_start) ;

堆的起点heap_start定义为栈的结尾,堆的结尾heap_end定义为RAM的结尾,这样剩余RAM的空间都交给OS管理。

对应的krhino的堆空间初始化为:


 
k_mm_region_t g_mm_region[] = {{(uint8_t *) &heap_start, (size_t) &heap_len}} ;

注意:这段内存分配给堆使用,并不是表示内存都耗尽了,而是将其交给OS管理,用户通过malloc出来的内存都是从其中申请。

2.2、内存分配管理

内核提供的内存申请返回地址和大小是8字节对齐的,上限受到总的堆空间的限制。

每一块的内存blk有管理头,用来提供基本的管理和维测信息。

内部会自动完成相关块的拆分合并,但是不可避免会有内存碎片的问题,需要通过下面的快速小内存来优化。

2.3、内存维测

通过内存头部的维测模块的信息,来对该内存块进行监控,主要包含的信息包括:

内存魔术字 => 判断是否被踩

申请的任务号 => 跟踪任务申请状况

申请的时间段 => 跟踪某时间段的内存申请释放情况

申请的backtrace => 具体是哪个位置申请的内存

当前内存状态: => 申请还是释放

具体参考:k_mm.h中k_mm_list_t数据结构

2.4、小内存快速申请

内核还额外提供快速内存申请功能。其提供可配置的2^N固定大小的内存快速申请和释放,优点是效率高,没有碎片,缺点是没有维测信息。

2.5、内存踩踏

内核中提供了自动对内存块的检测,看其内存头是否正确,来达到检测内存踩踏的目的,一般检测在下面的时间点发生:

内存释放:会检测当前内存块的魔术字是否被踩;检测下一块内存头是否正确;检测内存空闲/忙状态是否正确。

在发生内存致命错误或者异常时:

系统会遍历所有内存块,将可疑内存给检测输出出来。

会存在检测遗漏的现场:

尤其是用户空间被飞踩,则检测内存头部检测不出来;

也会经常存在内存头部的非魔术字信息被踩的情况。

从串口打印看是否有内存踩踏:

目前从串口的输出信息查找下面两个关键字,可快速查看是否系统检测出内存踩踏:


  
  1. !used !free
  2. ======== all memory error blocks =========
  3. kernel space mem layout:
  4. g_kmm_head = 40ccce60
  5. ALL BLOCKS
  6. Blk_Addr Stat Len Chk Caller Point
  7. 0x4f9176e0 used 2368 OK 0x40526c58 (0x40526c54 <- 0x40626730 <- 0x40627160 <- 0x4061aba0 <- 0x4061b228 <- 0x4061b8a8 <- 0x4061be40 <- 0x40615450 )
  8. 0x4f918050 free 48 OK 0x0 (0x40654b90 <- 0x40664964 <- 0x40664b64 <- 0x40561aa8 <- 0x0 <- 0x0 <- 0x0 <- 0x0 )
  9. 0x4f9180b0 !used 56 a848 0x406528d4 (0x406528d0 <- 0x40664964 <- 0x40664b64 <- 0x40664b60 <- 0x0 <- 0x0 <- 0x0 <- 0x0 )

如上图,检测出0x4f9180b0内存状态不对,此时一般首先怀疑被前面的内存块给踩了。当然这只是最基本的情况。

可以通过上面Caller打印出来的调用栈,通过addr2line命令输出。也可通过OS提供的自动解析脚本和IDE工具输出。

2.6、内存泄漏

当内存申请失败的时候,系统报致命错误,并将当前剩余空间,已经当前的内存状态都打印出来。

内存不足报错:


   
WARNING, malloc failed!!!! need size: 80, but free size: 40

所有的内存状态信息打印:


    
  1. ------------------------------- all memory blocks ---------------------------------
  2. g_kmm_head = 805985a0
  3. ALL BLOCKS
  4. Blk_Addr Stat Len Chk Caller Point
  5. 0x80598688 used 8 OK 0x0 (0x0 <- 0x0 <- 0x0 <- 0x0 <- 0x0 <- 0x0 <- 0x0 <- 0x0 )
  6. 0x805986c0 used 1049952 OK 0x0 (0x0 <- 0x0 <- 0x0 <- 0x0 <- 0x0 <- 0x0 <- 0x0 <- 0x0 )
  7. 0x80698c50 used 3112 OK 0x8000a448 (0x8000a444 <- 0x800084fc <- 0x80000780 <- 0x0 <- 0x0 <- 0x0 <- 0x0 <- 0x0 )

通过我们提供的python解析脚本,能自动检测可以内存泄漏点,使用方法:

把上面log 和对应 elf取出,和AliOS Things工程内提供的解析脚本 coredump_parser_mmleak.py放在同一目录

执行脚本:


     
./coredump_parser_mmleak.py err. log alios_kernel\@mt8153a-mk.kernel.elf

分析结果样例:


      
  1. ========== Show MM LEAK Info : Top 10 of Malloc-Cnt Backtrace ==========
  2. --------------------------------------------------------------------------------------------------------------------------------------------
  3. { 'Backtrace': '0x80290880 <- 0x8029f8b4 <- 0x802a0f2c <- 0x802a131c <- 0x80296ad8 <- 0x0 <- 0x0 <- 0x0', 'Blk Cnt': 18320, 'Total Size': 1124424}
  4. js_def_malloc at thirdparty/quickjs/quickjs.c: 34194 (discriminator 1)
  5. ========== Show MM Statistic Info ==========
  6. Caller | Func | Alloc Cnt | Total Size | Line | File
  7. 0x802fd8c4 | sk_malloc_flags( unsigned int, unsigned int) | 249 | 22265888 | 263 | thirdparty/skia/src/core/SkMemory_stdlib.cpp

可以将目前申请次数最大,以及申请内存总数最大的位置导出,供用户进一步分析。

2.7、堆和栈

内核中的堆指的是划分给内存malloc申请的内存空间;

栈一般是任务运行的自身的栈空间,用作用户函数执行过程中的压栈出栈处理;

另外还有CPU相关的模式栈、系统栈之类的,用户暂不用关注。

3、中断

3.1、中断必调接口

一般在CPU架构代码中已经默认调用,但是一定要确保中断上下文调用过。


       
  1. krhino_intrpt_enter(); //指示系统进入中断上下文
  2. isr_handler();
  3. krhino_intrpt_exit(); //内部会进行切换动作

3.2、中断中失效接口

Sem、mutex、queue的等待接口不能在中断中使用,因为其会调度当前的task,而目前正处于中断上下文;当然OS可以封装一层不触发调度的基本等待接口,但是一旦没有等待信息,会立即返回失败,没有等待的效果。

对应的释放接口可以在中断中使用。

3.3、中断优先级

目前中断设定为同样的优先级,不支持中断抢占。

3.4、中断开关

用户接口不应该直接调用开关中断的接口,而全部内核接管。

3.5、Fiq和irq

普通的中断一般叫irq,位于GIC架构的Group1;另外ARM还提供的快速中断fiq,位于Group0,其默认优先级高于所有的irq中断,能打断任意中断和任务现场

4、多核相关

4.1、任务相关接口

内核提供所有的对外接口都可以在单核或者多核场景下使用,且能到达相关的目的。

如mutex接口能同时保障单核和多核的互斥。

同时还提供了4个基本的多核扩展接口:

krhino_task_cpu_create

任务静态创建,并指定核运行

krhino_task_dyn_create

任务动态创建,并指定核运行

krhino_task_cpu_bind

任务绑定核运行

krhino_task_cpu_unbind

任务解绑核运行,运行核随机

4.2、多核互斥接口

原则上,用户使用通用的mutex接口来进行互斥,不直接使用和系统运行深度关联的关中断、加锁功能接口,以免造成不必要的死锁。

对于死锁问题,尤其要排查用户显示调用加锁的地方是否有问题。

4.3、加锁和关中断

加锁接口前必定要关中断:

对于普通核内不可嵌套锁,中断触发后再次加锁会导致死锁;

对于核内嵌套锁,如果不关中断,内部发生调度,该任务被调度到其他核,那么就会导致解锁失败。

同样的原理:关中断加锁接口内,只能有普通的数据、寄存器操作,不能调用会发生切换的接口,如mutex、printf、malloc。

5、用户态/内核态

内核态与用户态权限隔离、页表隔离

任务的三种运行状态:用户态任务、内核态任务、用户态任务的内核模式;

用户态异常现场在SVC,说明进入了内核态之后异常,得查看内核态的现场;

拿到异常现场需要首先确认异常发生在用户态还是内核态。

判断方法:

  • 查看异常PC和相关通用寄存器空间处于用户态还是内核态;
  • 从异常打印现场区分

内核会在异常时检测是用户态还是内核态异常,区分关键字 :

“kernel space exception” : 内核态发生异常

“uspace \*\* exception” : 用户态发生异常

“uspace task result exception in kernel” : 用户态任务系统调用进入内核发生异常

开发者技术支持

如需更多技术支持,可加入钉钉开发者群,或者关注微信公众号

image.png

更多技术与解决方案介绍,请访问阿里云AIoT首页https://iot.aliyun.com/

相关文章
|
物联网 Linux C语言
3_1_2 AliOS Things 编译工具及编译配置系统|学习笔记
快速学习3_1_2 AliOS Things 编译工具及编译配置系统。
386 0
3_1_2 AliOS Things 编译工具及编译配置系统|学习笔记
|
监控 物联网 测试技术
|
NoSQL 安全 IDE
结合AliOS Things谈嵌入式系统通用问题定位方法(1):CPU相关基础
本文着重从问题定位的角度来介绍如何定位嵌入式软件系统中的问题,并结合AliOS Things提供的部分维测手段来介绍。
结合AliOS Things谈嵌入式系统通用问题定位方法(1):CPU相关基础
|
物联网 调度
AliOS Things SMP系统及其在esp32上实现示例
AliOS Things实现了基本的SMP调度框架,支持多CPU体系的系统运行和调度机制。任务可以动态在多核间进行切换或者绑定运行;高优先级任务可以最大化利用空闲资源核运行。基于此框架,可以快速实现AliOS Things在各种不同多核CPU架构下的移植。
5335 0
|
物联网 测试技术 持续交付
AliOS Things 持续集成(CI)系统介绍
AliOS Things在快速的迭代进化之中,如何保证提交的代码质量,并保证在各个硬件平台上的稳定性,是一个非常大的挑战。同时物联网硬件碎片化,资源紧张,对持续集成(CI)系统也提出了特殊的要求。本文介绍AliOS Things的CI系统的实现方式及思考。
5610 0
|
安全 物联网 Java
AliOS Things 组件系统(uCube)
AliOS Things 是阿里巴巴提供的物联网操作系统,可以在不同的设备上运行不同的功能,甚至相同的设备运行不同的功能,AliOS Things 基于组件管理: 1、 组件功能单一,复用组件提供的功能,比如通道、升级等功能。
4392 0
|
传感器 消息中间件 物联网
HCIA物联网初级考试-第五章物联网操作系统及感知层开发介绍
HCIA物联网初级考试-第五章物联网操作系统及感知层开发介绍
HCIA物联网初级考试-第五章物联网操作系统及感知层开发介绍
|
算法 AliOS-Things 物联网
HaaS100开发调试系列 之 定位AliOS Things内存及Crash问题
本文主要说开发调试过程中经常遇到的内存问题。
347 15
HaaS100开发调试系列 之 定位AliOS Things内存及Crash问题
|
AliOS-Things 物联网 编译器
使用HaaS Studio开发AliOS Things C/C++应用
本文章将介绍使用HaaS Studio 进行AliOS-Things C/C++应用开发。
使用HaaS Studio开发AliOS Things C/C++应用
|
NoSQL 物联网
使用线上的开发板做开发调试 |《AliOS Things快速开发指南》
当您手上没有现成可用的开发板时,也可以使用线上的开发板来调试验证您的程序。本文主要介绍线上开发板的使用流程。
使用线上的开发板做开发调试 |《AliOS Things快速开发指南》