Maison  >  Article  >  Tutoriel système  >  Comprendre la pile du noyau du processus Linux

Comprendre la pile du noyau du processus Linux

PHPz
PHPzavant
2024-02-10 18:09:411301parcourir

Quand j'ai relu "LDD3", j'ai trouvé une phrase que j'avais ignorée : "Le noyau a une très petite pile, elle peut être aussi petite qu'une page de 4096 octets. En réponse à cette phrase, j'ai simplement." Découverte de la « pile de noyau » du processus.

Qu'est-ce que la « pile noyau » d'un processus ? Dans le cycle de vie de chaque processus, il sera inévitablement piégé dans le noyau via les appels système. Après avoir exécuté un appel système et intercepté dans le noyau, la pile utilisée par ces codes du noyau n'est pas la pile d'origine dans l'espace utilisateur, mais une pile dans l'espace du noyau, qui est la "pile du noyau" du processus.

Par exemple, un simple pilote de caractère implémente l'appel système open()方法。在这个驱动程序挂载后,应用程序通过glib库调用Linux的open(). Lorsqu'un appel système est exécuté et piégé dans le noyau, le processeur passe en mode privilégié (le mécanisme de transition spécifique varie en fonction de l'architecture du processeur. Par exemple, pour ARM, le pointeur de pile (SP) en mode normal et en mode utilisateur est un registre différent). À l'heure actuelle, le pointeur de pile utilisé est le pointeur de pile du noyau, qui pointe vers l'espace de pile du noyau alloué par le noyau pour chaque processus.

Le rôle de la pile du noyau Ma compréhension personnelle est la suivante : après être tombé dans le noyau, il existe également des appels de fonction et des variables automatiques dans les appels système, qui nécessitent la prise en charge de la pile. La pile de l'espace utilisateur est évidemment dangereuse et nécessite donc la prise en charge de la pile du noyau. De plus, la pile du noyau est également utilisée pour enregistrer certaines informations de la couche application avant les appels système (par exemple, le pointeur de la pile d'espace utilisateur et les paramètres d'appel système).

La relation entre la pile du noyau et la structure du processus Chaque processus obtiendra un espace de pile du noyau lors de sa création. La relation correspondante entre la pile du noyau et le processus est complétée par les membres pointeurs dans les deux structures : (1) struct task_struct Une structure qui doit être apprise lors de l'apprentissage de la gestion des processus Linux. Il représente un processus dans le noyau et enregistre toutes les informations d'état du processus. Cette structure est définie dans Sched.h (includelinux). Il existe une void *stack,它指向下面的内核栈结构体的“栈底”。 在系统运行时,宏current获得的是当前进程的struct task_structstructure de membres.

(2) Union de structure de pile de noyau thread_union

1. union thread_union {
2.   struct thread_info thread_info;
3.   unsigned long stack[THREAD_SIZE/sizeof(long)];
4. };

La struct thread_info est une structure qui enregistre une partie des informations sur le processus, y compris les informations sur le contexte du processus :

1. /*
2.  \* low level task data that entry.S needs immediate access to.
3.  \* __switch_to() assumes cpu_context follows immediately after cpu_domain.
4.  */
5. struct thread_info {
6.   unsigned long    flags;    /* low level flags */
7.   int      preempt_count;  /* 0 => preemptable,  bug */
8.   mm_segment_t    addr_limit;  /* address limit */
9.   struct task_struct  *task;    /* main task structure */
10.   struct exec_domain  *exec_domain;  /* execution domain */
11.   __u32      cpu;    /* cpu */
12.   __u32      cpu_domain;  /* cpu domain */
13.   struct cpu_context_save  cpu_context;  /* cpu context */
14.   __u32      syscall;  /* syscall number */
15.   __u8      used_cp[16];  /* thread used copro */
16.   unsigned long    tp_value;
17.   struct crunch_state  crunchstate;
18.   union fp_state    fpstate __attribute__((aligned(8)));
19.   union vfp_state    vfpstate;
20. \#ifdef CONFIG_ARM_THUMBEE
21.   unsigned long    thumbee_state;  /* ThumbEE Handler Base register */
22. \#endif
23.   struct restart_block  restart_block;
24. };

La clé est le membre de la tâche, qui pointe vers la structure struct task_struct du processus créé

Le membre de la pile est la pile du noyau. On peut voir d'ici que l'espace de la pile du noyau et thread_info partagent un espace. Si la pile du noyau déborde, thread_info sera détruit et le système plantera~~~

La relation entre la pile du noyau—struct thread_info—struct task_struct est illustrée dans la figure ci-dessous :

Comprendre la pile du noyau du processus Linux

Génération de la pile du noyau
Lorsqu'un processus est créé, l'appel système de la famille fork allouera respectivement de l'espace pour la pile du noyau et la struct task_struct :

Appels système de la famille Fork—>do_fork—>copy_process—>dup_task_struct

Dans la fonction dup_task_struct :

1. static struct task_struct *dup_task_struct(struct task_struct *orig)
2. {
3.   struct task_struct *tsk;
4.   struct thread_info *ti;
5.   unsigned long *stackend;
6.  
7.   int err;
8.  
9.   prepare_to_copy(orig);
10.  
11.   **tsk = alloc_task_struct();**
12.   if (!tsk)
13. ​    return NULL;
14.  
15.   **ti = alloc_thread_info(tsk);**
16.   if (!ti) {
17. ​    free_task_struct(tsk);
18. ​    return NULL;
19.   }
20.  
21.    err = arch_dup_task_struct(tsk, orig);
22.   if (err)
23. ​    goto out;
24.  
25.   **tsk->stack = ti;**
26.  
27.   err = prop_local_init_single(&tsk->dirties);
28.   if (err)
29. ​    goto out;
30.  
31.   **setup_thread_stack(tsk, orig);**
32. ......

 

Alloc_task_struct utilise l'allocateur de dalle du noyau pour allouer l'espace de struct task_struct pour le processus à créer
Alloc_thread_info utilise le système partenaire du noyau pour allouer de l'espace dans la pile du noyau (union thread_union) pour le processus à créer

Remarque : L'instruction tsk->stack = ti; après
est liée à la structure task_struct et à la pile du noyau
Dans setup_thread_stack(tsk, orig);, la pile du noyau et la struct task_struct sont associées :

1. static inline void setup_thread_stack(struct task_struct *p, struct task_struct *org)
2. {
3.   *task_thread_info(p) = *task_thread_info(org);
4.   task_thread_info(p)->task = p;
5. }

Taille de la pile du noyau
Étant donné que chaque processus se voit attribuer un espace de pile du noyau, il est impossible d'en allouer une grande quantité. Cette taille dépend de l'architecture et est généralement mesurée en pages. En fait, il s'agit du THREAD_SIZE que nous avons vu ci-dessus. Cette valeur est généralement 4K ou 8K. Pour l'architecture ARM, ceci est défini dans Thread_info.h (archarmincludeasm),

1. \#define THREAD_SIZE_ORDER  1
2. \#define THREAD_SIZE   8192
3. \#define THREAD_START_SP   (THREAD_SIZE - 8)

La pile du noyau d'ARM fait donc 8 Ko

Choses à noter lors de la programmation des pilotes (noyau) :
En raison de la limitation de l'espace de la pile, lors de l'écriture des pilotes (en particulier des fonctions de bas niveau utilisées par les appels système), il convient de veiller à éviter les codes qui consomment une grande quantité d'espace de pile, tels que les algorithmes récursifs, la taille des variables automatiques locales. définitions, etc.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer