Sur sa page Web sur l' astuce du self-pipe , Dan Bernstein explique une condition de course avec select()
et signale, propose une solution de contournement et conclut que
Bien sûr, la bonne chose serait d'avoir
fork()
renvoyé un descripteur de fichier, pas un ID de processus.
Que veut-il dire par cela - s'agit-il de pouvoir select()
sur des processus enfants gérer leurs changements d'état au lieu d'avoir à utiliser un gestionnaire de signaux pour être notifié de ces changements d'état?
signals
file-descriptors
fork
Lassi
la source
la source
signalfd
que ce soit une chose à l'époque?wait()
, il y avait des choses que vous ne pouviez pas faire, alors quelqu'un a inventé SIGCHLD, mais c'était un mauvais travail. Dans mon expérience, et maintenant qu'ils existent, aspergeant agréable, non bloquantewait3()
,wait4()
et / ou deswaitpid()
appels à des endroits clés (peut - être votre boucle d'événement) est une alternative nettement supérieure.Réponses:
Le problème est décrit ici dans votre source,
select()
devrait être interrompu par des signaux commeSIGCHLD
, mais dans certains cas, cela ne fonctionne pas bien. La solution de contournement consiste donc à écrire le signal sur un canal, qui est ensuite surveillé parselect()
. Regarder les descripteurs de fichiers est à quoi celaselect()
sert, donc cela contourne le problème.La solution de contournement transforme essentiellement l'événement de signal en un événement de descripteur de fichier. Si
fork()
juste retourné un fd en premier lieu, la solution de contournement ne serait pas nécessaire, car ce fd pourrait alors vraisemblablement être utilisé directement avecselect()
.Alors oui, votre description dans le dernier paragraphe me semble juste.
Une autre raison pour laquelle un fd (ou un autre type de descripteur de noyau) serait préférable à un numéro d'identification de processus simple, est que les PID peuvent être réutilisés après la fin du processus. Cela peut être un problème dans certains cas lors de l'envoi de signaux aux processus, il peut ne pas être possible de savoir avec certitude que le processus est celui que vous pensez être, et pas un autre réutilisant le même PID. (Bien que je pense que cela ne devrait pas être un problème lors de l'envoi de signaux à un processus enfant, car le parent doit s'exécuter
wait()
sur l'enfant pour que son PID soit publié.)la source
wait()
.clone
, qui est l'appel système réel que fork appelle sur LInux. Le drapeau pour l'activer est appeléCLONE_PIDFD
- Voir par exemple lwn.net/Articles/784831 .C'est juste une réflexion sur les lignes de «ce serait génial si Unix était conçu différemment».
Le problème avec les PID est qu'ils vivent dans un espace de noms global où ils pourraient être réutilisés pour un autre processus, et ce serait bien s'ils étaient
fork()
retournés au parent une sorte de handle qui serait garanti de toujours se référer au processus enfant, et qu'il pourrait passer à d'autres processus via l'héritage ou les sockets unix /SCM_RIGHTS
[1].Voir également la discussion ici pour un effort récent pour "corriger" cela sous Linux, y compris l'ajout d'un indicateur
clone()
auquel il retournera un pid-fd au lieu d'un PID.Mais même dans ce cas, cela n'éliminerait pas la nécessité de ce hack auto-pipe [2] ou de meilleures interfaces, car les signaux notifiant un processus parent de l'état d'un enfant ne sont pas les seuls que vous souhaitez gérer dans la boucle principale. du programme. Malheureusement, des choses comme
epoll(7) + signalfd(2)
Linux oukqueue(2)
BSD ne sont pas standard - la seule interface standard (mais non prise en charge sur les anciens systèmes) est la bien inférieurepselect(2)
.[1] Empêcher le PID d'être recyclé au moment où l'
waitpid()
appel système est revenu et sa valeur de retour a été utilisée pourrait probablement être atteint sur les systèmes plus récents en utilisant à lawaitid(.., WNOWAIT)
place.[2] Je ne commenterais pas l'affirmation de DJ Bernstein qu'il l'a inventé (désolé pour l'apophasie ;-)).
la source
Bernstein ne donne pas beaucoup de contexte pour cette remarque "Right Thing", mais je vais hasarder une supposition: avoir fork (2) retourner un PID est incompatible avec open (2), creat (2) etc renvoyant des descripteurs de fichier. Le reste du système Unix aurait pu effectuer une manipulation de processus avec un descripteur de fichier représentant un processus, au lieu d'un PID. Il existe un appel système signalfd (2) , qui permet une interaction un peu meilleure entre les signaux et les descripteurs de fichier, et montre qu'un descripteur de fichier représentant un processus pourrait fonctionner.
la source
pidfd_open
Linux, voir par exemple lwn.net/Articles/789023