Les modules task et stack permettent de créer, configurer et piloter les tâches du noyau. Cette page détaille les fonctions de ces modules et leur usage typique.
1. Synthèse des fonctions
L'ensemble de ces fonctions est déclaré dans les fichiers d'en-tête mk_task.h et mk_stack.h :
| Fonction | Description |
|---|---|
| mk_ |
Initialise les attributs d'une pile. |
| mk_ |
Initialise les attributs d'une tâche. |
| mk_ |
Crée une tâche. |
| mk_ |
Supprime une tâche. |
| mk_ |
Réalise un changement de contexte. |
| mk_ |
Réalise une temporisation. |
| mk_ |
Réalise une temporisation relative. |
| mk_ |
Suspend une tâche. |
| mk_ |
Réveille une tâche suspendue. |
| mk_ |
Change la priorité d'une tâche. |
| mk_ |
Récupère l'adresse d'une tâche. |
| mk_ |
Récupère l'identifiant, le type, l'état ou la priorité d'une tâche. |
| mk_ |
Récupère le taux de charge CPU d'une tâche. |
2. Utilisation
La création d'une tâche s'effectue à partir des fonctions mk_stack_create, mk_task_setTaskCtrlBlock et mk_task_create. L'exemple ci-dessous présente le code minimal pour créer une tâche de manière statique :
/* Déclaration de la variable de retour */ T_mkCode l_result = K_MK_OK; /* Déclaration du buffer où sera stockée la pile de la tâche */ /* Celui-ci peut être dans une zone privilégiée ou non */ /* Cette partie sera abordée dans le chapitre sur la MPU. */ K_MK_PRIVILEGED_MEMORY uint32_t l_privilegedStackBuf [ 512 ]; /* Déclaration d'un pointeur de tâche */ T_mkTask* l_task; /* Déclaration d'une structure contenant les informations de la stack */ T_mkStack l_stack; /* Déclaration d'une structure contenant les informations de la tâche */ T_mkTaskCtrlBlock l_taskCtrlBlock; /* Configuration de la structure l_stack avec les attributs de la pile */ /* K_MK_TYPE_DEFAULT - pile classique */ /* Taille de 512 mots 32bits */ l_result = mk_stack_create ( &l_stack, K_MK_TYPE_DEFAULT, l_privilegedStackBuf, 512 ); /* Configuration de la structure l_taskCtrlBlock avec les attributs */ /* de la tâche */ /* Type : tâche privilégiée non flottante */ /* Identifiant : K_MK_TASK_ID_MY_TASK */ /* Priorité : 10 */ /* Propriétaire : NULL */ l_result = mk_task_setTaskCtrlBlock ( &l_taskCtrlBlock, K_MK_TYPE_PRIVILEGED, K_MK_TASK_ID_MY_TASK, 10, K_MK_NULL ); /* Si aucune erreur ne s'est produite */ if ( l_result == K_MK_OK ) { /* Création de la tâche */ /* Point d'entrée de la tâche : mk_task_privileged */ /* Argument de la fonction : "Hello world !" */ l_result = mk_task_create ( &l_task, &l_stack, K_MK_NULL, &l_taskCtrlBlock, mk_task_privileged, ( T_mkAddr ) "Hello world !" ); }
La fonction mk_stack_create permet de rassembler les attributs de la pile dans une structure de type T_mkStack. En fonction du type de la pile (K_MK_TYPE_DEFAULT ou K_MK_TYPE_FLOATING), cette fonction vérifie que la taille du buffer spécifié par l'utilisateur est suffisante pour sauvegarder le contexte de la tâche.
La fonction mk_task_setTaskCtrlBlock permet de rassembler les attributs de la tâche dans une structure de type T_mkTaskCtrlBlock. Elle configure l'identifiant, la priorité, le propriétaire et le type de la tâche :
L'utilisateur exécute ensuite la fonction mk_task_create avec les caractéristiques précédentes, l'adresse du point d'entrée de la tâche (mk_task_privileged) et la valeur de son argument.
Dans la situation où le noyau a déjà démarré (mk_start), la tâche est alors créée et est placée dans la liste des tâches prêtes à être exécutées.
La définition d'une tâche et son code minimal sont présentés ci-dessous :
void mk_task_privileged ( T_mkAddr p_param ) { /* Dans notre exemple, p_param pointe sur "Hello world !" */ for ( ;; ) ; }
Les tâches ne doivent jamais terminer leur exécution et doivent vivre à l'intérieur d'une boucle infinie. Dans la situation où une tâche doit être détruite, la fonction mk_task_terminate peut être utilisée.
Les tâches peuvent être créées avant et après le démarrage du noyau :
void mk_main ( void ) { /* ... */ /* Initialisation du noyau */ l_result = mk_init ( K_MK_MODE_FLOATING, g_mkProcessStack, K_MK_PROCESS_STACK_SIZE ); /* Initialisation de la tâche de repos */ l_result |= mk_createIdle ( g_mkIdleStack, K_MK_TASK_IDLE_STACK_SIZE, mk_task_idle, ( T_mkAddr ) "I" ); /* On crée des tâches depuis le programme principal */ l_result |= mk_createTasks ( ); /* Lancement du noyau avec un tick de 1 ms */ l_result |= mk_start ( 27000 ); for ( ;; ) ; } /* Une tâche quelconque */ void mk_task_privileged ( T_mkAddr p_param ) { /* ... */ /* On crée une tâche depuis une autre tâche */ l_result = mk_task_create ( &l_task, &l_stack, K_MK_NULL, &l_taskCtrlBlock, mk_task_newTask, K_MK_NULL ); /* ... */ }
Elles peuvent aussi être créées depuis un vecteur d'interruption. Dans cette situation, il est plus simple d'allouer dynamiquement la pile de la tâche en plaçant une pool mémoire en paramètre.
❔
Une pool est un allocateur mémoire qui permet d'allouer dynamiquement des blocs de taille fixe. De par leur nature, les pools ne sont pas soumises à la fragmentation mémoire.
L'exemple ci-dessous montre comment créer une tâche à pile dynamique depuis un vecteur d'interruption :
/* Déclaration du buffer où sera stockée la tâche */ /* Celui-ci doit être dans une zone protégée */ K_MK_UNPRIVILEGED_DMA_MEMORY uint32_t l_unprivilegedStackBuf [ 1024 ]; /* Déclaration d'un pointeur de pool */ T_mkPool* g_mkPool; /* Il est nécessaire d'initialiser un gestionnaire mémoire dans un contexte persistant */ void mk_task ( T_mkAddr p_param ) { /* ... */ /* Configuration des attributs de la zone mémoire dans une structure */ l_result = mk_pool_initArea ( &l_area, l_unprivilegedStackBuf, 1024 ); /* Création d'un allocateur mémoire constitué de 4 buffers de 256 mots */ l_result |= mk_pool_create ( &l_area, &g_mkPool, K_MK_AREA_UNPROTECTED, 256, 4 ); /* ... */ } /* Un vecteur d'interruption quelconque */ void mk_isr ( void ) { /* ... */ /* Configuration de la structure l_taskCtrlBlock avec les attributs */ /* de la tâche */ /* Type : tâche non privilégiée flottante */ /* Identifiant : K_MK_TASK_ID_MY_TASK */ /* Priorité : 1 */ /* Propriétaire : NULL */ l_result = mk_task_setTaskCtrlBlock ( &l_taskCtrlBlock, K_MK_TYPE_FLOATING, K_MK_TASK_ID_MY_TASK, 1, K_MK_NULL ); /* Si aucune erreur ne s'est produite */ if ( l_result == K_MK_OK ) { /* Création de la tâche */ /* Pour une tâche dynamique, on précise K_MK_NULL pour le paramètre */ /* p_mkStack et l'adresse d'un allocateur mémoire pour p_mkPool */ /* La pile sera allouée dans l'un des 4 buffers de l'allocateur */ l_result = mk_task_create ( &l_task, K_MK_NULL, g_mkPool, &l_taskCtrlBlock, mk_task_unprivileged, ( T_mkAddr ) "Hello world !" ); } /* ... */ }
Dans l'exemple ci-dessus, lorsque la tâche créée par l'interruption a terminé son travail, elle peut stopper son exécution en utilisant la fonction mk_task_terminate :
void mk_task_unprivileged ( T_mkAddr p_param ) { /* ... */ /* Cette tâche a terminé son travail */ /* Elle peut donc s'autodétruire */ l_result = mk_task_terminate ( K_MK_NULL ); for ( ;; ) ; }
Une tâche peut aussi détruire une autre tâche en combinant les fonctions mk_task_getHandle et mk_task_terminate :
void mk_task ( T_mkAddr p_param ) { /* ... */ /* Récupération de l'instance de la tâche à détruire */ /* via son identifiant 32 bits */ l_result = mk_task_getHandle ( &l_taskToDelete, K_MK_TASK_ID ); /* Si aucune erreur ne s'est produite */ if ( l_result == K_MK_OK ) { /* On détruit une tâche depuis une autre tâche */ l_result = mk_task_terminate ( l_taskToDelete ); } /* ... */ }
Avant d'utiliser la fonction mk_task_terminate, l'utilisateur doit s'assurer que la tâche à détruire a libéré l'ensemble des ressources prises (objet de synchronisation et mémoire). Cette synchronisation s'effectue généralement en utilisant un signal couplé à une autodestruction de tâche.
Le module task offre aussi la possibilité de suspendre et reprendre l'exécution d'une tâche. Le couple de fonctions mk_task_suspend et mk_task_resume est prévu pour cet usage :
/* Code d'une interruption ou d'une tâche quelconque */ void mk_isr_or_task ( void ) { /* ... */ /* Les fonctions mk_task_resume et mk_task_suspend sont */ /* toutes les deux utilisables dans un vecteur d'interruption */ /* Redémarrage de l'exécution d'une tâche */ l_result = mk_task_resume ( &l_taskToResume ) ; /* ... */ } /* Une tâche quelconque */ void mk_task ( void ) { /* Routines d'initialisation de l_taskToResume ... */ /* ... */ /* La tâche s'auto-suspend au démarrage le temps de recevoir un signal */ l_result = mk_task_suspend ( K_MK_NULL ) ; for ( ;; ) { /* Suite du code de la tâche... */ } }
Lorsqu'une tâche est suspendue, celle-ci reste dans l'état K_MK_STATE_SUSPENDED jusqu'au prochain appel explicite de la fonction mk_task_resume.
L'appel de la fonction mk_task_yield permet de déclencher un changement de contexte explicite. Elle est surtout dédiée au mode de fonctionnement coopératif :
void mk_main ( void ) { /* ... */ /* On crée 3 tâches de même priorité dans cette fonction */ /* La fonction mk_task_create ajoute séquentiellement les tâches */ /* dans la liste des tâches prêtes à être exécutées. */ /* La première tâche ajoutée sera la première exécutée. */ l_result |= mk_createTasks ( ); /* Lancement du noyau avec le timer système désactivé */ /* Mode coopératif - round-robin désactivé. */ l_result |= mk_start ( 0 ); for ( ;; ) ; } /* Première tâche créée */ void mk_task1 ( T_mkAddr p_mkAddr ) { for ( ;; ) { /* ... */ /* Donne la main à mk_task2 */ l_result = mk_task_yield ( ); } } /* Deuxième tâche créée */ void mk_task2 ( T_mkAddr p_mkAddr ) { for ( ;; ) { /* ... */ /* Donne la main à mk_task3 */ l_result = mk_task_yield ( ); } } /* Troisième tâche créée */ void mk_task3 ( T_mkAddr p_mkAddr ) { for ( ;; ) { /* ... */ /* Donne la main à mk_task1 */ l_result = mk_task_yield ( ); } }
❔
Même si le noyau est intrinsèquement préemptif, un modèle d'ordonnancement coopératif peut être obtenu en désactivant le timer système et en configurant la priorité de toutes les tâches à la même valeur. Les services de temporisations deviennent alors inutilisables.
Le module task offre deux services de temporisation. La fonction mk_task_sleep permet d'endormir une tâche pendant une certaine durée :
void mk_task ( T_mkAddr p_param ) { /* ... */ for ( ;; ) { /* Temporisation de la tâche (Tick 300) */ /* Celle-ci se réveillera dans 2000 ticks au tick 2300 */ l_result = mk_task_sleep ( 2000 ); } }
Contrairement à la fonction mk_task_sleep, la routine mk_task_delay effectue sa temporisation par rapport à son tick de référence. Cette fonction peut être utilisée lorsqu'une tâche doit s'exécuter périodiquement à des ticks précis :
void mk_task ( T_mkAddr p_param ) { /* ... */ for ( ;; ) { /* Temporisation relative d'une tâche (Tick 300) */ /* Celle-ci se réveillera au tick (refTime + 2000) soit 2000 */ /* pour la première itération (refTime=0) */ l_result = mk_task_delay ( 2000 ); /* Après cette temporisation, refTime = 2000 puis 4000, ... */ } }
Le tick de référence de chaque tâche est initialement nul. Celui-ci s'actualise à chaque itération de la fonction. Dans la situation où la valeur du tick calculé est supérieure au tick courant, la tâche se réveille immédiatement. Ce mécanisme permet de compenser le retard éventuel induit par les autres tâches du noyau.
Le module task offre aussi la possibilité de modifier la priorité d'une tâche. En situation nominale, toutes les tâches du noyau s'exécutent avec leur priorité de base. Il est possible de changer cette priorité en utilisant la fonction mk_task_priority :
void mk_task ( T_mkAddr p_param ) { /* ... */ /* La tâche courante modifie sa propre priorité */ l_result = mk_task_priority ( K_MK_NULL, 1 ); /* Récupération de l'instance d'une tâche */ /* dont la priorité doit être modifiée */ l_result |= mk_task_getHandle ( &l_taskToModify, K_MK_TASK_ID ); /* Modification de la priorité d'une autre tâche */ l_result |= mk_task_priority ( l_taskToModify, 3 ); /* ... */ for ( ;; ) ; }
Du fait de la complexité du mécanisme d'héritage de priorité, le noyau n'autorise le changement d'une priorité que lorsque les conditions ci-dessous sont remplies :
✔la tâche n'est pas en possession d'un objet de synchronisation de type T_mkMutex.
✔la tâche est dans l'état K_MK_
Enfin, le module task offre deux derniers services au travers des fonctions mk_task_get et mk_task_getLoad.
La première fonction permet de récupérer l'identifiant, le type, l'état ou la priorité d'une tâche. La seconde permet de récupérer le taux de charge CPU d'une tâche en pourcentage :
void mk_task ( T_mkAddr p_param ) { /* Déclaration des variables stockant les attributs */ uint32_t l_id, l_type, l_state, l_basePriority, l_currentPriority; uint32_t l_load; /* ... */ /* Récupération de l'instance d'une tâche */ l_result = mk_task_getHandle ( &l_task, K_MK_TASK_ID ); /* Récupération des attributs de la tâche */ l_result |= mk_task_get ( l_task, &l_id, K_MK_ID ); l_result |= mk_task_get ( l_task, &l_type, K_MK_TYPE ); l_result |= mk_task_get ( l_task, &l_state, K_MK_STATE ); l_result |= mk_task_get ( l_task, &l_basePriority, K_MK_PRIORITY ); l_result |= mk_task_get ( l_task, &l_currentPriority, K_MK_CURRENT_PRIORITY ); /* Récupération du taux de charge CPU */ l_result |= mk_task_getLoad ( l_task, &l_load ); /* ... */ for ( ;; ) ; }
3. API
3.1. La fonction mk_stack_create()
Cette fonction stocke les attributs d'une pile dans une structure T_mkStack.
Prototype :
T_mkCode mk_stack_create ( T_mkStack* p_mkStack, uint32_t p_mkType, uint32_t* p_mkAddress, uint32_t p_mkSize );
Paramètres :
- p_mkStack [out]
Adresse d'une structure de type T_mkStack.
- p_mkType [in]
Type de la pile à allouer. Les valeurs possibles sont les suivantes :
- K_MK_TYPE_DEFAULT : la pile est de type non flottante.
- K_MK_TYPE_FLOATING : la pile est de type flottante.
- p_mkAddress [in]
Adresse mémoire de la pile (alignée sur 32 bits).
- p_mkSize [in]
Taille de la pile (en multiple de mots 32 bits).
Retour :
- K_MK_OK : les attributs de la pile ont été configurés dans la structure T_mkStack.
- K_MK_ERROR_PARAM : les attributs de la pile n'ont pas été configurés car au moins un paramètre est invalide.
- K_MK_ERROR_INIT : les attributs de la pile n'ont pas été configurés car le noyau n'est pas initialisé.
Note :
- Pour déterminer si la taille d'une pile est suffisante, cette fonction récupère le type du
noyau (flottant/non flottant) et compare la valeur du paramètre p_mkSize avec les constantes suivantes :
- K_MK_
STACK_ : taille minimale d'une pile non flottante pour un noyau de type non flottant.MIN_ SIZE_ DEFAULT_ MODE_ DEFAULT_ TYPE - K_MK_
STACK_ : taille minimale d'une pile non flottante pour un noyau de type flottant.MIN_ SIZE_ FLOATING_ MODE_ DEFAULT_ TYPE - K_MK_
STACK_ : taille minimale d'une pile flottante pour un noyau de type flottant.MIN_ SIZE_ FLOATING_ MODE_ FLOATING_ TYPE
- K_MK_
- L'architecture cortex-m7 utilise des piles de type descendant. Pour un buffer donné, l'adresse de début de la stack est « p_mkAddress + p_mkSize - 1 », l'adresse de fin de la pile est « p_mkAddress ».
3.2. La fonction mk_task_setTaskCtrlBlock()
Cette fonction écrit la valeur des attributs type, identifier, priority et owner dans une structure de type T_mkTaskCtrlBlock.
Prototype :
T_mkCode mk_task_setTaskCtrlBlock ( T_mkTaskCtrlBlock* p_mkAttribute, uint32_t p_mkType, uint32_t p_mkIdentifier, uint32_t p_mkPriority, T_mkAddr p_mkOwner );
Paramètres :
- p_mkAttribute [out]
Adresse d'une structure de type T_mkTaskCtrlBlock.
- p_mkType [in]
Type de la tâche à créer. Le type de la tâche peut prendre les valeurs suivantes :
- K_MK_TYPE_DEFAULT : le contexte de la tâche est non flottant, la tâche est de type non privilégié.
- K_MK_TYPE_PRIVILEGED : le contexte de la tâche est non flottant, la tâche est de type privilégié.
- K_MK_TYPE_FLOATING : le contexte de la tâche est flottant, la tâche est de type non privilégié.
- K_MK_TYPE_FLOATING_PRIVILEGED : le contexte de la tâche est flottant, la tâche est de type privilégié.
- p_mkIdentifier [in]
Identifiant de la tâche à créer. La valeur peut évoluer de [0 à 0xFFFFFFFF]. Les valeurs K_MK_TASK_ID_MAIN et K_MK_TASK_ID_IDLE sont réservées.
- p_mkPriority [in]
Priorité de la tâche à créer. La valeur de priorité peut évoluer de 1 à K_MK_SCHEDULER_PRIORITY_NUMBER (la plus élevée).
- p_mkOwner [in]
Adresse du propriétaire de la tâche. Ce paramètre peut être nul (K_MK_NULL) si aucun propriétaire n'existe. Ce paramètre est sans effet lorsque l'attribut p_mkOwner de la tâche créatrice est non nul (héritage des propriétaires). Cette règle ne s'applique pas aux interruptions.
Retour :
- K_MK_OK : les attributs de la tâche ont été écrits.
- K_MK_ERROR_PARAM : les attributs n'ont pas été écrits car le paramètre « p_mkAttribute » est invalide.
3.3. La fonction mk_task_create()
Cette fonction crée une nouvelle tâche. Suite à sa création, la tâche se situe dans l'état K_MK_STATE_READY.
Prototype :
T_mkCode mk_task_create ( T_mkTask** p_mkHandle, T_mkStack* p_mkStack, T_mkPool* p_mkPool, T_mkTaskCtrlBlock* p_mkAttribute, T_mkAddress p_mkFunction, T_mkAddr p_mkArg );
Paramètres :
- p_mkHandle [out]
Adresse d'un pointeur de tâche de type T_mkTask*. Si cette fonction est appelée depuis un vecteur d'interruption, ce paramètre doit être K_MK_NULL.
- p_mkStack [in]
Adresse d'une structure de type T_mkStack. Cette structure stocke les informations relatives à la création d'une pile statique. Si une pile dynamique doit être créée alors ce paramètre doit être K_MK_NULL.
- p_mkPool [in]
Adresse d'une structure de type T_mkPool. Cette structure stocke les informations du gestionnaire d'allocation de taille fixe qui sera utilisé pour allouer dynamiquement la pile. Si une stack statique doit être créée alors ce paramètre doit être K_MK_NULL.
- p_mkAttribute [in]
Adresse d'une structure de type T_mkTaskCtrlBlock. Cette structure stocke les attributs de la tâche à créer.
- p_mkFunction [in]
Adresse de la fonction de démarrage.
- p_mkArg [in]
Valeur de l'argument de la tâche.
Retour :
- K_MK_OK : la tâche a été démarrée.
- K_MK_ERROR_PARAM : la tâche n'a pas été démarrée car au moins un paramètre est invalide.
- K_MK_ERROR_MALLOC : la tâche n'a pas été démarrée car le nombre de tâches maximales pouvant être allouées est atteint, la quantité de mémoire disponible dans le gestionnaire d'allocation de taille fixe est insuffisante ou la taille de la pile est insuffisante.
- K_MK_ERROR_RIGHT : la tâche n'a pas été démarrée car une tâche de type non privilégié ne peut pas créer une tâche de type privilégié.
Note :
- Cette fonction peut être exécutée dans un vecteur d'interruption. Le paramètre p_mkHandle doit être nul dans ce cas de figure.
- Si au moins une tâche est de type flottant alors le noyau doit obligatoirement être initialisé en mode flottant (fonction mk_init).
Attention :
⚠️
- Cette fonction entre dans une section critique lors de son exécution. Elle masque temporairement les interruptions de priorité numérique supérieure ou égale à K_MK_SCHEDULER_MASK_PRIORITY. Le masque est automatiquement levé avant d'en sortir.
3.4. La fonction mk_task_terminate()
Cette fonction supprime une tâche. La mémoire ou les objets alloués par cette tâche ne sont pas libérés.
Prototype :
T_mkCode mk_task_terminate ( T_mkTask* p_mkTask );
Paramètres :
- p_mkTask [in]
Adresse de la tâche à supprimer. Il peut prendre la valeur K_MK_NULL pour désigner la tâche courante.
Retour :
- K_MK_OK : la tâche a été supprimée.
- K_MK_ERROR_RIGHT : la tâche n'a pas été supprimée car une tâche de type non privilégié ne peut pas supprimer une tâche privilégiée.
Attention :
⚠️
- Cette fonction entre dans une section critique lors de son exécution. Elle masque temporairement les interruptions de priorité numérique supérieure ou égale à K_MK_SCHEDULER_MASK_PRIORITY. Le masque est automatiquement levé avant d'en sortir.
3.5. La fonction mk_task_yield()
Cette fonction déclenche un changement de contexte.
Prototype :
T_mkCode mk_task_yield ( void );
Retour :
- K_MK_OK : le changement de contexte a été réalisé.
- K_MK_ERROR_ISR : le changement de contexte n'a pas été réalisé car cette fonction a été exécutée depuis un vecteur d'interruption.
Note :
- Cette fonction ne peut pas être exécutée dans un vecteur d'interruption.
- Si aucune tâche de priorité identique à la tâche courante n'existe alors la tâche courante reprend son exécution.
3.6. La fonction mk_task_sleep()
Cette fonction stoppe l'exécution de la tâche courante pendant une durée définie. Le tick de réveil est calculé en ajoutant la durée « p_mkTick » au tick courant du noyau.
Prototype :
T_mkCode mk_task_sleep ( uint32_t p_mkTick );
Paramètres :
- p_mkTick [in]
Durée de la temporisation [en multiple de tick]. Il peut prendre les valeurs [1 à 0xFFFFFFFF].
Retour :
- K_MK_OK : la temporisation a été réalisée.
- K_MK_ERROR_PARAM : la temporisation n'a pas été réalisée car la valeur du paramètre « p_mkTick » est nulle.
- K_MK_ERROR_ISR : la temporisation n'a pas été réalisée car cette fonction a été exécutée depuis un vecteur d'interruption.
Note :
- Cette fonction ne peut pas être exécutée dans un vecteur d'interruption.
- Si une tâche plus prioritaire préempte la tâche courante, celle-ci reprendra son exécution après un délai au moins égal à la durée spécifiée, lorsque les tâches de priorité supérieure ou égale auront terminé leur exécution.
3.7. La fonction mk_task_delay()
Cette fonction stoppe l'exécution de la tâche courante pendant une durée relative au tick de référence.
Le tick de réveil est calculé en ajoutant la durée « p_mkTick » au tick de référence de la tâche. Si ce tick de réveil est déjà dépassé au moment de l'appel, la tâche n'est pas temporisée et son tick de référence est immédiatement actualisé à la valeur courante du compteur de ticks du noyau. Dans le cas contraire, la tâche est placée dans la liste des tâches temporisées jusqu'à ce tick de réveil.
Le tick de référence d'une tâche est initialement nul.
Prototype :
T_mkCode mk_task_delay ( uint32_t p_mkTick );
Paramètres :
- p_mkTick [in]
Durée de la temporisation [en multiple de tick]. Il peut prendre les valeurs [1 à 0xFFFFFFFF].
Retour :
- K_MK_OK : la temporisation a été réalisée.
- K_MK_ERROR_PARAM : la temporisation n'a pas été réalisée car la valeur du paramètre « p_mkTick » est nulle.
- K_MK_ERROR_ISR : la temporisation n'a pas été réalisée car cette fonction a été exécutée depuis un vecteur d'interruption.
Note :
- Cette fonction ne peut pas être exécutée dans un vecteur d'interruption.
- Si une tâche plus prioritaire préempte la tâche courante, celle-ci reprendra son exécution après un délai au moins égal à la durée spécifiée, lorsque les tâches de priorité supérieure ou égale auront terminé leur exécution.
3.8. La fonction mk_task_resume()
Cette fonction redémarre une tâche suspendue.
Prototype :
T_mkCode mk_task_resume ( T_mkTask* p_mkTask );
Paramètres :
- p_mkTask [in]
Adresse de la tâche à redémarrer.
Retour :
- K_MK_OK : la tâche a été redémarrée.
- K_MK_ERROR_PARAM : la tâche n'a pas été redémarrée car le
paramètre est invalide ou car l'état de la tâche à redémarrer n'est pas l'état K_MK_
STATE_ .SUSPENDED - K_MK_ERROR_RIGHT : la tâche n'a pas été redémarrée car une tâche de type non privilégié ne peut pas redémarrer une tâche privilégiée.
Note :
- Une tâche peut être suspendue avec la fonction mk_task_suspend.
Attention :
⚠️
- Cette fonction entre dans une section critique lors de son exécution. Elle masque temporairement les interruptions de priorité numérique supérieure ou égale à K_MK_SCHEDULER_MASK_PRIORITY. Le masque est automatiquement levé avant d'en sortir.
3.9. La fonction mk_task_suspend()
Cette fonction suspend une tâche.
Prototype :
T_mkCode mk_task_suspend ( T_mkTask* p_mkTask );
Paramètres :
- p_mkTask [in]
Adresse de la tâche à suspendre. Il peut prendre la valeur K_MK_NULL pour désigner la tâche courante.
Retour :
- K_MK_OK : la tâche a été suspendue.
- K_MK_ERROR_PARAM : la tâche n'a pas été suspendue car l'état de la tâche à suspendre est K_MK_STATE_SUSPENDED ou K_MK_STATE_DELETED.
- K_MK_ERROR_RIGHT : la tâche n'a pas été suspendue car une tâche de type non privilégié ne peut pas suspendre une tâche privilégiée.
Note :
- Une tâche peut être redémarrée avec la fonction mk_task_resume.
Attention :
⚠️
- Cette fonction entre dans une section critique lors de son exécution. Elle masque temporairement les interruptions de priorité numérique supérieure ou égale à K_MK_SCHEDULER_MASK_PRIORITY. Le masque est automatiquement levé avant d'en sortir.
3.10. La fonction mk_task_priority()
Cette fonction modifie la priorité d'une tâche.
Prototype :
T_mkCode mk_task_priority ( T_mkTask* p_mkTask, uint32_t p_mkPriority );
Paramètres :
- p_mkTask [in]
Adresse de la tâche dont la priorité doit être modifiée. Il peut prendre la valeur K_MK_NULL pour désigner la tâche courante.
- p_mkPriority [in]
Nouvelle valeur de priorité. La valeur de priorité peut évoluer de 1 à K_MK_SCHEDULER_PRIORITY_NUMBER (la plus élevée).
Retour :
- K_MK_OK : la priorité de la tâche a été modifiée.
- K_MK_ERROR_PARAM : la priorité de la tâche n'a pas été modifiée car au moins un paramètre est invalide ou la tâche est dans un état invalide.
- K_MK_ERROR_RIGHT : la priorité de la tâche n'a pas été modifiée car une tâche de type non privilégié ne peut pas modifier une tâche privilégiée.
Note :
-
La priorité d'une tâche peut être modifiée
si elle se situe dans l'état K_MK_
STATE_ , K_MK_READY STATE_ ou K_MK_DELAYED STATE_ .SUSPENDED - La priorité d'une tâche possédant un objet de synchronisation de type T_mkMutex ne peut pas être modifiée.
Attention :
⚠️
- Cette fonction entre dans une section critique lors de son exécution. Elle masque temporairement les interruptions de priorité numérique supérieure ou égale à K_MK_SCHEDULER_MASK_PRIORITY. Le masque est automatiquement levé avant d'en sortir.
3.11. La fonction mk_task_getHandle()
Cette fonction récupère l'adresse d'une tâche à partir de son identifiant.
Prototype :
T_mkCode mk_task_getHandle ( T_mkTask** p_mkTask, uint32_t p_mkIdentifier );
Paramètres :
- p_mkTask [out]
Adresse d'une tâche de type T_mkTask.
- p_mkIdentifier [in]
Identifiant de la tâche dont l'adresse doit être récupérée.
Retour :
- K_MK_OK : l'adresse de la tâche a été récupérée.
- K_MK_ERROR_PARAM : l'adresse de la tâche n'a pas été récupérée car le paramètre « p_mkTask » est invalide.
- K_MK_ERROR_ISR : l'adresse de la tâche n'a pas été récupérée car cette fonction a été exécutée depuis un vecteur d'interruption.
- K_MK_ERROR_NOT_AVAILABLE : l'adresse de la tâche n'a pas été récupérée car aucune tâche possédant cet identifiant n'existe.
Note :
- Cette fonction ne peut pas être exécutée dans un vecteur d'interruption.
- L'adresse de la tâche de repos et de la tâche principale ne peut pas être récupérée en utilisant cette fonction.
- Lorsque deux tâches possèdent le même identifiant, l'adresse de la première tâche trouvée est renvoyée.
3.12. La fonction mk_task_get()
Cette fonction récupère l'identifiant, le type, l'état ou la priorité d'une tâche à partir de son adresse.
Prototype :
T_mkCode mk_task_get ( T_mkTask* p_mkTask, uint32_t* p_mkAttribute, uint32_t p_mkOffset );
Paramètres :
- p_mkTask [in]
Adresse d'une tâche de type T_mkTask.
- p_mkAttribute [out]
Valeur de l'attribut récupéré.
- p_mkOffset [in]
Offset de l'attribut qui doit être récupéré. Les constantes suivantes peuvent être utilisées :
- K_MK_ID : offset de l'attribut id.
- K_MK_TYPE : offset de l'attribut type.
- K_MK_STATE : offset de l'attribut state.
- K_MK_PRIORITY : offset de l'attribut priority.
- K_MK_CURRENT_PRIORITY : offset de l'attribut currentPriority.
Retour :
- K_MK_OK : l'attribut a été récupéré.
- K_MK_ERROR_PARAM : l'attribut n'a pas été récupéré car au moins un paramètre est invalide.
- K_MK_ERROR_ISR : l'attribut n'a pas été récupéré car cette fonction a été exécutée depuis un vecteur d'interruption.
Note :
- Cette fonction ne peut pas être exécutée dans un vecteur d'interruption.
3.13. La fonction mk_task_getLoad()
Cette fonction récupère le taux de charge CPU d'une tâche.
Prototype :
T_mkCode mk_task_getLoad ( T_mkTask* p_mkTask, uint32_t* p_mkTaskLoad );
Paramètres :
- p_mkTask [in]
Adresse de la tâche dont le taux de charge doit être récupéré.
- p_mkTaskLoad [out]
Valeur du taux de charge CPU de la tâche (en pourcentage).
Retour :
- K_MK_OK : le taux de charge CPU de la tâche a été récupéré.
- K_MK_ERROR_PARAM : le taux de charge CPU de la tâche n'a pas été récupéré car au moins un paramètre est invalide.
- K_MK_ERROR_ISR : le taux de charge CPU de la tâche n'a pas été récupéré car cette fonction a été exécutée depuis un vecteur d'interruption.
- K_MK_ERROR_RIGHT : le taux de charge n'a pas été récupéré car une tâche de type non privilégié ne peut pas exécuter cette fonction.
Attention :
⚠️
- Cette fonction entre dans une section critique lors de son exécution. Elle masque temporairement les interruptions de priorité numérique supérieure ou égale à K_MK_SCHEDULER_MASK_PRIORITY. Le masque est automatiquement levé avant d'en sortir.
3.14. Les définitions
Le module task peut être configuré à l'aide des définitions suivantes :
| Définition | Description | Valeur |
|---|---|---|
| K_MK_ |
Cette constante définit le nombre de tâches pouvant être allouées. Elle ne peut pas être nulle. | 32 |
✔ L'identifiant de la tâche est un entier non-signé sur 32 bits. Il est préférable d'utiliser un identifiant unique pour chaque tâche.
✔ La priorité de la tâche évolue de 1 à K_MK_SCHEDULER_PRIORITY_NUMBER (la
plus forte).
✔ Le type de la tâche peut être privilégié, flottant ou les deux. Il se sélectionne en utilisant les constantes K_MK_TYPE_PRIVILEGED , K_MK_TYPE_FLOATING ou K_MK_TYPE_FLOATING_PRIVILEGED .
✔ Le propriétaire de la tâche contient l'adresse d'une application ou d'une tâche "mère" ou à défaut la valeur K_MK_NULL. Lorsqu'un propriétaire est spécifié, chaque nouvelle tâche créée par la tâche "mère" hérite de la valeur de cet argument. Toutes les tâches d'une même application peuvent alors être identifiées. Pour les tâches enfants, ce paramètre devient alors sans effet car elles héritent du propriétaire de leur parent.