Maison > Article > Tutoriel système > Discussion approfondie sur les principes de mise en œuvre et les technologies associées du processus de suspension/reprise du noyau Linux
Dans le noyau Linux, le processus de suspension/reprise est un processus très important. Il peut réaliser la mise en veille et le réveil du système et améliorer l'efficacité énergétique et la vitesse de réponse du système. Dans cet article, nous approfondirons les principes de mise en œuvre et les technologies associées du processus de suspension/reprise du noyau Linux.
La veille prolongée/réveil est un élément très important dans Linux embarqué. Les appareils embarqués doivent entrer en état de veille autant que possible pour prolonger la durée de vie de la batterie. Cet article présentera en détail le fonctionnement de la veille/réveil sous Linux
.Article de référence : Auteur : zhangjiejing
Ma version du noyau Linux : 3.0.31
Une brève introduction à l'hibernation
Sous Linux, l'hibernation est divisée en trois étapes principales :
1. Geler les processus en mode utilisateur et les tâches en mode noyau
2. Appelez la fonction de rappel de suspension de l'appareil enregistré
3. La commande est conforme à l'ordre d'inscription
Mettre les périphériques principaux en veille prolongée et mettre le processeur en veille prolongée signifie que le noyau définit l'état de tous les processus de la liste des processus sur arrêté et enregistre le contexte de tous les processus. Lorsque ces processus sont dégelés, ils ne savent pas qu'ils le sont. étant S'il est gelé, il continue simplement à s'exécuter. Comment faire passer Linux en hibernation ? Les utilisateurs peuvent contrôler le système pour qu'il entre en hibernation en lisant et en écrivant le fichier sys /sys /power/state Par exemple
.# echo mem > /sys/power/state
Commande au système de s'endormir. Peut également être utilisé
.# chat /sys/power/state
Pour savoir quels modes de veille sont pris en charge par le noyau.
Processus de suspension Linux
Documents associés :
Vous pouvez obtenir le code source en visitant le site du noyau Linux, voici le chemin d'accès au fichier :
kernel/kernel/power/main.c kernel/kernel/power/suspend.c kernel/driver/base/power/main.c
Regardons de plus près comment Linux se met en veille/réveil. Voyons comment cela se produit.
La lecture et l'écriture par les utilisateurs de /sys/power/state appelleront state_store() dans main.c. Les utilisateurs peuvent écrire des chaînes définies dans const char * const pm_state[], telles que "mem", "standby". il est généralement contrôlé par les boutons de suspension et de reprise
Ensuite, state_store() appellera enter_state(), qui vérifiera d'abord certains paramètres d'état puis synchronisera le système de fichiers :
1. /** 2. \* enter_state - Do common work of entering low-power state. 3. \* @state: pm_state structure for state we're entering. 4. \* 5. \* Make sure we're the only ones trying to enter a sleep state. Fail 6. \* if someone has beat us to it, since we don't want anything weird to 7. \* happen when we wake up. 8. \* Then, do the setup for suspend, enter the state, and cleaup (after 9. \* we've woken up). 10. */ 11. int enter_state(suspend_state_t state) 12. { 13. int error; 14. 15. if (!valid_state(state)) 16. return -ENODEV; 17. 18. if (!mutex_trylock(&pm_mutex)) 19. return -EBUSY; 20. 21. printk(KERN_INFO "PM: Syncing filesystems ... "); 22. sys_sync(); 23. printk("done.\n"); 24. 25. pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]); 26. error = suspend_prepare(); 27. if (error) 28. goto Unlock; 29. 30. if (suspend_test(TEST_FREEZER)) 31. goto Finish; 32. 33. pr_debug("PM: Entering %s sleep\n", pm_states[state]); 34. pm_restrict_gfp_mask(); 35. error = suspend_devices_and_enter(state); 36. pm_restore_gfp_mask(); 37. 38. Finish: 39. pr_debug("PM: Finishing wakeup.\n"); 40. suspend_finish(); 41. Unlock: 42. mutex_unlock(&pm_mutex); 43. return error; 44. }
Préparer, congeler le processus
Après avoir entré suspend_prepare(), il allouera un terminal virtuel pour suspendre pour produire des informations, puis diffusera une notification indiquant que le système souhaite entrer en suspension, fermera le processus d'assistance en mode utilisateur, puis appellera suspend_freeze_processes() dans l'ordre pour tout geler. processus. , l'état actuel de tous les processus sera enregistré ici. Certains processus peuvent refuser d'entrer dans l'état gelé. Lorsque de tels processus existent, le gel échouera et débloquera tous les processus. qui étaient juste congelés
.1. /** 2. \* suspend_prepare - Do prep work before entering low-power state. 3. \* 4. \* This is common code that is called for each state that we're entering. 5. \* Run suspend notifiers, allocate a console and stop all processes. 6. */ 7. static int suspend_prepare(void) 8. { 9. int error; 10. 11. if (!suspend_ops || !suspend_ops-**>**enter) 12. return -EPERM; 13. 14. pm_prepare_console(); 15. 16. error = pm_notifier_call_chain(PM_SUSPEND_PREPARE); 17. if (error) 18. goto Finish; 19. 20. error = usermodehelper_disable(); 21. if (error) 22. goto Finish; 23. 24. error = suspend_freeze_processes(); 25. if (!error) 26. return 0; 27. 28. suspend_thaw_processes(); 29. usermodehelper_enable(); 30. Finish: 31. pm_notifier_call_chain(PM_POST_SUSPEND); 32. pm_restore_console(); 33. return error; 34. }
Mettre les périphériques en veille
Maintenant, tous les processus (y compris workqueue/kthread) ont été arrêtés. Les caractères du mode noyau peuvent contenir certains sémaphores lorsqu'ils sont arrêtés, donc si vous déverrouillez le sémaphore dans le périphérique à ce moment, la mort peut survenir, alors soyez très prudent lors du verrouillage. /déverrouillage dans la fonction suspend() du périphérique. Il est recommandé de ne pas attendre le verrouillage dans suspend() lors de la conception. Et comme certains journaux ne peuvent pas être générés pendant la suspension, donc une fois qu'un problème survient, il est très difficile de déboguer.
Ensuite, le noyau essaiera de libérer de la mémoire ici.
Enfin, suspend_devices_and_enter() sera appelé pour mettre tous les périphériques en veille. Dans cette fonction, si la plateforme enregistre suspend_pos (généralement défini et enregistré dans la définition au niveau de la carte), suspend_ops->begin() sera appelé ici, et alors device_suspend()->dpm_suspend() dans driver/base/power/main.c sera appelé, et ils appelleront tour à tour le rappel suspend() du pilote pour mettre tous les appareils en veille.
Lorsque tous les appareils se mettent en veille, suspend_ops->prepare() sera appelé. Cette fonction effectue généralement un travail de préparation pour mettre la carte en veille. Ensuite, sous Linux, le processeur qui ne démarre pas dans les processeurs multicœurs sera mis en veille. off. , comme vous pouvez le voir dans les commentaires, c'est pour éviter la condition de concurrence provoquée par ces autres processeurs. Désormais, un seul processeur fonctionnera.
.suspend_ops est une opération de gestion de l'alimentation au niveau de la carte, généralement enregistrée dans le fichier arch/xxx/mach-xxx/pm.c.
Ensuite, suspend_enter() sera appelée. Cette fonction fermera l'irq arch, appellera device_power_down(), et elle appellera la fonction suspend_late(). Cette fonction est la dernière fonction appelée lorsque le système entre réellement en veille. effectué dans cette fonction. Vérification finale. Si la vérification est OK, mettez en veille tous les périphériques et bus du système et appelez suspend_pos->enter() pour mettre le processeur dans un état d'économie d'énergie. l'exécution du code s'arrête. Le voici
1. /** 2. \* suspend_devices_and_enter - suspend devices and enter the desired system 3. \* sleep state. 4. \* @state: state to enter 5. */ 6. int suspend_devices_and_enter(suspend_state_t state) 7. { 8. int error; 9. 10. if (!suspend_ops) 11. return -ENOSYS; 12. 13. trace_machine_suspend(state); 14. if (suspend_ops-**>**begin) { 15. error = suspend_ops-**>**begin(state); 16. if (error) 17. goto Close; 18. } 19. suspend_console(); 20. suspend_test_start(); 21. error = dpm_suspend_start(PMSG_SUSPEND); 22. if (error) { 23. printk(KERN_ERR "PM: Some devices failed to suspend\n"); 24. goto Recover_platform; 25. } 26. suspend_test_finish("suspend devices"); 27. if (suspend_test(TEST_DEVICES)) 28. goto Recover_platform; 29. 30. error = suspend_enter(state); 31. 32. Resume_devices: 33. suspend_test_start(); 34. dpm_resume_end(PMSG_RESUME); 35. suspend_test_finish("resume devices"); 36. resume_console(); 37. Close: 38. if (suspend_ops-**>**end) 39. suspend_ops-**>**end(); 40. trace_machine_suspend(PWR_EVENT_EXIT); 41. return error; 42. 43. Recover_platform: 44. if (suspend_ops-**>**recover) 45. suspend_ops-**>**recover(); 46. goto Resume_devices; 47. } RESUME
如果在休眠中系统被中断或者其他事件唤醒, 接下来的代码就会开始执行, 这个 唤醒的顺序是和休眠的循序相反的,所以系统设备和总线会首先唤醒,使能系统中 断, 使能休眠时候停止掉的非启动CPU, 以及调用suspend_ops->finish(), 而且 在suspend_devices_and_enter()函数中也会继续唤醒每个设备,使能虚拟终端, 最后调用 suspend_ops->end().
在返回到enter_state()函数中的, 当 suspend_devices_and_enter() 返回以后, 外设已经唤醒了, 但是进程和任务都还是冻结状态, 这里会调用suspend_finish()来解冻这些进程和任务, 而且发出Notify来表示系统已经从suspend状态退出, 唤醒终端.
到这里, 所有的休眠和唤醒就已经完毕了, 系统继续运行了.
总之,suspend/resume过程是Linux内核中不可或缺的一部分。它可以实现系统的休眠和唤醒,提高系统的能效和响应速度。希望本文能够帮助读者更好地理解Linux Kernel suspend/resume 过程的实现原理和相关技术。
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!