1.tick?内核ں?Դ??
2.å¦ä½å¦ä¹ nucleus os
3.SpringBoot定时任务 - 经典定时任务设计:时间轮(Timing Wheel)案例和原理
4.nodejs原理&源码赏析(7)Node.js中的事件循环,定时器和process.nextTick
5.浅析linux 内核 高精度定时器(hrtimer)实现机制(二)
6.iowait 到底是源码源码什么?
tick?ں?Դ??
本文深入解析鸿蒙轻内核的时间管理机制,关注其在任务调度与时间服务中的分析关键作用。时间管理模块的内核核心在于处理系统时钟的Tick中断,为应用程序提供时间转换、源码源码统计等服务。分析切牌源码
基于OpenHarmony LiteOS-M内核的内核源码,我们首先从系统时钟的源码源码生成机制讲起,它是分析通过定时器/计数器产生的Tick,作为操作系统的内核基本时间单位。Tick的源码源码周期和数量可以根据用户配置进行调整,如1ms等于个Tick。分析此外,内核Cycle作为最小计时单位,源码源码与主时钟频率紧密相关。分析
在代码实现上,时间管理的初始化和启动过程涉及关键配置,如系统时钟和Tick频率,以及可能的定制中断处理函数。在main函数中,通过调用一系列函数逐步启动和配置时间管理模块。
Tick中断处理函数OsTickHandler负责实时更新Tick计数,检查任务状态和定时器,确保时间服务的准确执行。同时,内核提供了实用工具,如将毫秒、Tick和Cycle互相转换,以及统计自系统启动以来的时间量。
总的来说,鸿蒙轻内核的actionsupport 源码时间管理模块是任务调度和应用程序之间时间协调的关键桥梁,其源码提供了深入了解和定制操作的基础。对于开发者来说,这是一项重要的技术基础,有助于优化系统性能和用户体验。
å¦ä½å¦ä¹ nucleus os
å 容ï¼
ä¸ãnucleus plusç¹ç¹ï¼
1.å æ ¸éç¨å¾®å æ ¸ç设计ï¼æ¹ä¾¿ç§»æ¤ï¼èµæåçæ´reliableï¼ä½æ¯æä¸è¿ä¹è®¤ä¸ºï¼ä¸linuxç¸æ¯ï¼ä»¥ARMå¹³å°ä¸ºä¾ï¼NUåªç¨å°äºSVC modeï¼å æ ¸ä¸ç¨æ·ä»»å¡é½è¿è¡å¨åä¸ä¸ªç¶æä¸ï¼ä¹å°±æ¯è¯´ææçtaské½æ¥æ访é®ä»»ä½èµæºçæéï¼è¿æ ·å¾reliableä¹ï¼
2.real-time OSï¼NUæ¯ä¸ä¸ªè½¯å®æ¶æä½ç³»ç»ï¼VxWorksæ¯ç¡¬å®æ¶ï¼ï¼thread control componentæ¯æå¤ä»»å¡ä»¥åä»»å¡çæ¢å ï¼å¯¹äºä¸æçå¤çå®ä¹äºä¸¤ç§æå¡æ¹å¼ï¼LISRåHISRï¼è¿ä¸ªä¸linuxä¸çä¸ãä¸åé¨æºå¶ç±»ä¼¼ï¼linuxä¸çä¸åé¨æ¯éè¿è½¯ä¸ææ¥å®ç°çï¼NUçHISRåªæ¯ä½ä¸ºä¸ç§ä¼å 级æ»æ¯é«äºtaskçä»»å¡åºç°ã
3.NUæ¯ä»¥libraryçæ¹å¼åºç¨çï¼éè¿åèªå·±çapp taskä¸è£åªåçNUå æ ¸åç»ä»¶é¾æ¥èµ·æ¥ï¼NU并没æCLI
äºãç»ä»¶
1.IN component
åå§åç»ä»¶ç±ä¸ä¸ªé¨åç»æï¼ç¡¬ä»¶å¨resetåé¦å è¿å ¥INT_initialize()ï¼è¿è¡æ¿çº§çç¸å ³åå§åï¼é¦å 设置SVC modeï¼å ³ä¸æï¼ç¶åå°å æ ¸ä»romä¸æ·è´è³ramä¸ï¼å»ºç«bss段ï¼ä¾æ¬¡å»ºç«sys stack, irq stackåfiq stackï¼æååå§åtimerï¼å»ºç«timer HISRçæ 空é´ï¼çäºä¸ä¸å¹³å°ç代ç ï¼ä¸ä¸ªtick大æ¦æ¯.8msï¼å®ææ¿çº§çåå§ååå°±è¿å ¥äºINC_initializeï¼åå§åå个ç»ä»¶ï¼å ¶ä¸å æ¬Application initializeï¼create taskåHISRï¼æåå°æ§å¶æ交ç»scheduleï¼ä¸»è¦çäºä¸ä¸RAMä¸å°å空é´çå®æ
|timer HISR stack = |
|FIQ stack = |
|IRQ stack = |
|SVC stack = |
|.bss|
|.data|
|.text|
å ¶ä¸SVC stackç大å°ä¸ä¸ææºç个æ°ç¸å ³ï¼nested irqåçæ¶ï¼irq_contextä¿åå¨SVC stackä¸ï¼IRQçstackåªæ¯åäºä¸´æ¶æ çä½ç¨ã
2.thread control component
TCç»ä»¶æ¯NUå æ ¸çæéè¦ç»æé¨åï¼ä¸»è¦æ¶µçäºè°åº¦ãä¸æãä»»å¡çç¸å ³æä½ãéãæ¶éå 个æ¹é¢ï¼ä¸é¢åå«ä»ç»ã
è°åº¦ï¼scheduleï¼
NUä¸ç线ç¨ç±»åï¼å¨åä¸ä¸ªå°å空é´å ï¼æ两ç§ï¼HISRåtaskï¼HISRå¯ä»¥ç解为ä¸ç§ä¼å 级è¾é«çtaskï¼ä½åä¸æ¯taskï¼HISRä¼å 级é«äºtaskçå®ç°æ¹å¼å°±æ¯schduleæ¶ï¼å å»æ¥çå½åæ¯å¦æactiveçHISRï¼åå»æ¥çtaskãtaskæsuspendãreadyãfinishedåterminatedåç§ç¶æï¼èHISRåªæexecutingåno-activeè¿ä¸¤ç§ç¶æã
æ¯ä¸ä¸ªtaské½æä¸ä¸ªçº¿ç¨æ§å¶çæ°æ®ç»æï¼TCB thread control blockï¼,å ¶ä¸å æ¬äºtaskçä¼å 级ãç¶æãæ¶é´çãtaskæ ãprotectä¿¡æ¯ãsignalæä½çæ å¿ä½åsignal_handlerçï¼taskå¨å建æ¶åå§åè¿äºä¿¡æ¯ï¼å°taskæå°ä¸ä¸ªcreate_listä¸ï¼åå§è®¾å®task为pure_suspendï¼å¦æ设å®auto startï¼è°ç¨resume_taskï¼ï¼å¤étaskï¼è¿éæ个ç»èï¼å¦æå¨application initializeä¸create_task()ï¼åtaskä¸ä¼èªå¨è¿è¡ï¼å 为åå§åè¿æªå®æï¼æ§å¶æè¿æ²¡æ交ç»scheduleï¼æ æ³è°åº¦taskãtask被å¤éåç¶ææ¹å为readyï¼å¹¶æå¨ä¸ä¸ªTCD_Priority_List[]ä¸ï¼æ°ç»çæ¯ä¸ªå ç´ æ¯ä¸ä¸ªæåTCBç¯å½¢ååé¾è¡¨çæéï¼æ ¹æ®taskçtc_priorityæ¾å°å¯¹åºä¼å 级çTCB head pointerã
æ¯ä¸ä¸ªHISRé½æä¸ä¸ªHISRæ§å¶çæ°æ®ç»æï¼HCB HISR control blockï¼,å ¶ä¸åªæä¼å 级ï¼HISRæ åHISR entryä¿¡æ¯ï¼å æ¤HISRæ¯ä¸å¯ä»¥suspendï¼åæ¶ä¹æ²¡ætime slice以åsignalçç¸å ³æä½ï¼ä¸è¬æ åµä¸å½åçäºä¸æåï¼HISR被activateï¼scheduleå°±ä¼è°åº¦HISRè¿è¡ï¼æé´å¦æä¸åçä¸æï¼HISRçæ§è¡æ¯ä¸ä¼è¢«ææçï¼HISRçä¼å 级åªæ0ã1ã2ï¼timerçHISRä¼å 级为2ï¼ä¹å°±æ¯è¯´ç±å¤é¨ä¸ææ¿æ´»çHISRå¾é¾è¢«æ¢å çï¼åªææ´é«ä¼å 级çä¸æHISRæå¯ä»¥ãä¸taskä¸åï¼è¢«æ¿æ´»çHISR使ç¨head_liståtail_listå°HCBæå¨ä¸ä¸ªå项çé¾è¡¨ä¸ï¼å 为ç¸åä¼å 级çHISRä¸ä¼æ¢å 对æ¹ï¼å æ¤ä¸éè¦ååé¾è¡¨ï¼ä½¿ç¨ä¸¤ä¸ªæéç®çæ¯å å¿«HISRæ§è¡çé度ã
ä¸ä¸ªå®æ¶æä½ç³»ç»çæ ¸å¿å°±æ¯å¯¹äºä»»å¡çè°åº¦ï¼NUçè°åº¦çç¥æ¯time sliceåround robinçç®æ³ï¼
è°åº¦çé¨å主è¦æä¸ä¸ªå½æ°control_to_system()ç¨äºä¿åä¸ä¸æï¼å»ºç«solicited stackï¼å ³ä¸æï¼å ³system time sliceï¼å¹¶éç½®taskçtime slice为é¢è®¾å¼ï¼å°spæ´æ°ä¸ºsystem_stack_pointerï¼è°ç¨schedule()ï¼è°åº¦çè¿ç¨æ¯é常ç®åçæ¥è¯¢ï¼å°±æ¯æ¥çä¸¤ä¸ªå ¨å±çåéï¼TCD_Execute_HISRåTCD_Execute_Taskï¼scheduleé¨åçå ³é®æ¯æå¼äºä¸æï¼ä¸ç¶å¦æå½å没æreadyçtaskææ¯è¢«æ¿æ´»çHISRï¼åsheduleæ»å¾ªç¯ä¸å»ï¼æ¥è¯¢å°ä¸ä¸ä¸ªåºè¯¥æ§è¡ç线ç¨å跳转è³control_to_thread(),å¨è¿ééæ°å¼å¯system time sliceï¼ç¶åå°çº¿ç¨çtc_stack_ptrå å ¥å°spä¸ï¼åæ¢è³çº¿ç¨çæ ä¸ï¼ä¾æ¬¡popåºæ¥ï¼å³å®æäºä»»å¡è°åº¦ã
ä»»å¡çåæ¢ä¸»è¦æ¯ä¸ä¸æçåæ¢ï¼ä¹å°±æ¯taskæ çåæ¢ï¼å½æ°çè°ç¨ä¼ä¿åé¨åregsåè¿åå°åï¼è¿äºå¨ä½é½æ¯ç¼è¯å¨æ¥å®æçï¼èOSä¸çä»»å¡åæ¢æ¯è¿è¡æ¶ï¼runtimeï¼çä¸ç§ç¶æååï¼å æ¤ç¼è¯å¨ä¹æ è½ä¸ºåï¼æ以对äºä¸ä¸æçä¿åéè¦ä»£ç æ¥å®ç°ã
ä»»å¡çæ¢å æ¯å¼æ¥çå æ¤å¿ é¡»è¦éè¿ä¸ææ¥å®ç°ï¼ä¸è¬æ¯æ¬¡timerçä¸æå³å®å½åçtaskçslice timeæ¯å¦expiredï¼ç¶å设置TCT_Set_Execute_Task为ç¸åä¼å 级çå ¶ä»taskææ´é«ä¼å 级çtaskï¼é«ä¼å 级çtaskæ¢å ä½ä¼å 级çtaskï¼ä¸è¬æ¯å¤é¨ä¸æ触åï¼å¨HISRä¸resume_task()å¤éé«ä¼å 级çtaskï¼ç¶åscheduleå°é«ä¼å 级çtaskä¸ï¼å 为timerçHISRæ¯å¨ç³»ç»åå§å就已ç»æ³¨åçï¼åªæ¯æ§è¡timeoutåtime sliceè¶ æ¶åçæä½ï¼å¹¶æ²¡ææ§è¡resume_taskçå¨ä½ã
NUä¸çstackæ两ç§solicited stackåinterrupt stackï¼solicited stackæ¯ä¸ç§minmum stackï¼èinterrupt stackæ¯å¯¹å½åææå¯åå¨å ¨é¨ä¿åï¼TCBä¸çminimum stack size = ç³è¯·å¾å°stack size - solicited stackï¼å¨arm modeä¸å åèï¼thumb modeä¸å åèï¼ï¼thumbæ å¿ç¨æ¥è®°å½ä¸ä¸æä¿åæ¶çARMçå·¥ä½æ¨¡å¼ï¼c代ç ç¼è¯ä¸ºthumb模å¼ï¼è¿æ ·å¯ä»¥åå°code sizeï¼æé«ä»£ç å¯åº¦ï¼assembly代ç ç¼è¯ä¸ºarm模å¼æå代ç çæçï¼NUä¸å æ ¸ç代ç ä¸å¤ï¼ä¸»è¦æ¯assembly代ç ãstackçç±»åä¸å ¶ä¸PCæåçshellæ å ³ï¼interrupt stackä¿åçæ¯taskææ¯HISRå¨æ§è¡çè¿ç¨ä¸è¢«ä¸ææ¶çç°åºï¼solicited stack建ç«çå°æ¹å æ¬ control_to_system()ãschedule_protect()åsend_signals()åéç»å æprotectèµæºçtaskçæ åµï¼HISR_Shell()æ§è¡å®åä¼å»ºç«solicited stackï¼å跳转è³scheduleã
(Lower Address) Stack Top -> 1 (Interrupt stack type)
CPSR Saved CPSR
r0 Saved r0
r1 Saved r1
r2 Saved r2
r3 Saved r3
r4 Saved r4
r5 Saved r5
r6 Saved r6
r7 Saved r7
r8 Saved r8
r9 Saved r9
r Saved r
r Saved r
r Saved r
sp Saved sp
lr Saved lr
(Higher Address) Stack Bottom-> pc Saved pc
(Lower Address) Stack Top -> 0 (Solicited stack type)
!!FOR THUMB ONLY!! 0/0x Saved state mask
r4 Saved r4
r5 Saved r5
r6 Saved r6
r7 Saved r7
r8 Saved r8
r9 Saved r9
r Saved r
r Saved r
r Saved r
(Higher Address) Stack Bottom-> pc Saved pc
ä¸ä¸ªç®åçä¾å说æstackçæ åµï¼é¦å æ¯ä¸ä¸ªtaskå¨ready(executing)çç¶æä¸ï¼èä¸time sliceè¶ æ¶äºï¼timerä¸æåçåï¼ä¿åtaskä¸ä¸æinterrupt_contex_save()ï¼å¨taskçtc_stack_ptræåçå°æ¹å»ºç«ä¸ææ
taskA |interrupt stack|___tc_stack_ptr æ 顶端æ¯pc=lr-4
ARM对äºä¸æçå¤å®åçå¨å½åæ令å®æexecuteæ¶ï¼åæ¶pipelineçåå pc=pc+8ï¼å ¥æ æ¶å°±ælr-4é¦å æ¾å¨stackçæé«ç«¯ï¼highï¼ã
timerçLISRå®æåæ¿æ´»äºHISRï¼æ§è¡TCC_Time_slice()å°å½åtask移å°ç¸åä¼å 级ç尾端ï¼å¹¶ä¸è®¾ç½®ä¸ä¸ä¸ªè¦æ§è¡çtaskï¼HISRå¨æ 顶端ä¿åçæ¯è¿ä¸ªHISR_shellçå ¥å£å°åï¼å 为taskçæ§è¡å®å°±finishedï¼HISRæ¯å¯éå ¥ç
HISR |solicited stack| æ 顶端æ¯HISR_shell_entry
ä¸æï¼interruptï¼
åé¢å·²ç»æåäºä¸æçåºæ¬æä½ï¼è¿éå°±åä¸äºä»£ç è·¯å¾çç»èï¼ä¸æçæ§è¡ä¸»è¦æ¯ä¸¤ä¸ªé¨åLISRåHISRï¼åæ两个é¨åçç®çå°±æ¯å°å ³ä¸æçæ¶é´æå°åï¼å¹¶ä¸å¨LISRä¸å¼ä¸æå 许ä¸æçåµå¥ï¼ä»¥å建ç«ä¸æä¼å 级ï¼é½å¯ä»¥åå°ä¸æç延è¿ï¼ä¿è¯OSçå®æ¶æ§ã
NUçä¸æ模å¼æ¯å¯éå ¥çä¸æå¤çæ¹å¼ï¼ä¹å°±æ¯åºäºä¸æä¼å 级ååµå¥ç模å¼ï¼ä¸æçåµå¥å¨å¤ççè¿ç¨ä¸åºå¯¹lr_irq_modeå¯åå¨è¿è¡ä¿åï¼å 为é«ä¼å 级çä¸æåçæ¶ä¼è¦çæä½ä¼å 级ä¸æçråspsrï¼å æ¤è¦å©ç¨ç³»ç»çæ æ¥ä¿åä¸ææ ã
NU对äºä¸æä¸ä¸æçä¿åå ·ä½æä½å¦ä¸ï¼
ï¼1ï¼å¨ä¸æåçåæ§è¡çå ¥å£å½æ°INT_IRQ()ä¸ï¼å°r0-r4ä¿åè³irqçæ ä¸
ï¼2ï¼æ¥æ¾å°å¯¹åºçinterrupt_shell()ï¼clearä¸ææºï¼æ´æ°å ¨å±çä¸æ计æ°å¨ï¼ç¶åè¿è¡interrupt_contex_save
ï¼3ï¼é¦å å©ç¨r1,r2,r3ä¿åirq模å¼ä¸çsp,lr,spsrï¼è¿éspæ¯ç¨æ¥åæ¢è³ç³»ç»æ åæ·è´lråspsrç,è¿éä¿ålråspsræ¯ç®çæ¯task被æ¢å åï¼å½å次scheduleæ¶å¯ä»¥è¿åtaskä¹åçç¶æã
ï¼4ï¼åæ¢è³SVC模å¼ï¼å¦ææ¯éåµå¥çä¸æåä¿åä¸ä¸æè³task stackä¸ï¼å°irq模å¼ä¸çlrä½ä¸ºé¡¶ç«¯PCçè¿åå¼å ¥æ ï¼å°SVC模å¼ä¸çr6-rå ¥æ ï¼å°irq模å¼ä¸çspä¿åè³r4ä¸å ¥æ ï¼æåå°ä¿åå¨irq_stackä¸çr0-r4å ¥æ
ï¼5ï¼å¦ææ¯åµå¥ä¸æï¼ä¸æçåµå¥åçå¨LISRä¸ï¼å¨æ§è¡LISRæ¶å·²ç»åæ¢è³system stackï¼å æ¤åµå¥ä¸æè¦å°ä¸æçä¸ä¸æä¿åè³system stackä¸ï¼ä¸task stackä¸interrupt stackç¸æ¯åªæ¯å°äºæ 顶ç¨æ¥æ è®°åµå¥çæ å¿ï¼1 not nestedï¼
ï¼6ï¼æä¸ä¸ªåæ¯å¤æï¼å°±æ¯å¦æå½å线ç¨æ¯ç©ºï¼å³TCD_Current_Thread == NULLï¼è¡¨æå½åæ¯scheduleä¸ï¼å 为åå§å线ç¨æ¯å ³ä¸æçï¼è¿æ ·å°±ä¸ä¸ºschedule线ç¨å»ºç«æ 帧ï¼å 为scheduleä¸éè¦ä¿åä¸ä¸æï¼å¨restoreä¸æä¸ä¸ææ¶ç´æ¥è·³è½¬è³scheduleã
ä¸æä¸ä¸æçæ¢å¤
å ¨å±çä¸æ计æ°å¨INT_Countæ¯å¦ä¸º0æ¥å¤å®å½ååºæ çä¿¡æ¯ï¼å¦ææ¯åµå¥åè¿åLISRä¸ï¼å¦ååæ¢è³system stackæ§è¡schedule
timer
timerä¸ä¸æç´§å¯ç¸å ³ï¼å ¶å®timerä¹æ¯ä¸æçä¸ç§ï¼åªæ¯åçä¸æçé¢çè¾é«ï¼ä¸ä½ç¨é大ï¼ä¸ä¸ªå®æ¶æä½ç³»ç»ï¼æ¶é´æ¯é常éè¦çä¸é¨åï¼NUä¸çtimer主è¦æå个ä½ç¨ï¼
ï¼1ï¼ç»´æ¤ç³»ç»æ¶é TMD_system_clock
ï¼2ï¼taskçtime slice
ï¼3ï¼taskçsuspend timeout timer
ï¼4ï¼application timer
å ¶ä¸ï¼3ï¼ï¼4ï¼å ±ç¨ä¸ç§æºå¶ï¼ä¸ä¸ªå ¨å±çæ¶é´è½´TMD_timerï¼timeout timeråapp timeré½å»ºç«å¨ä¸ä¸ªTM_TCBçæ°æ®ç»æä¸ï¼éè¿tm_remaining_timeæ¥è¡¨å¾å½åtimerçå©ä½æ¶é´ï¼ä¾å¦å½åætimer_listä¸æä¸ä¸ªTM_TCBï¼ä¾æ¬¡æ¯Ta = 5ï¼Tb = 7, Tc = ,é£ä¹å»ºç«çé¾è¡¨ä¸å©ä½æ¶é´ä¾æ¬¡æ¯5ï¼2ï¼8ï¼å¦æç°å¨è¦å å ¥ä¸ä¸ªæ°çtimeræ ¹æ®timerå¼æå ¥è³åéçä½ç½®ï¼å¦ææå ¥çtimer为ï¼åå®æå¨Tbåé¢ï¼å©ä½æ¶é´ä¸º1ï¼åé¢ç8æ¹ä¸º7ï¼å½åçäºtimer expiredï¼å触åtimer_HISRï¼å¦ææ¯app timeråæ§è¡timer callbackï¼å¦ææ¯task timeout timerï¼åæ§è¡TCC_Task_Timeoutå¤étaskã
ï¼2ï¼çå®ç°ä¹æ¯ä¾èµäºå ¨å±çtime sliceæ¶é´è½´ï¼æ¯ä¸ä¸ªtaskå¨æ§è¡æ¶é½ä¼å°èªå·±çæ¶é´çä¿¡æ¯æ´æ°è³å ¨å±çæ¶é´è½´ä¸ï¼å½ä¸ä¸ªtaskçtime sliceæ§è¡å®å¨timer HISRä¸è°ç¨TCC_task_Timeoutå°å½åçtaskæ¾å¨ç¸åä¼å 级listçæ尾端ï¼å¹¶è®¾ç½®ä¸ä¸ä¸ªæé«ä¼å 级çä»»å¡ãtaskå¨æ§è¡çè¿ç¨ä¸åªæ被ä¸æåtime sliceä¼ä¿åä¸æ¥ï¼å ¶ä»è®©åºå¤çå¨çæ åµé½ä¼å°time sliceæ´æ°ä¸ºé¢è®¾å¼ã
protect
protectä¸linuxçéæºå¶ç±»ä¼¼ï¼äºæ¥è®¿é®ï¼å©ç¨å¼å ³ä¸ææ¥å®ç°ï¼å¹¶ä¸æ¥æprotectçtaskæ¯ä¸å¯ä»¥suspendçï¼å¿ é¡»è¦å°protectéæ¾åæå¯ä»¥æèµ·ï¼å½ä¸ä¸ªä¼å 级è¾ä½çtaskå æprotectèµæºï¼å¦æ被æ¢å ï¼ä¸ä¸ªé«ä¼å 级çtaskæHISRå¨è¯·æ±protectèµæºæ¶ä¼æ§è¡TCC_schedule_protect()让åºå¤çå¨ç»ä½ä¼å 级çtaskæ§è¡ï¼ç´å°ä½ä¼å 级çtaskæ§è¡unprotect()为æ¢ï¼æ¤æ¶taskæHISR建ç«çæ¯solicited stackï¼åæ¶å¨control_to_threadåå¼å ³ä¸æä¸æ¬¡ï¼è¿æ ·å¯ä»¥åå°ä¸æ¬¡ä¸ä¸æçåæ¢ãNUä¸å¸¸ç¨å°çæ¯system_protectï¼å®å°±æ¯ä¸æ大éï¼ä¿æ¤å æ ¸ä¸ææå ¨å±æ°æ®ç»æç顺åºè®¿é®ï¼ç²åº¦å¾å¤§ã
LISRä¸ä¸å¯ä»¥è¯·æ±protectèµæºï¼å 为LISRæ¯ä¸ætaskåæ§è¡ï¼å¦ætaskå æprotectèµæºï¼è¿æ¶LISRåå»è¯·æ±protectèµæºï¼ä¼åçæ»éï¼å 为LISR让åºå¤çå¨åï¼schedule没åæ³å次è°åº¦å°LISRæ§è¡ï¼ååçæ»éé误ï¼å æ¤å¨LISRä¸é¤äºactivate_HISRï¼ï¼ä»¥å¤ä¸å¯ä»¥ä½¿ç¨system callï¼ä¾å¦resume_taskççï¼è¿åç³»ç»è°ç¨é½ä¼è¯·æ±protectèµæºã
对äºprotectç请æ±æç §ä¸å®ç顺åºå¯ä»¥é²æ¢æ»éï¼NUçæºç ä¸ä¸è¬å°system_protectèµæºç请æ±æ¾å¨åé¢ï¼å ¶ä»å¦DM_protectå 请æ±ã
SpringBoot定时任务 - 经典定时任务设计:时间轮(Timing Wheel)案例和原理
在探讨经典定时任务设计时,时间轮(Timing Wheel)无疑是一个引人注目的概念。时间轮是一种环形数据结构,由George Varghese和Tony Lauck在年提出,被广泛应用于Linux内核中,并构成了Linux定时器的基础之一。时间轮的结构类似于一个时钟,分为多个格子(Tick),每个格子代表固定的时间间隔,指向存储在其中的任务链表。
具体而言,任务的添加与执行遵循时间轮的规则:假设任务在秒后执行,它将转两轮,最终加入Tick=1位置的链表。当时钟转至两轮后到达Tick=1的位置时,会启动该链表中的任务。这使得时间轮成为非准实时、延迟短平快任务的理想选择,比如心跳检测。
Netty的HashedWheelTimer正是基于时间轮的原理设计,旨在解决延迟任务和低时效性问题。在Netty中,HashedWheelTimer特别适用于优化I/O超时调度,例如在长连接场景中判断连接是否idle。通过使用时间轮,Netty能够高效地管理数百万级别的leakcanary源码长连接,减少资源占用,提升系统性能。
HashedWheelTimer的使用方式主要包括构造函数参数的设置,其中关键参数包括轮数、tick数等。通过合理配置,开发者可以针对特定需求定制时间轮的运行逻辑。例如,可以设置轮数为多级,形成层次化的结构,进一步优化任务调度。
通过示例代码展示,HashedWheelTimer可以实现5秒后执行任务的逻辑,并提供任务失效后的cancel机制,使其重新在3秒后执行。这些功能使得HashedWheelTimer在处理I/O超时等延迟任务时展现出强大优势。
对于HashedWheelTimer的内部实现,它主要包括构造函数、创建轮、任务添加、执行方法和停止方法等关键部分。这些内部机制协同工作,确保了时间轮高效稳定地运行。
理解多级时间轮的概念时,可以将其类比为时间的多级分层,如小时、分钟、秒的层级结构。在这种结构中,每层的vplayer源码轮转代表更长的时间间隔,实现了一种层次化的任务调度机制。
为了深入了解HashedWheelTimer的实现细节,开发者可以查阅相关源码,如在github上找到的示例代码。通过系统学习后端开发的全栈知识体系,可以进一步巩固对时间轮及其应用的理解。
告别碎片化的学习方式,采用一站式、体系化的学习路径,是提升后端开发技能的有效方法。通过精进Java全栈知识体系,开发者能够全面掌握关键概念和技术,为职业生涯发展打下坚实基础。
nodejs原理&源码赏析(7)Node.js中的事件循环,定时器和process.nextTick
事件循环是Node.js的核心机制,确保了其非阻塞I/O模型的实现。尽管JavaScript在Node.js中是单线程运行的,它却能利用系统内核的多线程特性处理并发任务。Node.js在开始执行时初始化事件循环,处理脚本文件或REPL环境中的异步调用。事件循环通过检查异步I/O、定时器和process.nextTick调用,然后进入各个阶段,处理回调函数。每个阶段维护一个先进先出的回调队列,处理与阶段相关操作后执行队列中的回调,直至队列为空或达到最大函数执行数量。系统操作回调、定时器和处理关闭回调的阶段各有功能。setImmediate()与setTimeout()相似,mount 源码但执行顺序受调用上下文影响,setImmediate()在I/O周期中通常优先执行。process.nextTick()则在当前操作执行后立即执行回调,不受事件循环阶段限制,但需谨慎使用以防阻塞事件循环。
浅析linux 内核 高精度定时器(hrtimer)实现机制(二)
分析linux内核高精度定时器(hrtimer)的实现机制时,首先介绍的是定时器的迁移过程switch_hrtimer_base。该函数会尝试选择一个新的hrtimer_cpu_base结构体,用于定时器的激活。get_target_base函数被用于挑选新的迁移位置,这个函数的代码与分析低分辨率定时器层时的定时器迁移概念相似。timers_migration_enabled变量在切换到NO_HZ模式时变为True,退出NO_HZ模式时变为False,用于判断是否可以进行迁移。只有在切换到NO_HZ模式且定时器未绑定到特定CPU的情况下,才会进行迁移选择。get_nohz_timer_target函数会判断当前CPU是否处于空闲状态,如果不是,则返回当前CPU编号,如果是空闲,则会找到最近一个忙碌的处理器并返回其编号。所有条件不满足时,会直接返回传入的hrtimer_cpu_base结构体指针。
接下来分析hrtimer_callback_running函数,用于检查要迁移的定时器是否正是当前正在处理的定时器。hrtimer_check_target函数则用于检查定时器的到期时间是否早于要迁移到的CPU上即将到期的时间。如果高分辨率定时器的到期时间比目标CPU上的所有定时器到期时间还要早,并且目标CPU不是当前CPU,那么激活目标CPU会涉及到通知该CPU重新编程定时器,这通常不如直接在当前CPU上激活定时器来得简单。因此,如果迁移操作与实际激活操作没有关系,即使从get_target_base函数获得的base与定时器中指定的base相同,迁移操作也会进行。
在迁移过程中,内核会临时将定时器的hrtimer_clock_base结构体变量设置为全局变量migration_base的指针。这个全局变量仅用于在获得定时器所属CPU的hrtimer_cpu_base结构体变量时,通过判断base变量是否等于migration_base的指针来判断定时器是否正在迁移。这样的设计可以在未正式加锁之前过滤掉很多情况,从而提高速度。
文章福利提供Linux内核技术交流群,包含学习书籍、视频资料,前名可额外获得价值的内核资料包(含视频教程、电子书、实战项目及代码)。
内核资料直通车:Linux内核源码技术学习路线+视频教程代码资料
学习直通车:Linux内核源码/内存调优/文件系统/进程管理/设备驱动/网络协议栈-学习视频教程-腾讯课堂
在低精度模式下,高分辨率定时器层通过普通(低分辨率)定时器层驱动。当Tick到来时,其处理函数会调用hrtimer_run_queues函数通知高分辨率定时器层。每次调用该函数时,都会判断是否可以切换到高精度模式。如果可以切换,会调用hrtimer_switch_to_hres完成切换并退出。如果不需要切换,则从时间维护层获得当前时间和各种偏移值,并设置到所有的hrtimer_clock_base结构体中。如果当前时间不早于softirq_expires_next变量的值,表示“软”定时器已到期,需要激活软中断处理程序。在软中断处理程序中,首先调用hrtimer_update_base函数更新当前时间,并在适当时候执行,处理到期的“软”定时器。该处理程序会遍历所有指定类型(“软”或“硬”)的到期定时器,判断定时器的“软”到期时间是否已到,处理到期定时器,并循环取下一个要到期的定时器。最后,会调用hrtimer_reprogram函数对底层定时事件设备进行重编程。
在高精度模式下,周期处理函数hrtimer_interrupt在定时事件设备到期后调用。处理过程包括激活HRTIMER_SOFTIRQ软中断处理程序,处理所有“软”定时器,并对底层定时事件设备进行重编程。重编程确保设备在到期后能正确触发中断,同时避免在一次中断中处理过多定时器,以防止超时。通过查找和设置到期时间时使用“硬”到期时间,而在处理定时器时使用“软”到期时间,内核能尽量减少中断调用,提高性能。
低精度模式切换到高精度模式的hrtimer_switch_to_hres函数通过调用tick_init_highres函数实现切换,将定时事件设备切换到单次触发模式,并设置中断处理函数为hrtimer_interrupt。一旦完成切换,底层定时事件设备将始终工作在单次触发模式。切换成功后,必须找到最近到期的定时器,并用其到期事件对定时事件设备进行重编程,确保设备能正确响应到期。
在高精度模式下,中断处理程序通过直接调用__hrtimer_run_queues函数处理所有“硬”定时器,并激活HRTIMER_SOFTIRQ软中断处理程序来处理所有“软”定时器。在高精度模式下,底层定时事件设备始终处于单次触发模式,因此在到期后必须进行重编程。如果编程失败,重试三次后,适当延迟到期事件后再次尝试编程,并强制执行。
使用实例展示了高精度定时器在实际应用中的精度,时间戳显示其定时精度可达到ms级别。
iowait 到底是什么?
在理解Linux中的CPU使用率时,iowait是经常被提及的一个指标。本文旨在探究iowait的定义、计算方式以及它在系统分析中的应用。通常,当iowait值较高时,人们会直观地认为系统可能遇到了IO瓶颈。然而,深入研究后,我们发现iowait实际上是CPU处于等待I/O操作完成的状态时间。这一定义可能并不直观,但通过查阅系统手册,我们找到了更详细的解释。
iowait的来源可以从系统状态文件中寻得线索,如/proc/stat。通过阅读proc手册,我们了解到各列的定义,从而清晰地理解iowait的计算方式。进一步地,通过反向追踪Linux内核的实现,我们发现iowait状态的记录实际上是基于空闲CPU时间与I/O任务的结合。这种记录方式表明,当CPU处于iowait状态时,仍可能被调度执行其他进程,这与直观理解可能有所不同。
为了验证上述分析,我们以Linux内核版本v6.5.1为例,通过系统文件和内核源码进行了深入研究。在stat系统文件中,我们发现了实现细节,如get_iowait_time的调用。在tick_sched计时结构体中,我们找到了iowait时间的计算方法。通过判断CPU调度器runqueue信息,我们得知当idle_sleeptime和iowait_sleeptime被计算时,意味着CPU核心在空闲状态下可能处于iowait状态。
通过实验,我们尝试让系统中的iowait值接近%,并通过启动多个重度IO任务来实现。在该实验中,我们使用了一块机械硬盘作为测试对象,成功地使系统iowait达到了%,而idle状态基本不存在。尽管如此,系统响应并未感受到卡顿,这表明高iowait值实际上意味着系统中有大量CPU空闲时间等待IO操作完成。这一发现提示我们,iowait值高并不一定意味着系统不健康,而是可能表明系统具备处理额外计算密集型任务的能力,或者提示我们优化高iowait的应用程序。
进一步的实验显示,即使在引入计算密集型任务后,系统的iowait值并未显著增加,而主要集中在计算密集型任务上。这进一步表明了在分析系统IO压力时,需要综合考虑多种指标,如iostat和iotop,以全面评估系统的性能状况。通过结合这些工具的使用,我们可以更准确地判断系统是否存在IO瓶颈,而不仅仅是依赖于单一的iowait值。
综上所述,理解iowait的含义和其在系统分析中的应用,需要从多个角度出发。通过深入研究内核源码和系统状态文件,以及实际实验验证,我们可以更准确地判断系统性能,避免因单一指标的解读偏差导致的误解。在实际排查IO瓶颈时,综合使用多种工具和方法,将有助于我们更全面、准确地评估系统的运行状况,从而进行有效的性能优化。