[TencentOS 작은 소스 깊이 분석 (2) - 스케줄러

팁 :이 문서는 (결국, 나도 몰라) 자체 검사 내용, 부동 소수점 레지스터와 관련된 내용을 설명하지 않습니다

스케줄러의 기본 개념

TencentOS tiny그것은 시스템이 작업을 즉시 현재 작업의 현재 작업 우선 순위보다 더 많은 준비가있을 때, 실행, 작업 스케줄러가 전체 우선 순위 기반 선점 스케줄링입니다 제공 切出, 우선 순위가 높은 작업 抢占프로세서가 실행 중입니다.

TencentOS tiny커널은 또한이 같은 우선 순위의 태스크를 만들 수 있습니다. (종종 시분할 스케줄링 말한다) 같은 라운드 로빈 스케줄링 모드를 사용하여 우선 순위 작업, 라운드 로빈 스케줄링은 현재의 시스템입니다 더 높은 우선 순위 준비 작업 의 경우에 효과.

실시간 시스템을 보장하기 위해 가능한 시스템 최대 범위는 실행 우선 순위가 높은 작업을 보장합니다. 작업 상태가 변경되면 원리 작업 스케줄링이며, 현재 실행중인 작업 우선 순위가 가장 높은 우선 순위가 즉시 전환 작업 큐에서 우선 순위의 작업보다 작은 (현재의 시스템 상태 인터럽트 핸들러 또는 비활성화 작업 스위치가 아닌 경우) .

스케줄러는 운영 시스템 核心의 주요 기능은, 实现任务的切换준비 목록에있는 것을 找到가장 우선 순위가 높은 작업이 다음에 가서 执行작업.

시작 스케줄러

스케줄러에 의해 시작 cpu_sched_start기능을 완료하는 데,됩니다 tos_knl_start주로에 의해 첫 번째, 두 가지 작업을 수행 기능을 호출 readyqueue_highest_ready_task_get현재 작업 제어 블록을 가리 키도록 우선 순위가 가장 높은 준비 작업에서 현재의 시스템 기능을 획득하고 할당을 포인터 k_curr_task, 시스템의 상태가 작동 모드에 관한 설정 KNL_STATE_RUNNING.

물론, 가장 중요한 것은 어셈블리 코드로 작성된 함수를 호출하는 것입니다 cpu_sched_start스케줄러, 소스에서 함수 시작 arch\arm\arm-v7m디렉토리 port_s.S어셈블리 파일, 아래에 TencentOS tiny여러 개의 코어 칩에 대한 지원 M3/M4/M7, 기능 서로 다른 칩을 달성하기 위해 다른 여러 가지 방법 port_s.S뿐만 아니라 TencentOS tiny소프트웨어로 하드웨어는 CPU와 접속 桥梁. M4는 것입니다 cpu_sched_start예를 제공합니다 :

__API__ k_err_t tos_knl_start(void)
{
    if (tos_knl_is_running()) {
        return K_ERR_KNL_RUNNING;
    }

    k_next_task = readyqueue_highest_ready_task_get();
    k_curr_task = k_next_task;
    k_knl_state = KNL_STATE_RUNNING;
    cpu_sched_start();

    return K_ERR_NONE;
}
port_sched_start
    CPSID   I   

    ; set pendsv priority lowest
    ; otherwise trigger pendsv in port_irq_context_switch will cause a context swich in irq
    ; that would be a disaster
    MOV32   R0, NVIC_SYSPRI14
    MOV32   R1, NVIC_PENDSV_PRI
    STRB    R1, [R0]

    LDR     R0, =SCB_VTOR
    LDR     R0, [R0]
    LDR     R0, [R0]
    MSR     MSP, R0

    ; k_curr_task = k_next_task
    MOV32   R0, k_curr_task
    MOV32   R1, k_next_task
    LDR     R2, [R1]
    STR     R2, [R0]

    ; sp = k_next_task->sp
    LDR     R0, [R2]
    ; PSP = sp
    MSR     PSP, R0

    ; using PSP
    MRS     R0, CONTROL
    ORR     R0, R0, #2
    MSR     CONTROL, R0

    ISB

    ; restore r4-11 from new process stack
    LDMFD   SP!, {R4 - R11}

    IF {FPU} != "SoftVFP"
    ; ignore EXC_RETURN the first switch
    LDMFD   SP!, {R0}
    ENDIF

    ; restore r0, r3
    LDMFD    SP!, {R0 - R3}
    ; load R12 and LR
    LDMFD    SP!, {R12, LR}
    ; load PC and discard xPSR
    LDMFD    SP!, {R1, R2}

    CPSIE    I
    BX       R1

인터럽트 명령 해제 텍스-M 코어

위의 어셈블리 코드에서, 내가 소개하고 싶은 Cortex-M, 해제 명령 인터럽트 커널을 아아 ~ 약간의 문제를 느낌!
신속히 인터럽트 텍스 M 구체적 코어 설정 스위치에 CPS 指令조작을위한 PRIMASK등록을 FAULTMASK레지스터 두 레지스터 이외에과 연관된 마스크 가능 인터럽트되어 Cortex-M코어가 BASEPRI이 또한도 인터럽트와 관련된 레지스터 그것에 대해 알려주십시오.

CPSID I     ;PRIMASK=1     ;关中断
CPSIE I     ;PRIMASK=0     ;开中断
CPSID F     ;FAULTMASK=1   ;关异常
CPSIE F     ;FAULTMASK=0   ;开异常
회원 가입 기능
PRIMASK 이 설정 한 후 1 만 응답 NMI와 하드 폴트 FAULT에서 모든 마스크 가능 예외를 해제
FAULTMASK 1로 설정 한 경우에만 NMI는, 다른 모든 예외 (하드 폴트 FAULT 포함)에 응답 할 수 없습니다 수 있습니다
BASEPRI 이것은 구 (우선 순위 결정을 표현하는 비트의 개수)를 등록. 그것은 우선 순위 마스크 임계 값을 정의합니다. 이 값으로 설정되면, 우선이 인터럽트 이상인 모든 숫자 값 (더 큰 우선 순위 번호, 낮은 우선 순위) 턴온된다. 0으로 설정되어있는 경우, 어떤 인터럽트는 해제하지됩니다

더 자세한 설명을 내 이전 문서를 참조하십시오 지식의 RTOS 중요한 부분을 : HTTPS : //blog.csdn.net/jiejiemcu/article/details/82534974

주제로 돌아 가기

프로세스를 시작하는 커널 스케줄러에서는 구성해야 PendSV하는, 즉, 인터럽트 우선 순위가 가장 낮은 NVIC_SYSPRI14(0xE000ED22)주소를 쓰기 NVIC_PENDSV_PRI(0xFF). 왜냐하면 PendSV에 시스템 스케줄링 시스템 스케줄링 우선 순위를 포함 할 것이다 低于하는 PendSV 우선 인터럽트되도록 다른 하드웨어 시스템 인터럽트 우선, 외부 하드웨어 인터럽트의 우선 순위 응답 시스템을 최소 구성하거나 인터럽트의 생성 상황에서 예상되는 작업 스케줄링.

PendSV다른 때까지 이상 컨텍스트 스위치가 자동으로 요청을 지연시킬 ISR출시 된 이후 처리를 완료했습니다. 이 메커니즘을 달성하기 위해, 우리는해야 할 PendSV우선 순위가 가장 낮은 예외로 프로그래밍 될 수있다. 경우에 OS검출 ISR되는 활성을, 그것은 매달려 PendSV현탁 문맥 전환을 수행하기 위해, 예외. 즉,만큼으로 PendSV가장 낮은 우선 순위, systick도 IRQ 중단, 즉시 컨텍스트 스위치를 수 있지만 때까지 기다리지 않습니다 ISR실행, PendSV서비스 루틴을 수행하고, 내부에 컨텍스트 스위치를 수행하기 시작했다 . 도 절차와 같이

다음 수득 MSP에서 기본 스택 포인터의 주소를 Cortex-M중간 벡터 테이블의 개시 어드레스를 저장 한 어드레스 레지스터.0xE000ED08SCB_VTOR

로드 k_next_task태스크 제어 블록 가리키는 R2태스크 제어 블록의 제 1 기지 부재이 경우, 이전 기사의 스택 포인터를 R2상기 스택 포인터 같다.

PS : 상기 스케줄러가 시작될 때 k_next_taskk_curr_task동일하다 ( k_curr_task = k_next_task)

로드 R2R0다음 스택 포인터, R0업데이트 psp작업 실행이 때 스택 포인터가 사용된다 psp.

: PS sp각각 두 포인터, pspmsp. (간단하게 이해 될 수있다 : 선교 상황에서 사용 psp, 인터럽트 컨텍스트의 사용은 msp반드시 정확하지, 이건 내 개인적인 이해입니다)

에서 R0기본 주소, 스택은 위쪽으로 성장 8CPU의 내용을로드 단어를 등록 R4~R11하면서, R0자기 활력을 따릅니다

그런 다음로드 할 필요 R0 ~ R3、R12以及LR、 PC、xPSR는 CPU 레지스터 세트에 LR이 작업에 출구 지점을 등록하면서, PC 스레드에 대한 포인터, 실행하려고이다. 因为这是第一次启动任务,要全部手动把任务栈上的寄存器弹到硬件里,才能进入第一个任务的上下文,因为一开始并没有第一个任务运行的上下文环境,而在进入PendSV的时候需要上文保存,所以需要手动创造任务上下文环境(将这些寄存器加载到CPU寄存器组中)엔트리 기능, SP가 작업 지점의 스택의 상단이 선택한 (이다 먼저 어셈블러 k_curr_task).

작업 스택 초기화를 살펴 보자

위의 이해에서, 스택 초기화 작업을보고, 좀 더 깊이 인상이있을 수 있습니다. 주로 다음과 같은 점을 이해합니다 :

  • 스택 포인터를 가져옵니다 stk_base[stk_size]높은 주소를 Cortex-M커널 스택이다 向下增长에.
  • R0、R1、R2、R3、R12、R14、R15和xPSR的位24CPU가됩니다 自动로드 및 저장.
  • 의 xPSR bit24必须置1그 0x01000000.
  • 항목은 항목 즉, 작업을 처리한다PC
  • R14는 ( LR) 출구가 작업을 해결하는, 그래서 작업은하지 않고 일반적으로 무한 루프입니다return
  • R0는 : ARG 매개 변수는 주요 작업입니다
  • 스택 포인터 SP 초기화는 감소한다
__KERNEL__ k_stack_t *cpu_task_stk_init(void *entry,
                                              void *arg,
                                              void *exit,
                                              k_stack_t *stk_base,
                                              size_t stk_size)
{
    cpu_data_t *sp;

    sp = (cpu_data_t *)&stk_base[stk_size];
    sp = (cpu_data_t *)((cpu_addr_t)(sp) & 0xFFFFFFF8);

    /* auto-saved on exception(pendSV) by hardware */
    *--sp = (cpu_data_t)0x01000000u;    /* xPSR     */
    *--sp = (cpu_data_t)entry;          /* entry    */
    *--sp = (cpu_data_t)exit;           /* R14 (LR) */
    *--sp = (cpu_data_t)0x12121212u;    /* R12      */
    *--sp = (cpu_data_t)0x03030303u;    /* R3       */
    *--sp = (cpu_data_t)0x02020202u;    /* R2       */
    *--sp = (cpu_data_t)0x01010101u;    /* R1       */
    *--sp = (cpu_data_t)arg;            /* R0: arg  */

    /* Remaining registers saved on process stack */
    /* EXC_RETURN = 0xFFFFFFFDL
       Initial state: Thread mode +  non-floating-point state + PSP
       31 - 28 : EXC_RETURN flag, 0xF
       27 -  5 : reserved, 0xFFFFFE
       4       : 1, basic stack frame; 0, extended stack frame
       3       : 1, return to Thread mode; 0, return to Handler mode
       2       : 1, return to PSP; 0, return to MSP
       1       : reserved, 0
       0       : reserved, 1
     */
#if defined (TOS_CFG_CPU_ARM_FPU_EN) && (TOS_CFG_CPU_ARM_FPU_EN == 1U)
    *--sp = (cpu_data_t)0xFFFFFFFDL;
#endif

    *--sp = (cpu_data_t)0x11111111u;    /* R11      */
    *--sp = (cpu_data_t)0x10101010u;    /* R10      */
    *--sp = (cpu_data_t)0x09090909u;    /* R9       */
    *--sp = (cpu_data_t)0x08080808u;    /* R8       */
    *--sp = (cpu_data_t)0x07070707u;    /* R7       */
    *--sp = (cpu_data_t)0x06060606u;    /* R6       */
    *--sp = (cpu_data_t)0x05050505u;    /* R5       */
    *--sp = (cpu_data_t)0x04040404u;    /* R4       */

    return (k_stack_t *)sp;
}

가장 높은 우선 순위의 작업을 찾기

하나의 운영 체제가 우선 순위가 높은 작업을 할 수있는 경우 立即프로세서를 얻고 구현의 특성, 그것은 여전히 실시간 운영 시스템이 아니다. 이 우선 순위가 가장 높은 작업 스케줄링 프로세스는 시간이 결정적인지 여부를 결정 발견의 때문에, 간단하게 사용할 수있는 时间复杂度시스템이 시간의 우선 순위가 가장 높은 작업을 발견하면, 그것을 설명하기 위해 O(N), 그래서 이번에는 작업의 수에 따라 달라집니다 바람직하지 않은, 증가 증가, TencentOS tiny시간 복잡도는 O(1)로는 가장 높은 우선 순위의 작업을 찾을 수있는 두 가지 방법을 제공하는 TOS_CFG_CPU_LEAD_ZEROS_ASM_PRESENT정의 매크로를 결정합니다.

  1. 제 1 공통 방법은 준비리스트에있어서, 사용하는 k_rdyq.prio_mask[]대응 비트가 가변 설정되어 있는지 여부를 판정한다.
  2. 두 번째 방법은 상기 계산 된 선행 0 지침을 사용하여, 특별한 방법 CLZ으로 직접 직접 변수,이 방법은 종래의 방법보다 효율적으로하는 우선 순위가 가장 높은 비트 그린 위치 (영으로 지침을 선도에서, 하드웨어가 필요 STM32, 우리는)이 방법을 사용할 수 있습니다.k_rdyq.prio_mask[]32但受限于平台

구현 프로세스는이 참조하는 것이 좋습니다, 다음 readyqueue_prio_highest_get~ 자신의 실현은 여전히 매우 섬세 함수를

__STATIC__ k_prio_t readyqueue_prio_highest_get(void)
{
    uint32_t *tbl;
    k_prio_t prio;

    prio    = 0;
    tbl     = &k_rdyq.prio_mask[0];

    while (*tbl == 0) {
        prio += K_PRIO_TBL_SLOT_SIZE;
        ++tbl;
    }
    prio += tos_cpu_clz(*tbl);
    return prio;
}
__API__ uint32_t tos_cpu_clz(uint32_t val)
{
#if defined(TOS_CFG_CPU_LEAD_ZEROS_ASM_PRESENT) && (TOS_CFG_CPU_LEAD_ZEROS_ASM_PRESENT == 0u)
    uint32_t nbr_lead_zeros = 0;

    if (!(val & 0XFFFF0000)) {
        val <<= 16;
        nbr_lead_zeros += 16;
    }

    if (!(val & 0XFF000000)) {
        val <<= 8;
        nbr_lead_zeros += 8;
    }

    if (!(val & 0XF0000000)) {
        val <<= 4;
        nbr_lead_zeros += 4;
    }

    if (!(val & 0XC0000000)) {
        val <<= 2;
        nbr_lead_zeros += 2;
    }

    if (!(val & 0X80000000)) {
        nbr_lead_zeros += 1;
    }

    if (!val) {
        nbr_lead_zeros += 1;
    }

    return (nbr_lead_zeros);
#else
    return port_clz(val);
#endif
}

작업 전환의 실현

우리는 또한 전면 알고, 작업 전환이되어 PendSV인터럽트에서 수행, 인터럽트가 단어의 콘텐츠 본질의 요약으로 구현은 , 아래의 전환을 막아 위의 소스 코드를 직접 살펴 :

PendSV_Handler
    CPSID   I
    MRS     R0, PSP

_context_save
    ; R0-R3, R12, LR, PC, xPSR is saved automatically here
    IF {FPU} != "SoftVFP"
    ; is it extended frame?
    TST     LR, #0x10
    IT      EQ
    VSTMDBEQ  R0!, {S16 - S31}
    ; S0 - S16, FPSCR saved automatically here

    ; save EXC_RETURN
    STMFD   R0!, {LR}
    ENDIF

    ; save remaining regs r4-11 on process stack
    STMFD   R0!, {R4 - R11}

    ; k_curr_task->sp = PSP
    MOV32   R5, k_curr_task
    LDR     R6, [R5]
    ; R0 is SP of process being switched out
    STR     R0, [R6]

_context_restore
    ; k_curr_task = k_next_task
    MOV32   R1, k_next_task
    LDR     R2, [R1]
    STR     R2, [R5]

    ; R0 = k_next_task->sp
    LDR     R0, [R2]

    ; restore R4 - R11
    LDMFD   R0!, {R4 - R11}

    IF {FPU} != "SoftVFP"
    ; restore EXC_RETURN
    LDMFD   R0!, {LR}
    ; is it extended frame?
    TST     LR, #0x10
    IT      EQ
    VLDMIAEQ    R0!, {S16 - S31}
    ENDIF

    ; Load PSP with new process SP
    MSR     PSP, R0
    CPSIE   I
    ; R0-R3, R12, LR, PC, xPSR restored automatically here
    ; S0 - S16, FPSCR restored automatically here if FPCA = 1
    BX      LR

    ALIGN
    END

PSP값 저장 R0. 입력 할 때 PendSVC_Handler입니다 작업의 운영 환경 : xPSR,PC(任务入口地址),R14,R12,R3,R2,R1,R0는 CPU 레지스터가됩니다 自动포인터가 자동으로 PSP의 업데이트 된 경우 작업 스택에 저장됩니다. 나머지는 동안 r4~r11필요로 手动저장하고, 당신이하고 싶은 이유이다 PendSVC_Handler(위의 저장 _context_save자동으로 작업 스택에 누를 저장된 CPU 레지스터를로드하지 않는 주요 이유).

그런 다음 실행하는 작업을 찾을 수 k_next_task가 작업의 스택에로드, R0새 작업 후 수동으로 내용을 (여기에서 의미 스택 R4~R11)을에로드 CPU레지스터 세트, 이것은 물론, 다른이 아닌, 상황에 맞는 스위치입니다 방법의 내용은 자동으로 수동으로로드 저장됩니다 CPU레지스터 뱅크. 매뉴얼을로드 한 후, 이번에는 R0PSP의 출구의 업데이트 된 값, 업데이트 된 PendSVC_Handler인터럽트가 될 것이다 psp작업은 콘텐츠의 나머지 부분 (스택, 기본 주소로 사용 xPSR,PC(任务入口地址),R14,R12,R3,R2,R1,R0) 자동으로 CPU 레지스터로로드됩니다.

예외가 발생하는 경우 실제로, R14가 작업 모드 또는 프로세서 모드로 진입 후, 새 창을 포함한 비정상 복귀 플래그 저장된 상기 MSP PSP는 포인터를 스택 포인터 또는 스택 사용. 이때 R14 0xFFFFFFFD 다시 비정상 모드로 후방 가장 태스크 (이후 동일 PendSVC_Handler스택에 스택 포인터를 완료 한 후, 스택과 같은 우선 순위가 가장 낮은 태스크에 반환), SP PSP PSP스택 작업의 정상 점. 호출 명령어 BX R14, 시스템 때 PSP와 같은 SP다음 실행할 수있는 새로운 작업에 작업을 스택 스택 포인터는, CPU 레지스터의 나머지 내용에로드 : R0、R1、R2、R3、R12、R14(LR)、R15(PC)和xPSR새로운 태스크로 전환합니다.

SysTick

SysTick 초기화

systick는 시스템을 기반으로하며 그만큼, 코어 클록하다 M0/M3/M4/M7가 제시 될 코어 systick클록을, 그것은 운영 체제 마이그레이션 큰 편의를 제공하는 구성되도록 프로그램된다.
TencentOS tinycpu_init기능에 systick즉, 그것은 호출, 초기화 cpu_systick_init사용자 - 쓸 필요가 없다 이런 식으로 함수를 systick초기화 관련 코드.

__KERNEL__ void cpu_init(void)
{
    k_cpu_cycle_per_tick = TOS_CFG_CPU_CLOCK / k_cpu_tick_per_second;
    cpu_systick_init(k_cpu_cycle_per_tick);

#if (TOS_CFG_CPU_HRTIMER_EN > 0)
    tos_cpu_hrtimer_init();
#endif
}
__KERNEL__ void cpu_systick_init(k_cycle_t cycle_per_tick)
{
    port_systick_priority_set(TOS_CFG_CPU_SYSTICK_PRIO);
    port_systick_config(cycle_per_tick);
}

SysTick 인터럽트

SysTick인터럽트 서비스 기능은 봐 내에서 호출 할 수있는, 우리 자신을 작성할 필요가이다 TencentOS tiny의 기능과 관련된베이스를 실행하는 시스템을 업데이트, 드라이브 시스템 SysTick_Handler다음과 같다 이식 기능 :

void SysTick_Handler(void)
{
  HAL_IncTick();
  if (tos_knl_is_running())
  {
    tos_knl_irq_enter();
    
    tos_tick_handler();
    
    tos_knl_irq_leave();
  }
}

주로 필요가 호출 tos_tick_handler기본 시스템 업데이트, 특정 페이지의 기능 :

__API__ void tos_tick_handler(void)
{
    if (unlikely(!tos_knl_is_running())) {
        return;
    }

    tick_update((k_tick_t)1u);

#if TOS_CFG_TIMER_EN > 0u && TOS_CFG_TIMER_AS_PROC > 0u
    timer_update();
#endif

#if TOS_CFG_ROUND_ROBIN_EN > 0u
    robin_sched(k_curr_task->prio);
#endif
}

'라고해야 TencentOS tiny소스 코드의 구현은 매우 간단 我非常喜欢에서, tos_tick_handler첫째, 시스템이 실행 한 경우 직접 반환 실행하지 않을 경우, 다음 호출, 실행 된 결정 tick_update, 기본 시스템을 업데이트 기능을 사용할 경우 TOS_CFG_TIMER_EN매크로 표현 소프트웨어 타이머를 사용, 당신은 여기에 언급하지 당분간, 적절한 치료를 업데이트해야합니다. 당신이 사용하는 경우 TOS_CFG_ROUND_ROBIN_EN또한 관련 타임 슬라이스 변수를 업데이트해야, 매크로, 나중에 설명합니다.

__KERNEL__ void tick_update(k_tick_t tick)
{
    TOS_CPU_CPSR_ALLOC();
    k_task_t *first, *task;
    k_list_t *curr, *next;

    TOS_CPU_INT_DISABLE();
    k_tick_count += tick;

    if (tos_list_empty(&k_tick_list)) {
        TOS_CPU_INT_ENABLE();
        return;
    }

    first = TOS_LIST_FIRST_ENTRY(&k_tick_list, k_task_t, tick_list);
    if (first->tick_expires <= tick) {
        first->tick_expires = (k_tick_t)0u;
    } else {
        first->tick_expires -= tick;
        TOS_CPU_INT_ENABLE();
        return;
    }

    TOS_LIST_FOR_EACH_SAFE(curr, next, &k_tick_list) {
        task = TOS_LIST_ENTRY(curr, k_task_t, tick_list);
        if (task->tick_expires > (k_tick_t)0u) {
            break;
        }

        // we are pending on something, but tick's up, no longer waitting
        pend_task_wakeup(task, PEND_STATE_TIMEOUT);
    }

    TOS_CPU_INT_ENABLE();
}

tick_update주요 기능은 기능을하는 것입니다 k_tick_count +1, 그리고 스스로 판단 할 때 기본 목록 k_tick_list여부를 작업 시간 초과가 다음 작업을 깨워 경우, 제한 시간 (그것은 또한 지연 목록 일 수 있습니다), 그렇지 않으면 직접 종료합니다. 시트의 시간표는 작업 시간 슬라이스 나머지 변수가 매우 간단 timeslice감소하고, 변수가 0이라면, 가변 웨이트로드로 감소되는 경우 timeslice_reload, 스위칭 작업 knl_sched()은 다음과 같다 과정 :

__KERNEL__ void robin_sched(k_prio_t prio)
{
    TOS_CPU_CPSR_ALLOC();
    k_task_t *task;

    if (k_robin_state != TOS_ROBIN_STATE_ENABLED) {
        return;
    }

    TOS_CPU_INT_DISABLE();

    task = readyqueue_first_task_get(prio);
    if (!task || knl_is_idle(task)) {
        TOS_CPU_INT_ENABLE();
        return;
    }

    if (readyqueue_is_prio_onlyone(prio)) {
        TOS_CPU_INT_ENABLE();
        return;
    }

    if (knl_is_sched_locked()) {
        TOS_CPU_INT_ENABLE();
        return;
    }

    if (task->timeslice > (k_timeslice_t)0u) {
        --task->timeslice;
    }

    if (task->timeslice > (k_timeslice_t)0u) {
        TOS_CPU_INT_ENABLE();
        return;
    }

    readyqueue_move_head_to_tail(k_curr_task->prio);

    task = readyqueue_first_task_get(prio);
    if (task->timeslice_reload == (k_timeslice_t)0u) {
        task->timeslice = k_robin_default_timeslice;
    } else {
        task->timeslice = task->timeslice_reload;
    }

    TOS_CPU_INT_ENABLE();
    knl_sched();
}

나는 그것에 집중하고!

나는 대중의 관심 호를 환영합니다

관련 코드 번호는 공공 백그라운드에서 얻을 수있다.
자세한 내용은 우려 "것들의 IoT 개발을"기쁘게 대중 번호!

추천

출처www.cnblogs.com/iot-dev/p/11688906.html