Je rencontre souvent la situation lors du développement, où j'exécute un fichier binaire, disons a.out
en arrière-plan car cela fait un travail long. Pendant ce temps, j'apporte des modifications au code C qui a produit a.out
et compilé à a.out
nouveau. Jusqu'à présent, je n'ai eu aucun problème avec cela. Le processus en cours d'exécution se a.out
poursuit normalement, ne se bloque jamais et exécute toujours l'ancien code à partir duquel il a démarré à l'origine.
Cependant, disons que a.out
c'était un énorme fichier, peut-être comparable à la taille de la RAM. Que se passerait-il dans ce cas? Et dites-le lié à un fichier d'objet partagé, libblas.so
et si je le modifiais libblas.so
pendant l'exécution? Ce qui se passerait?
Ma question principale est - le système d'exploitation garantit-il que lorsque j'exécute a.out
, le code d'origine fonctionnera toujours normalement, selon le binaire d' origine , quelle que soit la taille du binaire ou des .so
fichiers auxquels il est lié, même lorsque ceux-ci .o
et les .so
fichiers sont modifiés pendant Durée?
Je sais qu'il y a ces questions qui abordent des problèmes similaires: /programming/8506865/when-a-binary-file-runs-does-it-copy-its-entire-binary-data-into-memory -en-une fois Que se passe - t-il si vous modifiez un script pendant l'exécution? Comment est-il possible de faire une mise à jour en direct pendant l'exécution d'un programme?
Ce qui m'a aidé à comprendre un peu plus à ce sujet mais je ne pense pas qu'ils demandent exactement ce que je veux, ce qui est une règle générale pour les conséquences de la modification d'un binaire pendant l'exécution
if they are read-only copies of something already on disc (like an executable, or a shared object file), they just get de-allocated and are reloaded from their source
, donc j'ai l'impression que si votre binaire est énorme, alors si une partie de votre binaire sort de la RAM, mais est à nouveau nécessaire, il est "rechargé à partir de la source" - donc tout changement dans le.(s)o
fichier sera reflété pendant l'exécution. Mais bien sûr, j'ai peut-être mal compris - c'est pourquoi je pose cette question plus spécifiqueNo, it only loads the necessary pages into memory. This is demand paging.
j'avais en fait l'impression que ce que j'avais demandé ne pouvait pas être garanti.Réponses:
Alors que la question Stack Overflow semblait être suffisante au début, je comprends, d'après vos commentaires, pourquoi vous avez peut-être encore un doute à ce sujet. Pour moi, c'est exactement le genre de situation critique impliquée lorsque les deux sous-systèmes UNIX (processus et fichiers) communiquent.
Comme vous le savez peut-être, les systèmes UNIX sont généralement divisés en deux sous-systèmes: le sous-système de fichiers et le sous-système de processus. Maintenant, sauf indication contraire via un appel système, le noyau ne devrait pas avoir ces deux sous-systèmes interagissent l'un avec l'autre. Il existe cependant une exception: le chargement d'un fichier exécutable dans les régions de texte d' un processus . Bien sûr, on peut faire valoir que cette opération est également déclenchée par un appel système (
execve
), mais il est généralement connu que c'est le seul cas où le sous-système de processus fait une demande implicite au sous-système de fichiers.Parce que le sous-système de processus n'a naturellement aucun moyen de gérer les fichiers (sinon il ne servirait à rien de diviser le tout en deux), il doit utiliser tout ce que le sous-système de fichiers fournit pour accéder aux fichiers. Cela signifie également que le sous-système de processus est soumis à toute mesure prise par le sous-système de fichiers concernant l'édition / la suppression de fichiers. Sur ce point, je recommanderais de lire la réponse de Gilles à cette question U&L . Le reste de ma réponse est basé sur celle plus générale de Gilles.
La première chose à noter est qu'en interne, les fichiers ne sont accessibles que via des inodes . Si le noyau reçoit un chemin, sa première étape sera de le traduire en un inode à utiliser pour toutes les autres opérations. Lorsqu'un processus charge un exécutable en mémoire, il le fait via son inode, qui a été fourni par le sous-système de fichiers après la traduction d'un chemin. Les inodes peuvent être associés à plusieurs chemins (liens) et les programmes ne peuvent supprimer que des liens. Afin de supprimer un fichier et son inode, l'espace utilisateur doit supprimer tous les liens existants vers cet inode et s'assurer qu'il est complètement inutilisé. Lorsque ces conditions sont remplies, le noyau supprimera automatiquement le fichier du disque.
Si vous regardez la partie remplaçable des exécutables de la réponse de Gilles, vous verrez que selon la façon dont vous éditez / supprimez le fichier, le noyau réagira / s'adaptera différemment, toujours via un mécanisme implémenté dans le sous-système de fichiers.
ETXTBSY
). Aucune conséquence que ce soit.mv
opération est atomique. Cela nécessitera probablement l'utilisation de l'rename
appel système, et comme les processus ne peuvent pas être interrompus en mode noyau, rien ne peut interférer avec cette opération tant qu'elle n'est pas terminée (avec succès ou non). Encore une fois, il n'y a pas d'altération de l'inode de l'ancien fichier: un nouveau est créé et les processus déjà en cours n'en auront aucune connaissance, même s'il est associé à l'un des liens de l'ancien inode.Recompilation d'un fichier : lorsque vous utilisez
gcc
(et le comportement est probablement similaire pour de nombreux autres compilateurs), vous utilisez la stratégie 2. Vous pouvez le voir en exécutant l'unstrace
des processus de votre compilateur:stat
etlstat
.a.out
, son inode et son contenu restent sur le disque, tant qu'ils sont utilisés par des processus déjà en cours d'exécution.a.out
. Il s'agit d'un tout nouvel inode et de nouveaux contenus dont les processus déjà en cours ne se soucient pas.Maintenant, en ce qui concerne les bibliothèques partagées, le même comportement s'applique. Tant qu'un objet de bibliothèque est utilisé par un processus, il ne sera pas supprimé du disque, quelle que soit la façon dont vous modifiez ses liens. Chaque fois que quelque chose doit être chargé en mémoire, le noyau le fera via l'inode du fichier, et ignorera donc les modifications que vous avez apportées à ses liens (comme les associer à de nouveaux fichiers).
la source
df
pour calculer le nombre d'octets libres sur le disque est incorrect car il ne prend pas d'inodes qui tous les liens du système de fichiers supprimés ont-ils été pris en compte? Je devrais donc utiliserdf -i
? (C'est juste une curiosité technique, je n'ai pas vraiment besoin de connaître l'utilisation exacte du disque!)rm
oumv
lui en tant qu'inode au fichier d'origine n'est pas supprimé jusqu'à ce que tous les processus suppriment leur lien vers cet inode.df
inclus) ne peut obtenir d'informations sur l'inode. Les nouvelles informations que vous trouvez sont liées au nouveau fichier et au nouvel inode. Le point principal ici est que le sous-système de processus ne s'intéresse pas à ce problème, donc les notions de gestion de la mémoire (pagination de la demande, échange de processus, défauts de page, ...) sont complètement hors de propos. Il s'agit d'un problème de sous-système de fichiers et il est pris en charge par le sous-système de fichiers. Le sous-système de processus ne se soucie pas de cela, ce n'est pas pour cela qu'il est là.df -i
: cet outil récupère probablement des informations du superbloc fs, ou de son cache, ce qui signifie qu'il peut inclure l'inode de l'ancien binaire (pour lequel tous les liens ont été supprimés). Cela ne signifie pas pour autant que les nouveaux processus sont libres d'utiliser ces anciennes données.Ma compréhension est qu'en raison du mappage de la mémoire d'un processus en cours, le noyau ne permettrait pas de mettre à jour une partie réservée du fichier mappé. Je suppose que dans le cas où un processus est en cours d'exécution, tout son fichier est réservé, ce qui le met à jour car vous avez compilé une nouvelle version de votre source entraîne en fait la création d'un nouvel ensemble d'inodes. En bref, les anciennes versions de votre exécutable restent accessibles sur le disque via des événements de défaut de page. Ainsi, même si vous mettez à jour un énorme fichier, il doit rester accessible et le noyau doit toujours voir la version intacte aussi longtemps que le processus est en cours d'exécution. Les inodes du fichier d'origine ne doivent pas être réutilisés tant que le processus est en cours d'exécution.
Cela doit bien sûr être confirmé.
la source
Ce n'est pas toujours le cas lors du remplacement d'un fichier .jar. Les ressources Jar et certains chargeurs de classe de réflexion d'exécution ne sont pas lus à partir du disque tant que le programme ne demande pas explicitement les informations.
Ce n'est qu'un problème car un jar est simplement une archive plutôt qu'un seul exécutable qui est mappé en mémoire. C'est un peu décalé mais c'est toujours une ramification de votre question et quelque chose avec laquelle je me suis tiré une balle dans le pied.
Donc pour les exécutables: oui. Pour les fichiers jar: peut-être (selon l'implémentation).
la source