Le processus est une abstraction de la logique Nous avons une grande compréhension du processus à partir des livres sur le système d'exploitation, mais nous ne savons peut-être pas grand-chose sur la mise en œuvre. du processus. , cet article tente d’expliquer les principes généraux de mise en œuvre du processus.
La mise en œuvre du processus est en fait la même que lorsque nous écrivons habituellement du code. Par exemple, si nous voulons représenter quelque chose, nous définirons une structure de données. Les processus ne font pas exception. L’essence d’un processus est donc une structure de données qui stocke une série de données. Le système d'exploitation gère tous les processus sous forme de tableaux ou de listes chaînées. On peut dire que les processus sont divisés en deux types
1 Le premier processus lorsque le système est initialisé,
2 À l'exception du premier processus, d'autres processus sont créés par fork ou fork+execute des appels système.
Jetons d'abord un coup d'œil aux informations contenues dans la structure du processus.
Lorsque le système crée un processus, la valeur du registre cs:ip sera définie s'il s'agit d'un. fork, puis ip C'est l'adresse IP de l'instruction après la fonction fork. S'il est exécuté, l'adresse IP est spécifiée par le compilateur. Quoi qu'il en soit, lorsque le processus commence à s'exécuter, le processeur analysera cs:ip et obtiendra une instruction à exécuter. Alors, comment cs:ip est-il analysé ?
Lorsque le processus est exécuté, le sélecteur tss (index GDT) est chargé dans le registre tss, puis le contexte en tss est également chargé dans le registre correspondant, tel que le sélecteur cr3, ldt. Selon l'index ldt dans les informations tss, recherchez d'abord la première adresse des données de structure ldt du processus à partir de GDT, puis obtenez le sélecteur de cs en fonction des attributs du segment actuel, tels que le segment de code, le système obtient le. première adresse de l'espace linéaire du processus de la table ldt Adresse, limite de longueur, autorisations et autres informations. Utilisez la première adresse de l'adresse linéaire plus le décalage dans l'IP pour obtenir l'adresse linéaire, puis obtenez l'adresse physique via le répertoire de pages et la table de pages. Si l'adresse physique n'a pas été allouée, les exceptions de défaut de page et d'autres traitements seront effectués. être effectué.
Suspension, blocage et processus multiples. Nous entendons généralement ces concepts assez souvent, voyons maintenant comment ils sont mis en œuvre. Il existe deux types de suspension ou de blocage du processus.
1 Suspendre activement. Laissez le processus se suspendre par intermittence pendant le sommeil. Le principe du sommeil a déjà été analysé, je ne l'analyserai donc pas à nouveau. Le principe général est de régler une minuterie et de réveiller le processus après expiration.
Modifiez le processus en état suspendu et attendez le réveil.
2 Suspension passive.
Il existe de nombreux scénarios de suspension passive. La raison principale est que le processus s'applique à une ressource, mais que la ressource ne remplit pas les conditions et que le processus est suspendu par le système d'exploitation. Par exemple, lorsque nous lisons une pipe. S'il n'y a aucune donnée à lire dans le canal, le processus est suspendu. Insérez-le dans la file d'attente du tuyau.
<code>// 当前进程挂载到睡眠队列p中,p指向队列头指针的地址<br>void sleep_on(struct task_struct **p)<br>{<br> struct task_struct *tmp;<br><br> if (!p)<br> return;<br> if (current == &(init_task.task))<br> panic("task[0] trying to sleep");<br> /*<br> *p为第一个睡眠节点的地址,即tmp指向第一个睡眠节点<br> 头指针指向当前进程,这个版本的实现没有采用真正链表的形式,<br> 他通过每个进程在栈中的临时变量形成一个链表,每个睡眠的进程,<br> 在栈里有一个变量指向后面一个睡眠节点,然后把链表的头指针指向当前进程,<br> 然后切换到其他进程执行,当被wake_up唤醒的时候,wake_up会唤醒链表的第一个<br> 睡眠节点,因为第一个节点里保存了后面一个节点的地址,所以他唤醒后面一个节点,<br> 后面一个节点以此类推,从而把整个链表的节点唤醒,这里的实现类似nginx的filter,<br> 即每个模块保存后面一个节点的地址,然后把全局指针指向自己。<br> */<br> tmp = *p;<br> *p = current;<br> // 不可中断睡眠只能通过wake_up唤醒,即使有信号也无法唤醒<br> current->state = TASK_UNINTERRUPTIBLE;<br> // 进程调度<br> schedule();<br> // 唤醒后面一个节点<br> if (tmp)<br> tmp->state=0;<br>}<br><br>// 唤醒队列中的第一个节点,并清空链表,因为第一个节点会向后唤醒其他节点<br>void wake_up(struct task_struct **p)<br>{<br> if (p && *p) {<br> (**p).state=0;<br> *p=NULL;<br> }<br>}</code>
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!