IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

Appel system poll()


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre très actif
    Homme Profil pro
    Inscrit en
    Août 2013
    Messages
    274
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Août 2013
    Messages : 274
    Par défaut Appel system poll()
    Bonjour à tous,

    voila je cherche a tester une boucle d'evenement par curiosité sur le fonctionnement de ce dernier. J'ai donc fait ce code pour tester :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <poll.h>
     
    #define FD_COUNT 2
    #define TUBE_COUNT 2
     
    int main(int argc, char *argv[])
    {	
     
    	struct pollfd fds[FD_COUNT];
    	int timeout = -1;
    	char buffer[6];
     
    	for (int i = 0; i < FD_COUNT; ++i)
    	{
    		fds[i].events = POLLIN;
    	}
     
    	int tube[TUBE_COUNT][2];
     
    	for (int i = 0; i < TUBE_COUNT; ++i)
    	{
    		if(  pipe(tube[i]) < 0 )
    		{
    			printf("pipe : errno = %i\n", errno);
    		}
     
    		close(tube[i][1]);
    	}
     
    	if (mkfifo("pipeNamed1", 0666) < 0)
    	{
    		printf("pipeNamed : errno = %i\n", errno);
    	}
     
    	if (mkfifo("pipeNamed2", 0666) < 0)
    	{
    		printf("pipeNamed : errno = %i\n", errno);
    	}
     
    	int fd_open1 = open("pipeNamed1", O_RDONLY | O_NONBLOCK);
    	if ( fd_open1 < 0 )
    	{
    		printf("fd_open1 : errno = %i\n", errno);	
    	}
     
    	int fd_open2 = open("pipeNamed2", O_RDONLY | O_NONBLOCK);
    	if ( fd_open1 < 0 )
    	{
    		printf("fd_open2 : errno = %i\n", errno);	
    	}
     
     
    	fds[0].fd = fd_open1;
    	fds[1].fd = fd_open2;
     
    	printf("boucle :\n");
     
    	while(1)
    	{
    		int fd_ready = poll( fds, 2, timeout );
    		printf("fd_ready = %i\trevents = %i\n", fd_ready, 
    			fds[fd_ready -1].revents);
     
    		read(fds[fd_ready - 1].fd, buffer, 6 );
     
    		printf("buffer = %s\n", buffer);
    	}
    }
    une fois le programme lancé, l'appel systeme poll bloque mon programme (ce qui est le but voulu) puis je tape sur un terminal :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    echo "coucou" >pipeNamed1
    et la le texte suivant defile et poll n'est plus du tout bloquant :

    fd_ready = 1 revents = 16
    buffer =
    oucou
    fd_ready = 1 revents = 16
    buffer =
    oucou
    fd_ready = 1 revents = 16
    buffer =
    oucou



    Avez vous une idée du probleme ?

    Merci d'avance

  2. #2
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 832
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 832
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Je ne connais pas poll() (je suis en train de lire la doc). Mais ce que je vois, c'est que la valeur renvoyée ne donne pas le n° du fd qui a reçu un évènement mais le nombre de fd. Autrement dit, que tu écrives sur pipeNamed1 ou sur pipeNamed2, tu auras toujours le même retour (il faudrait écrire sur les deux en même temps pour avoir un retour à 2).
    Donc déjà ce n'est pas fds[rd_ready - 1] qu'il faut lire. Il te faut boucler sur tous les fds pour trouver celui qui a été invoqué (celui dont le "revents" n'est pas à 0)

    Ensuite je ne vois pas l'utilité de "tube" et accessoirement il manque dans ton code "errno.h" et "stdio.h"

    Sinon chez-moi aussi ça tourne. Je continue à chercher pourquoi. J'ai bien dans l'idée que le truc continue à détecter le "pipeNamed" comme ayant été ouvert mais je vois pas encore comment le réinitialiser (j'ai même tenté de mettre le remplissage de "events" dans le while sans succès). Tout ce que je remarque, c'est qu'au départ "revents" vaut 16 (POLLHUP) et qu'ensuite il vaut 17 (POLLHUP | POLLIN). Peut-être que "POLLIN" seul ne suffit pas dans "events"...

    [edit]
    Je commence à y voir plus clair suite à cet exemple. poll() n'attend pas qu'une écriture soit faite sur un descripteur, il attend que le descripteur soit devenu lisible (ce qui se passe quand tu écris dans un des deux pipe car tant que rien n'est écrit, ils sont non lisibles car bloqués).
    En remplaçant "namedPipe1" et "namedPipe2" par des fichiers du même nom, le truc ne bloque même plus du tout parce qu'un fichier est déjà lisible de nature. Sauf si je supprime le droit "r" avant de lancer le programme. Là le truc bloque définitivement.

    Enfin c'est ma théorie...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  3. #3
    Membre très actif
    Homme Profil pro
    Inscrit en
    Août 2013
    Messages
    274
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Août 2013
    Messages : 274
    Par défaut
    merci pour ta réponse,

    ca reste curieux car poll() est sensé se comporter comme select() et select() attend qu'un descripteur soit pret c'est a dire qu'il est possible d'effectuer un read par exemple. Or une fois le read lu, le descripteur est sensé ne plus etre pret et la fonction poll devrait etre bloquante.

    Je pense plus qu'il y a une erreur dans mon code et qu'on tombe dans un comportement incohérent mais je n'arrive pas a voir l'erreur

    Le probleme vient des tubes nommés.

    J'ai remplacé les tubes nommés par des tubes et ca marche, voici le code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>        
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <errno.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <poll.h>
     
    #define FD_COUNT 2
    #define TUBE_COUNT 2
     
    int main(int argc, char *argv[])
    {	
     
    	struct pollfd fds[FD_COUNT];
    	int timeout = -1;
    	char buffer[7];
     
    	for (int i = 0; i < FD_COUNT; ++i)
    	{
    		fds[i].events = POLLIN;
    	}
     
    	int tube[TUBE_COUNT][2];
     
    	for (int i = 0; i < TUBE_COUNT; ++i)
    	{
    		if(  pipe(tube[i]) < 0 )
    		{
    			printf("pipe : errno = %i\n", errno);
    		}
     
    		//close(tube[i][1]);
    	}
     
    	pid_t pid;
     
    	if (  (pid = fork() ) < 0 )
    	{
    		printf("fork : errno = %i\n", errno);
    	}
     
    	if(pid == 0)
    	{
    		//processus fils
    		sleep(5);
    		//printf("ecriture\n");
    		write( tube[0][1], "coucou", 6);
    		sleep(20);
    		write( tube[1][1], "bonjour", 6);
    	}
    	else
    	{
    		fds[0].fd = tube[0][0];
    		fds[1].fd = tube[1][0];
     
    		printf("boucle :\n");
     
    		while(1)
    		{
    			int fd_ready_count = poll( fds, 2, timeout );
     
    			if (fds[0].revents & POLLIN)
    			{
    				printf ("fds[0] is readable\n");
    				read( fds[0].fd, buffer, 6 );
    				printf("buffer = %s\n", buffer);
    			}
     
    			if (fds[1].revents & POLLIN)
    			{	
    				printf ("fds[1] is readable\n");
    				read( fds[1].fd, buffer, 6 );
    				printf("buffer = %s\n", buffer);
    			}
     
    			printf("ready_count = %i\n", fd_ready_count);
    			sleep(1);
    		}
    	}
     
     
    }
    je regarde pourquoi il y a des erreurs avec les tubes nommés

  4. #4
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 832
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 832
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par cosmoff Voir le message
    J'ai remplacé les tubes nommés par des tubes et ca marche, voici le code :
    Exact, c'est bon.
    Il te manque juste la fermeture des cotés inutilisés. En effet, dans une comm père/fils via tube, le tube est ouvert avant le fork(). Il s'ensuit que chaque processus père/fils reçoit les deux côtés du tube (le coté 0 pour la lecture et le coté 1 pour l'écriture).
    Il faut donc que chaque process ferme le côté qu'il n'utilise pas. Et dans ton cas il y a 2 tubes.

    Donc pour le fils
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    for (int i = 0; i < TUBE_COUNT; ++i)
    	close(tube[i][STDIN_FILENO]);

    Et pour le père
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    for (int i = 0; i < TUBE_COUNT; ++i)
    	close(tube[i][STDOUT_FILENO]);

    Citation Envoyé par cosmoff Voir le message
    je regarde pourquoi il y a des erreurs avec les tubes nommés
    Peut-être que poll() n'est pas fait pour gérer un truc qui vient du dehors...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  5. #5
    Membre très actif
    Avatar de sambia39
    Homme Profil pro
    No Comment
    Inscrit en
    Mai 2010
    Messages
    548
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : No Comment
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Mai 2010
    Messages : 548
    Par défaut
    Bonsoir,

    Citation Envoyé par Sve@r Voir le message
    Exact, c'est bon.
    Attention, le code source dit fonctionnel n’est absolument pas si fonctionnel que l’on pense et encore moins résolu. Dans le cas actuel, le programme génère un processus zombie, suite à la fin d’exécution du code du fils et dont le père n’a aucune connaissance puisqu’il ne lit pas le code du statut de terminaison du fils et de ce fait le processus fils restera indéfiniment dans un état zombie.

    Autre point : l’évaluation de la valeur retour de la fonction poll doit être évaluée ; car c’est elle qui donne le nombre de structures dont le champ revents est non-nul (événement ou erreur signalé(e) inscrit(e) par le noyau) et qui doit être testé pour prendre les mesures nécessaires en cas d’erreur ; et pour l’instant, ce n’est pas le cas. Sans compter que le test if (fds[1].revents & POLLIN) peut éventuellement être toujours vrai et les instructions/code qui viennent à la suite de cette évaluation seront alors exécutés (lecture du message « écrit dans les tubes anonymes ») malgré l’erreur survenue. Pire encore, si la fonction poll renvoie -1 due à une interruption provoquée par un signal ; la lecture du tube sera tout de même exécuté (vu que cette valeur est également ignoré).

    Au final, le code source fonctionne similairement comme des tubes bidirectionnels en apparence…

    à bientôt

  6. #6
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 832
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 832
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par sambia39 Voir le message
    Attention, le code source dit fonctionnel n’est absolument pas si fonctionnel que l’on pense et encore moins résolu. Dans le cas actuel, le programme génère un processus zombie, suite à la fin d’exécution du code du fils et dont le père n’a aucune connaissance puisqu’il ne lit pas le code du statut de terminaison du fils et de ce fait le processus fils restera indéfiniment dans un état zombie.
    J'ai dit "c'est bon" dans un cadre simpliste signifiant de façon plus détaillée "ok on a un résultat qui commence à correspondre à ce qu'on attend donc on peut maintenant continuer à examiner le fonctionnement". N'oublie pas que ça a été décrit initialement comme un programme permettant de regarder le fonctionnement de poll(), pas de la dernière version du code de surveillance d'une centrale nucléaire...

    Citation Envoyé par sambia39 Voir le message
    Autre point : l’évaluation de la valeur retour de la fonction poll doit être évaluée ; car c’est elle qui donne le nombre de structures dont le champ revents est non-nul (événement ou erreur signalé(e) inscrit(e) par le noyau) et qui doit être testé pour prendre les mesures nécessaires en cas d’erreur ; et pour l’instant, ce n’est pas le cas.
    Mëme remarque. Et j'avais parlé du retour dans ma phrase "Mais ce que je vois, c'est que la valeur renvoyée ne donne pas le n° du fd qui a reçu un évènement mais le nombre de fd"...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 3
    Dernier message: 15/11/2011, 15h00
  2. Probleme avec la fonction system(3)
    Par labrute dans le forum Linux
    Réponses: 3
    Dernier message: 02/06/2008, 15h06
  3. Problème avec les commandes systèmes
    Par ouakammathieu dans le forum Administration système
    Réponses: 8
    Dernier message: 27/05/2006, 15h06
  4. Problème avec l'heure système
    Par Oega dans le forum Administration système
    Réponses: 1
    Dernier message: 15/05/2006, 16h03
  5. bizarrerie avec l'appel system read sous linux.
    Par Hypnocrate dans le forum C
    Réponses: 20
    Dernier message: 20/11/2005, 02h47

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo