Nota: Basado en el análisis de oscuridad del núcleo de código abierto, la fuente oficial [ kernel_liteos_a ] documentos oficiales [ docs ] Documento de referencia [ Huawei LiteOS ]
autor: entusiastas del núcleo de Hong Meng, continuará estudiando el núcleo de oscuridad, actualizará el blog, así que estad atentos. El contenido solo representa opiniones personales, los errores son bienvenidos, todos pueden corregir y mejorar. Ver todos los artículos de esta serie en el análisis del código fuente del sistema de oscuridad (Lista)
Este artículo analiza el código fuente de la gestión de tareas / subprocesos en detalle: los_task.c
Tabla de contenido
1. ¿Cómo describe el documento oficial los hilos?
2. Ejecute el comando de tarea
En segundo lugar, cómo administrar la tarea
1. ¿Qué es un grupo de tareas?
2. ¿Qué pasa con la cola lista?
3. ¿Qué pasa con la pila de tareas?
4. Inicialización de la pila de tareas
Tres, conjunto de funciones de tareas
1. Escenarios de uso y funciones
2. El proceso de creación de tareas
3. ¿Cuáles son los contenidos importantes de la parte Task / Thread que no se han mencionado?
Prefacio
En el kernel de Hongmeng, una tarea puede entenderse como un hilo en un sentido amplio
1. Cómo entender la tarea
1. ¿Cómo describe el documento oficial los hilos?
Conceptos básicos
Desde la perspectiva del sistema, un hilo es la unidad de operación más pequeña que compite por los recursos del sistema. Los subprocesos pueden usar o esperar recursos del sistema, como CPU y espacio de memoria, y ejecutarse independientemente de otros subprocesos.
Los subprocesos en cada proceso de Hongmeng Kernel se ejecutan de forma independiente y se programan de forma independiente, y la programación de subprocesos en el proceso actual no se ve afectada por otros subprocesos en el proceso.
Los subprocesos en el kernel de Hongmeng adoptan un mecanismo de programación preventiva y admiten la programación por turnos por intervalos de tiempo y la programación FIFO.
Los subprocesos del kernel de Hongmeng tienen un total de 32 prioridades (0-31), la prioridad más alta es 0 y la prioridad más baja es 31.
El subproceso de alta prioridad en el proceso actual puede adelantarse al subproceso de baja prioridad en el proceso actual, y el subproceso de baja prioridad en el proceso actual solo se puede programar después de que el subproceso de alta prioridad en el proceso actual se bloquee o finalice.
Descripción del estado del hilo:
Inicialización (Init): se está creando el hilo.
Listo (Listo): el hilo está en la lista de listos, esperando la programación de la CPU.
En ejecución: el hilo se está ejecutando.
Bloqueado: el hilo está bloqueado y suspendido. Los estados bloqueados incluyen: pendiente (debido a bloqueos, eventos, semáforos, etc.), suspensión (pendiente activo), retraso (bloqueo retrasado), tiempo de espera (debido a bloqueos, eventos, tiempo de semáforo, etc. espera de tiempo extra).
Exit (Exit): el hilo finaliza, esperando que el hilo principal recupere sus recursos de bloque de control.
Figura 1 Diagrama esquemático de la migración del estado de subprocesos.
Tenga en cuenta que el documento oficial habla de subprocesos y no menciona tareas. Sin embargo, hay muchos códigos de tareas en el código fuente del kernel y muy pocos códigos de subprocesos. ¿Qué está pasando?
De hecho, en el kernel de Hongmeng, las tareas son subprocesos. Los principiantes pueden entenderlo de esta manera, pero todavía hay diferencias entre los dos. De lo contrario, ¿por qué deberían describirse en dos palabras?
¿Cuál es la diferencia? Es la diferencia en la gestión, la tarea es el concepto de nivel de programación y el hilo es el concepto de nivel de proceso. Así como la misma persona tiene diferentes identidades en diferentes sistemas de gestión, un hombre puede ser un niño, un padre, un esposo o un programador, con diferentes perspectivas y funciones.
Cómo demostrarlo es una cosa, sigue mirando hacia abajo.
2. Ejecute el comando de tarea
El resultado de la ejecución del comando de tarea Hongmeng:
El comando de tarea descubre el estado de ejecución de cada tarea en el ciclo de vida, su espacio de memoria en ejecución, prioridad, intervalo de tiempo, función de ejecución de entrada, ID de proceso, estado y otra información, lo cual es muy complicado. Esta información compleja necesita una estructura para ser transportada. Y esta estructura es LosTaskCB (bloque de control de tareas)
3. ¿Cómo se ve la tarea?
Antes de hablar de LosTaskCB, hablemos de la definición correspondiente al estado de la tarea del documento oficial, se puede ver que la tarea y el hilo son lo mismo.
#define OS_TASK_STATUS_INIT 0x0001U
#define OS_TASK_STATUS_READY 0x0002U
#define OS_TASK_STATUS_RUNNING 0x0004U
#define OS_TASK_STATUS_SUSPEND 0x0008U
#define OS_TASK_STATUS_PEND 0x0010U
#define OS_TASK_STATUS_DELAY 0x0020U
#define OS_TASK_STATUS_TIMEOUT 0x0040U
#define OS_TASK_STATUS_PEND_TIME 0x0080U
#define OS_TASK_STATUS_EXIT 0x0100U
¿Qué aspecto tiene LosTaskCB? Lo siento, es un poco largo, pero aún tengo que publicar la imagen completa.
typedef struct {
VOID *stackPointer; /**< Task stack pointer */
UINT16 taskStatus; /**< Task status */
UINT16 priority; /**< Task priority */
UINT16 policy;
UINT16 timeSlice; /**< Remaining time slice */
UINT32 stackSize; /**< Task stack size */
UINTPTR topOfStack; /**< Task stack top */
UINT32 taskID; /**< Task ID */
TSK_ENTRY_FUNC taskEntry; /**< Task entrance function */
VOID *joinRetval; /**< pthread adaption */
VOID *taskSem; /**< Task-held semaphore */
VOID *taskMux; /**< Task-held mutex */
VOID *taskEvent; /**< Task-held event */
UINTPTR args[4]; /**< Parameter, of which the maximum number is 4 */
CHAR taskName[OS_TCB_NAME_LEN]; /**< Task name */
LOS_DL_LIST pendList; /**< Task pend node */
LOS_DL_LIST threadList; /**< thread list */
SortLinkList sortList; /**< Task sortlink node */
UINT32 eventMask; /**< Event mask */
UINT32 eventMode; /**< Event mode */
UINT32 priBitMap; /**< BitMap for recording the change of task priority,
the priority can not be greater than 31 */
INT32 errorNo; /**< Error Num */
UINT32 signal; /**< Task signal */
sig_cb sig;
#if (LOSCFG_KERNEL_SMP == YES)
UINT16 currCpu; /**< CPU core number of this task is running on */
UINT16 lastCpu; /**< CPU core number of this task is running on last time */
UINT16 cpuAffiMask; /**< CPU affinity mask, support up to 16 cores */
UINT32 timerCpu; /**< CPU core number of this task is delayed or pended */
#if (LOSCFG_KERNEL_SMP_TASK_SYNC == YES)
UINT32 syncSignal; /**< Synchronization for signal handling */
#endif
#if (LOSCFG_KERNEL_SMP_LOCKDEP == YES)
LockDep lockDep;
#endif
#if (LOSCFG_KERNEL_SCHED_STATISTICS == YES)
SchedStat schedStat; /**< Schedule statistics */
#endif
#endif
UINTPTR userArea;
UINTPTR userMapBase;
UINT32 userMapSize; /**< user thread stack size ,real size : userMapSize + USER_STACK_MIN_SIZE */
UINT32 processID; /**< Which belong process */
FutexNode futex;
LOS_DL_LIST joinList; /**< join list */
LOS_DL_LIST lockList; /**< Hold the lock list */
UINT32 waitID; /**< Wait for the PID or GID of the child process */
UINT16 waitFlag; /**< The type of child process that is waiting, belonging to a group or parent,
a specific child process, or any child process */
#if (LOSCFG_KERNEL_LITEIPC == YES)
UINT32 ipcStatus;
LOS_DL_LIST msgListHead;
BOOL accessMap[LOSCFG_BASE_CORE_TSK_LIMIT];
#endif
} LosTaskCB;
La estructura de LosTaskCB tiene mucho contenido, ¿qué significan?
LosTaskCB es equivalente al ID de la tarea en el kernel, que refleja el funcionamiento de cada tarea en el ciclo de vida. Dado que es un ciclo, hay un estado y necesita espacio de memoria para ejecutarse, y debe ser programado por el algoritmo del kernel. La CPU seleccionada ejecuta las instrucciones del segmento de código. Si la CPU quiere ejecutar, debe indicarle dónde comenzar la ejecución, porque es multiproceso, pero Solo una CPU necesita cambiar constantemente de tareas, luego la ejecución se interrumpirá y la ejecución debe reanudarse. ¿Cómo asegurarse de que la ejecución de la tarea reanudada no salga mal? Estos problemas deben aclararse.
En segundo lugar, cómo administrar la tarea
1. ¿Qué es un grupo de tareas?
Como se mencionó anteriormente, la tarea es el concepto del nivel de programación del kernel. El algoritmo de programación asegura la ejecución ordenada de la tarea. Habrá un capítulo detallado sobre el algoritmo de programación en el seguimiento.
¿Cómo gestionar y ejecutar tantas tareas? La administración se basa en grupos de tareas y colas listas, y la ejecución se basa en algoritmos de programación.
El código es el siguiente (OsTaskInit):
LITE_OS_SEC_TEXT_INIT UINT32 OsTaskInit(VOID)
{
UINT32 index;
UINT32 ret;
UINT32 size;
g_taskMaxNum = LOSCFG_BASE_CORE_TSK_LIMIT;//任务池中最多默认128个,可谓铁打的任务池流水的线程
size = (g_taskMaxNum + 1) * sizeof(LosTaskCB);
/* * This memory is resident memory and is used to save the system resources * of task control block and will not be freed. */
g_taskCBArray = (LosTaskCB *)LOS_MemAlloc(m_aucSysMem0, size);//任务池 常驻内存,不被释放
if (g_taskCBArray == NULL) {
return LOS_ERRNO_TSK_NO_MEMORY;
}
(VOID)memset_s(g_taskCBArray, size, 0, size);
LOS_ListInit(&g_losFreeTask);//空闲任务链表
LOS_ListInit(&g_taskRecyleList);//需回收任务链表
for (index = 0; index < g_taskMaxNum; index++) {
g_taskCBArray[index].taskStatus = OS_TASK_STATUS_UNUSED;
g_taskCBArray[index].taskID = index;//任务ID最大默认127
LOS_ListTailInsert(&g_losFreeTask, &g_taskCBArray[index].pendList);//都插入空闲任务链表
}
ret = OsPriQueueInit();//创建32个任务优先级队列,即32个双向循环链表
if (ret != LOS_OK) {
return LOS_ERRNO_TSK_NO_MEMORY;
}
/* init sortlink for each core */
for (index = 0; index < LOSCFG_KERNEL_CORE_NUM; index++) {
ret = OsSortLinkInit(&g_percpu[index].taskSortLink);//每个CPU内核都有一个执行任务链表
if (ret != LOS_OK) {
return LOS_ERRNO_TSK_NO_MEMORY;
}
}
return LOS_OK;
}
g_taskCBArray es un grupo de tareas, se crean 128 tareas de forma predeterminada, residen en la memoria y no se liberan.
g_losFreeTask es una lista enlazada de tareas inactivas. Cuando desee crear una tarea, venga aquí para solicitar una tarea gratuita. Cuando se agote, se reciclará y se seguirá utilizando para aplicaciones posteriores.
g_taskRecyleList es una lista de tareas de reciclaje, dedicada a las tareas de salida de reciclaje. Los recursos ocupados por las tareas se eliminan por completo una vez confirmadas y devueltas. Al igual que la renuncia de un empleado, debe haber una cola y un proceso de renuncia. La computadora y el buzón deben ser devueltos. Y otras operaciones.
2. ¿Qué pasa con la cola lista?
La velocidad de ejecución de la CPU es muy rápida. El intervalo de tiempo predeterminado del kernel de Hongmeng es de 10 ms. Los recursos son limitados y necesitan alternar entre muchas tareas. Por lo tanto, no se debe permitir que la CPU espere las tareas. La CPU es como el líder más grande de la compañía, muchos departamentos debajo, etc. Los líderes vienen a aprobar y comer. Solo todos están esperando al líder, no hay razón para que el líder espere por usted, por lo que el trabajo debe estar preparado con anticipación, y la prioridad de cada departamento es diferente, por lo que cada departamento debe tener una cola de tareas, que se coloca en el líder puede manejar directamente Tareas, no las ponga si no está listo, ¡porque esto es comida preparada con anticipación para la CPU!
Este es el principio de la cola lista. Hay 32 colas listas, tanto de procesos como de subprocesos, porque la prioridad de los subprocesos es 32 por defecto, y cada cola coloca tareas de la misma prioridad.
Veamos el código fuente .
#define OS_PRIORITY_QUEUE_NUM 32
UINT32 OsPriQueueInit(VOID)
{
UINT32 priority;
/* system resident resource */
g_priQueueList = (LOS_DL_LIST *)LOS_MemAlloc(m_aucSysMem0, (OS_PRIORITY_QUEUE_NUM * sizeof(LOS_DL_LIST)));//常驻内存,不被释放
if (g_priQueueList == NULL) {
return LOS_NOK;
}
for (priority = 0; priority < OS_PRIORITY_QUEUE_NUM; ++priority) {
LOS_ListInit(&g_priQueueList[priority]);
}
return LOS_OK;
}
Preste atención a la asignación de memoria de g_priQueueList, que es 32 LOS_DL_LIST. ¿Recuerda el efecto mágico de LOS_DL_LIST? Vaya a Análisis de código fuente del sistema Hongmeng (Catálogo general) si no está seguro .
3. ¿Qué pasa con la pila de tareas?
Cada tarea se abre de forma independiente y las tareas también son independientes entre sí. La comunicación entre ellas se realiza a través de IPC. El "independiente" aquí significa que cada tarea tiene su propio entorno operativo: espacio de pila, llamado pila de tareas, pila La información almacenada en el espacio incluye variables locales, registros, parámetros de función, direcciones de retorno de función, etc.
Sin embargo, solo hay una CPU en el sistema y las tareas son independientes. La esencia de la programación es que la CPU ejecuta una nueva tarea y ¿dónde se interrumpe la tarea anterior? No está claro, es aleatorio. Entonces, ¿cómo garantizar que la tarea anterior pueda continuar ejecutándose desde el lugar donde se interrumpió la última vez cuando se programó nuevamente?
La respuesta es: contexto de la tarea, hay un montón de registros en la CPU. La esencia del funcionamiento de la CPU es que los valores de estos registros cambian constantemente. Siempre que estos valores se guarden al cambiar y luego se restauren, se puede garantizar la ejecución continua de la tarea, dejando al usuario sin Percepción.
Esto es lo mismo que cuando jugábamos al escondite cuando éramos jóvenes. Nuestros padres nos interrumpieron a la mitad del juego y nos llamaron para comer. Seguimos jugando por la tarde. Zhang San, deberías volver al árbol y esconderte, Li Si siguió escondiéndose debajo de la cama, Wang El quinto es atrapar a Zhang San y Li Si continúan atrapando, primero restauran la escena y luego continúan jugando. Esto registra la ubicación de todos y la información del rol es el contexto de la tarea. De hecho, una tarea debe interrumpirse repetidamente. El kernel de Hongmeng da un tiempo de ejecución de la tarea de 20 ms, lo que significa que en el caso de una competencia multitarea, tiene que alternar 50 veces en un segundo como máximo.
¿Qué es el contexto de la tarea (TaskContext)? Todavía mira el código fuente directamente
/* The size of this structure must be smaller than or equal to the size specified by OS_TSK_STACK_ALIGN (16 bytes). */
typedef struct {
#if !defined(LOSCFG_ARCH_FPU_DISABLE)
UINT64 D[FP_REGS_NUM]; /* D0-D31 */
UINT32 regFPSCR; /* FPSCR */
UINT32 regFPEXC; /* FPEXC */
#endif
UINT32 resved; /* It's stack 8 aligned */
UINT32 regPSR;
UINT32 R[GEN_REGS_NUM]; /* R0-R12 */
UINT32 SP; /* R13 */
UINT32 LR; /* R14 */
UINT32 PC; /* R15 */
} TaskContext;
Se encuentra que es básicamente el valor del campo de recuperación del registro de la CPU, puedes consultar las funciones específicas de cada registro en Internet, y habrá un artículo especial para presentarlo más adelante. Estos son tres de los registros SP, LR, PC
LR
tiene dos propósitos. El primero es guardar la dirección de retorno de la subrutina. Cuando se llama a una instrucción de salto como BL, BX, BLX, etc., la dirección de retorno se guarda automáticamente en LR; el segundo es guardar la dirección de retorno de excepción cuando ocurre una excepción.
PC (Program Counter)
es el contador de programa, que se utiliza para guardar la dirección de ejecución del programa. En la arquitectura de canalización de tres etapas de ARM, la canalización del programa incluye tres etapas: direccionamiento, decodificación y ejecución. La PC apunta a la dirección del programa de la dirección actual , Por lo tanto, en ARM de 32 bits, la dirección de decodificación (el programa que se está analizando y aún no se está ejecutando) es PC-4, y la dirección de ejecución (la dirección del programa que se está ejecutando actualmente) es PC-8. Cuando ocurre una interrupción repentina, la PC se guarda la dirección de.
Cada modo de excepción de SP tiene su propio r13 independiente, que generalmente apunta a la pila dedicada al modo de excepción.Cuando ARM entra en el modo de excepción, el programa puede empujar registros de propósito general a la pila y luego abrir la pila cuando regresa. La integridad del estado del programa en varios modos.
4. Inicialización de la pila de tareas
La inicialización de la pila de tareas es la inicialización del contexto de la tarea, debido a que la tarea no ha comenzado a ejecutarse, no habrá otro contenido excepto el contexto. Tenga en cuenta que el contexto se almacena en la parte inferior de la pila.
Tres, conjunto de funciones de tareas
LITE_OS_SEC_TEXT_INIT VOID *OsTaskStackInit(UINT32 taskID, UINT32 stackSize, VOID *topStack, BOOL initFlag)
{
UINT32 index = 1;
TaskContext *taskContext = NULL;
if (initFlag == TRUE) {
OsStackInit(topStack, stackSize);
}
taskContext = (TaskContext *)(((UINTPTR)topStack + stackSize) - sizeof(TaskContext));//注意看上下文将存放在栈的底部
/* initialize the task context */
#ifdef LOSCFG_GDB
taskContext->PC = (UINTPTR)OsTaskEntrySetupLoopFrame;
#else
taskContext->PC = (UINTPTR)OsTaskEntry;//程序计数器,CPU首次执行task时跑的第一条指令位置
#endif
taskContext->LR = (UINTPTR)OsTaskExit; /* LR should be kept, to distinguish it's THUMB or ARM instruction */
taskContext->resved = 0x0;
taskContext->R[0] = taskID; /* R0 */
taskContext->R[index++] = 0x01010101; /* R1, 0x01010101 : reg initialed magic word */
for (; index < GEN_REGS_NUM; index++) {
//R2 - R12的初始化很有意思,为什么要这么做?
taskContext->R[index] = taskContext->R[index - 1] + taskContext->R[1]; /* R2 - R12 */
}
#ifdef LOSCFG_INTERWORK_THUMB // 16位模式
taskContext->regPSR = PSR_MODE_SVC_THUMB; /* CPSR (Enable IRQ and FIQ interrupts, THUMNB-mode) */
#else
taskContext->regPSR = PSR_MODE_SVC_ARM; /* CPSR (Enable IRQ and FIQ interrupts, ARM-mode) */
#endif
#if !defined(LOSCFG_ARCH_FPU_DISABLE)
/* 0xAAA0000000000000LL : float reg initialed magic word */
for (index = 0; index < FP_REGS_NUM; index++) {
taskContext->D[index] = 0xAAA0000000000000LL + index; /* D0 - D31 */
}
taskContext->regFPSCR = 0;
taskContext->regFPEXC = FP_EN;
#endif
return (VOID *)taskContext;
}
1. Escenarios de uso y funciones
Una vez creada la tarea, el kernel puede realizar operaciones como bloquear la programación de tareas, desbloquear la programación de tareas, suspender, reanudar y retrasar. Al mismo tiempo, también puede establecer la prioridad de la tarea y obtener la prioridad de la tarea. Cuando finaliza la tarea, se realiza la operación de eliminación automática de la tarea actual.
El módulo de gestión de tareas del sistema Huawei LiteOS proporciona a los usuarios las siguientes funciones.
Clasificación de funciones | Nombre de la interfaz | descripción |
---|---|---|
Creación y eliminación de tareas | LOS_TaskCreateOnly | Cree una tarea y haga que la tarea entre en estado de suspensión sin programar. |
LOS_TaskCreate | Cree una tarea, haga que la tarea entre en estado listo y prográmela. | |
LOS_TaskDelete | Elimina la tarea especificada. | |
Control de estado de la tarea | LOS_TaskResume | Reanudar las tareas suspendidas. |
LOS_TaskSuspend | Suspenda la tarea especificada. | |
LOS_TaskDelay | La tarea se retrasa. | |
LOS_TaskYield | Descentralización explícita, ajuste el orden de programación de tareas de la prioridad especificada. | |
Control de programación de tareas | LOS_TaskLock | Bloquear la programación de tareas. |
LOS_TaskUnlock | Desbloquee la programación de tareas. | |
Control de prioridad de tareas | LOS_CurTaskPriSet | Establece la prioridad de la tarea actual. |
LOS_TaskPriSet | Establece la prioridad de la tarea especificada. | |
LOS_TaskPriGet | Obtenga la prioridad de la tarea especificada. | |
Adquisición de información de tareas | LOS_CurTaskIDGet | Obtén el ID de la tarea actual. |
LOS_TaskInfoGet | Establece la prioridad de la tarea especificada. | |
LOS_TaskPriGet | Obtén información sobre la tarea especificada. | |
LOS_TaskStatusGet | Obtén el estado de la tarea especificada. | |
LOS_TaskNameGet | Obtenga el nombre de la tarea especificada. | |
LOS_TaskInfoMonitor | Supervise todas las tareas y obtenga información sobre todas las tareas. | |
LOS_NextTaskIDGet | Obtenga el ID de la tarea que se va a programar. |
2. El proceso de creación de tareas
Antes de crear una tarea, aprenda sobre otra estructura tagTskInitParam
typedef struct tagTskInitParam {
TSK_ENTRY_FUNC pfnTaskEntry; /**< Task entrance function */
UINT16 usTaskPrio; /**< Task priority */
UINT16 policy; /**< Task policy */
UINTPTR auwArgs[4]; /**< Task parameters, of which the maximum number is four */
UINT32 uwStackSize; /**< Task stack size */
CHAR *pcName; /**< Task name */
#if (LOSCFG_KERNEL_SMP == YES)
UINT16 usCpuAffiMask; /**< Task cpu affinity mask */
#endif
UINT32 uwResved; /**< It is automatically deleted if set to LOS_TASK_STATUS_DETACHED. It is unable to be deleted if set to 0. */
UINT16 consoleID; /**< The console id of task belongs */
UINT32 processID;
UserTaskParam userParam;
} TSK_INIT_PARAM_S;
Estos parámetros de inicialización son los parámetros iniciales expuestos de la tarea y pfnTaskEntry 对java来说就是你new进程的run(),
deben ser proporcionados por el usuario superior.
Veamos un ejemplo: escriba el comando ping en el shell para ver el proceso de su creación
u32_t osShellPing(int argc, const char **argv)
{
int ret;
u32_t i = 0;
u32_t count = 0;
int count_set = 0;
u32_t interval = 1000; /* default ping interval */
u32_t data_len = 48; /* default data length */
ip4_addr_t dst_ipaddr;
TSK_INIT_PARAM_S stPingTask;
// ...省去一些中间代码
/* start one task if ping forever or ping count greater than 60 */
if (count == 0 || count > LWIP_SHELL_CMD_PING_RETRY_TIMES) {
if (ping_taskid > 0) {
PRINTK("Ping task already running and only support one now\n");
return LOS_NOK;
}
stPingTask.pfnTaskEntry = (TSK_ENTRY_FUNC)ping_cmd;//线程的执行函数
stPingTask.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;//0x4000 = 16K
stPingTask.pcName = "ping_task";
stPingTask.usTaskPrio = 8; /* higher than shell 优先级高于10,属于内核态线程*/
stPingTask.uwResved = LOS_TASK_STATUS_DETACHED;
stPingTask.auwArgs[0] = dst_ipaddr.addr; /* network order */
stPingTask.auwArgs[1] = count;
stPingTask.auwArgs[2] = interval;
stPingTask.auwArgs[3] = data_len;
ret = LOS_TaskCreate((UINT32 *)(&ping_taskid), &stPingTask);
}
// ...
return LOS_OK;
ping_error:
lwip_ping_usage();
return LOS_NOK;
}
Se encuentra que la prioridad de programación del ping es 8, que es mayor que la del shell ¿Cuál es la prioridad del shell? La respuesta es: ver el código fuente es 9
LITE_OS_SEC_TEXT_MINOR UINT32 ShellTaskInit(ShellCB *shellCB)
{
CHAR *name = NULL;
TSK_INIT_PARAM_S initParam = {
0};
if (shellCB->consoleID == CONSOLE_SERIAL) {
name = SERIAL_SHELL_TASK_NAME;
} else if (shellCB->consoleID == CONSOLE_TELNET) {
name = TELNET_SHELL_TASK_NAME;
} else {
return LOS_NOK;
}
initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)ShellTask;
initParam.usTaskPrio = 9; /* 9:shell task priority */
initParam.auwArgs[0] = (UINTPTR)shellCB;
initParam.uwStackSize = 0x3000;
initParam.pcName = name;
initParam.uwResved = LOS_TASK_STATUS_DETACHED;
(VOID)LOS_EventInit(&shellCB->shellEvent);
return LOS_TaskCreate(&shellCB->shellTaskHandle, &initParam);
}
Continúe prestando atención a la introducción detallada de shell en el seguimiento.
Después de comprender las condiciones previas, depende de cómo se crea la tarea paso a paso, cómo vincularse al proceso, unirse a la cola de programación lista o continuar mirando el código fuente
LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskCreate(UINT32 *taskID, TSK_INIT_PARAM_S *initParam)
{
UINT32 ret;
UINT32 intSave;
LosTaskCB *taskCB = NULL;
if (initParam == NULL) {
return LOS_ERRNO_TSK_PTR_NULL;
}
if (OS_INT_ACTIVE) {
return LOS_ERRNO_TSK_YIELD_IN_INT;
}
if (initParam->uwResved & OS_TASK_FLAG_IDLEFLAG) {
initParam->processID = OsGetIdleProcessID();
} else if (OsProcessIsUserMode(OsCurrProcessGet())) {
initParam->processID = OsGetKernelInitProcessID();
} else {
initParam->processID = OsCurrProcessGet()->processID;
}
initParam->uwResved &= ~OS_TASK_FLAG_IDLEFLAG;
initParam->uwResved &= ~OS_TASK_FLAG_PTHREAD_JOIN;
if (initParam->uwResved & LOS_TASK_STATUS_DETACHED) {
initParam->uwResved = OS_TASK_FLAG_DETACHED;
}
ret = LOS_TaskCreateOnly(taskID, initParam);
if (ret != LOS_OK) {
return ret;
}
taskCB = OS_TCB_FROM_TID(*taskID);
SCHEDULER_LOCK(intSave);
taskCB->taskStatus &= ~OS_TASK_STATUS_INIT;
OS_TASK_SCHED_QUEUE_ENQUEUE(taskCB, 0);
SCHEDULER_UNLOCK(intSave);
/* in case created task not running on this core,
schedule or not depends on other schedulers status. */
LOS_MpSchedule(OS_MP_CPU_ALL);
if (OS_SCHEDULER_ACTIVE) {
LOS_Schedule();//*kyf 任务创建完了 申请调度
}
return LOS_OK;
}
Hasta ahora, la creación se ha completado y todos están en su lugar. El código fuente finalmente se aplicó para LOS_Schedule (); debido a que el método de programación de Hongmeng es preventivo, la prioridad de esta tarea es mayor que la de otras colas listas, entonces la tarea que se ejecutará a continuación ¡Eso es!
3. ¿Cuáles son los contenidos importantes de la parte Task / Thread que no se han mencionado?
Cómo se asigna la memoria, cómo comunicarse entre subprocesos y cómo se ejecuta la pila durante la operación Después de la charla de seguimiento sobre la memoria, la parte IPC se desmontará para su análisis.
Para obtener más información, haga clic en Análisis de código fuente del sistema Hongmeng (catálogo general)