Maison > Article > Tutoriel système > Artefact sous Linux : principes et applications d'eventfd
Linux est un système d'exploitation puissant qui fournit de nombreux mécanismes de communication inter-processus efficaces, tels que des tuyaux, des signaux, des files d'attente de messages, une mémoire partagée, etc. Mais existe-t-il un moyen de communication plus simple, plus flexible et plus efficace ? La réponse est oui, c'est eventfd. eventfd est un appel système introduit dans Linux version 2.6. Il peut être utilisé pour implémenter la notification d'événements, c'est-à-dire pour transmettre des événements via un descripteur de fichier. eventfd contient un compteur entier non signé de 64 bits géré par le noyau. Le processus peut lire/modifier la valeur du compteur en lisant/écrivant ce descripteur de fichier pour établir une communication inter-processus. Quels sont les avantages d’eventfd ? Il présente les fonctionnalités suivantes :
Alors, comment fonctionne eventfd ? De quels scénarios d'application dispose-t-il ? Cet article présentera l'artefact eventfd sous deux aspects : le principe et l'application.
De manière générale : il existe cinq solutions principales pour la communication inter-processus Linux : les canaux, les files d'attente de messages, les sémaphores, la mémoire partagée et les sockets.
Je ne connais pas très bien les tubes. Je ne connais que les limites des tubes généraux et la relation entre les processus parent et enfant, car ce que je veux faire, c'est une communication indépendante entre les processus. limité aux processus parents et enfants, mais dans l'état du noyau. Je ne sais pas comment l'utiliser.
Je ne comprends pas du tout Message Queue.
Le cœur du sémaphore est une opération atomique des variables du noyau, mais l'interface ne se reflète que dans l'état de l'utilisateur, et le fonctionnement PV du sémaphore semble être davantage une exclusion mutuelle que le mécanisme de réveil de notification que je souhaite .
La mémoire partagée est encore plus gênante. L'interface est uniquement en mode utilisateur. Si vous souhaitez partager la mémoire entre le mode noyau et le mode utilisateur, vous devez écrire le fichier vous-même puis fournir l'interface mmap.
Les sockets n'ont été utilisés auparavant qu'avec tcp/udp d'af_inet et dgram d'af_unix. Le problème est toujours le même. Le noyau ne fournit pas d'interface claire, bien que vous puissiez l'appeler vous-même en utilisant des fonctions telles que sock->ops->recvmsg. Après tout, vous devez construire vous-même les paramètres d’entrée, ce qui semble toujours dangereux.
La seule chose qui reste semble être netlink. Ce socket fournit clairement la fonction d'envoi de paquets du noyau, car il exporte clairement la fonction netlink_kernel_create, donc la fonction d'état du noyau peut utiliser cette sock pour envoyer des paquets. Mais l'une est que le mode utilisateur doit enregistrer une fonction de réception de paquets, et l'autre est que le mode noyau doit toujours assembler skb pour envoyer des paquets. C'est encore trop compliqué pour moi qui veux simplement me réveiller par notification.
J'ai donc cherché à nouveau et trouvé l'artefact eventfd. Entre la communication entre KVM et Qemu, eventfd a été superbement utilisé par Daniel. Après avoir soigneusement analysé le code source, j'ai trouvé que cette chose est comme son nom l'indique, uniquement pour les notifications existantes. .
En tant que fichier (y a-t-il quelque chose dans Linux qui n'est pas un fichier ~~), sa structure private_data eventfd_ctx n'a que quatre variables pitoyables.
struct eventfd_ctx { struct kref kref; /* 这个就不多说了,file计数用的,用于get/put */ wait_queue_head_t wqh; /* 这个用来存放用户态的进程wait项,有了它通知机制才成为可能 */ /* \* Every time that a write(2) is performed on an eventfd, the \* value of the __u64 being written is added to "count" and a \* wakeup is performed on "wqh". A read(2) will return the "count" \* value to userspace, and will reset "count" to zero. The kernel \* side eventfd_signal() also, adds to the "count" counter and \* issue a wakeup. */ __u64 count; /* 这个就是一个技术器,应用程序可以自己看着办,read就是取出然后清空,write就是把value加上 */ unsigned int flags; /* 所有的file都有的吧,用来存放阻塞/非阻塞标识或是O_CLOEXEC之类的东西 */ }; 我之所以选用它是因为它有 eventfd_signal 这个特地为内核态提供的接口,下面的是注释。 \* This function is supposed to be called by the kernel in paths that do not \* allow sleeping. In this function we allow the counter to reach the ULLONG_MAX \* value, and we signal this as overflow condition by returining a POLLERR to poll(2).
En fait, ce sera plus clair si vous regardez le code
int eventfd_signal(struct eventfd_ctx *ctx, int n) { unsigned long flags; if (n return -EINVAL; spin_lock_irqsave(&ctx->wqh.lock, flags); if (ULLONG_MAX - ctx->count count); ctx->count += n; if (waitqueue_active(&ctx->wqh)) wake_up_locked_poll(&ctx->wqh, POLLIN); spin_unlock_irqrestore(&ctx->wqh.lock, flags); return n; }
L'essence est de se réveiller une fois, sans lire ni écrire. La différence avec eventfd_write est qu'il n'y a pas de blocage
.Voici mon utilisation spécifique :
L'état du noyau est un module qui enregistre un périphérique divers et crée un thread de noyau pour fonctionner (le paramètre est le fichier->private_data du module). Fournissez une interface ioctl pour que le processus en mode utilisateur fournisse le fd créé par son propre eventfd et enregistrez-le dans file->private_data accessible par le thread du noyau.
Lorsque l'état du noyau veut notifier l'état de l'utilisateur, eventfd_signal est utilisé directement. À ce stade, le thread de l'état de l'utilisateur doit d'abord se placer sur eventfd_ctx->wqh. Il existe deux solutions, l'une consiste à appeler read et l'autre. pour appeler un sondage. S'il s'agit d'une lecture, eventfd_ctx->count sera effacé plus tard et il pourra être bloqué la prochaine fois. Cependant, si poll est utilisé, le décompte n'est pas effacé par la suite, ce qui entraîne le retour immédiat du sondage même s'il n'y a pas de signal eventfd_signal dans l'état du noyau lors d'une nouvelle interrogation.
Il est un peu plus difficile de notifier l'état du noyau à partir de l'état de l'utilisateur. Tout d'abord, vous devez créer un eventfd puis l'envoyer à file->private_data (l'opération ici est la même que ci-dessus). créez un iotcl dans le module, qui est responsable de l'état de l'utilisateur pour notifier l'état du noyau. , eventfd_signal est effectué dans la fonction. Le thread d'état du noyau doit d'abord être placé sur eventfd_ctx->wqh. un sondage dans l'état du noyau vous-même (cela semble encore une fois gênant).
Cet article présente eventfd, un artefact sous Linux. Il s'agit d'un mécanisme de communication inter-processus simple, flexible et efficace. Nous avons analysé la création, la lecture et l'écriture, ainsi que les bits d'indicateur de eventfd sous l'aspect principal, et avons donné des exemples de code correspondants. Nous avons également introduit l'utilisation de eventfd dans des scénarios tels que la communication en mode utilisateur et en mode noyau, les minuteries et les déclencheurs d'événements du point de vue de l'application, et avons donné des exemples de code correspondants. Grâce à l'étude de cet article, nous pouvons maîtriser l'utilisation de base d'eventfd et utiliser de manière flexible eventfd dans le développement réel pour répondre à différents besoins de communication. J'espère que cet article vous sera utile !
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!