팁 :이 문서는 (결국, 나도 몰라) 자체 검사 내용, 부동 소수점 레지스터와 관련된 내용을 설명하지 않습니다
스케줄러의 기본 개념
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
중간 벡터 테이블의 개시 어드레스를 저장 한 어드레스 레지스터.0xE000ED08
SCB_VTOR
로드 k_next_task
태스크 제어 블록 가리키는 R2
태스크 제어 블록의 제 1 기지 부재이 경우, 이전 기사의 스택 포인터를 R2
상기 스택 포인터 같다.
PS : 상기 스케줄러가 시작될 때
k_next_task
와k_curr_task
동일하다 (k_curr_task = k_next_task
)
로드 R2
에 R0
다음 스택 포인터, R0
업데이트 psp
작업 실행이 때 스택 포인터가 사용된다 psp
.
: PS
sp
각각 두 포인터,psp
및msp
. (간단하게 이해 될 수있다 : 선교 상황에서 사용psp
, 인터럽트 컨텍스트의 사용은msp
반드시 정확하지, 이건 내 개인적인 이해입니다)
에서 R0
기본 주소, 스택은 위쪽으로 성장 8
CPU의 내용을로드 단어를 등록 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的位24
CPU가됩니다自动
로드 및 저장.- 의 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 공통 방법은 준비리스트에있어서, 사용하는
k_rdyq.prio_mask[]
대응 비트가 가변 설정되어 있는지 여부를 판정한다. - 두 번째 방법은 상기 계산 된 선행 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
레지스터 뱅크. 매뉴얼을로드 한 후, 이번에는 R0
PSP의 출구의 업데이트 된 값, 업데이트 된 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 tiny
윌 cpu_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 개발을"기쁘게 대중 번호!