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 :

[Linux][message queues] BUG incompréhensible


Sujet :

C

  1. #1
    Membre averti

    Homme Profil pro
    Enseignant
    Inscrit en
    Septembre 2012
    Messages
    313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Septembre 2012
    Messages : 313
    Points : 354
    Points
    354
    Par défaut [Linux][message queues] BUG incompréhensible
    Je me suis pris la tête tout le week-end pour tenter de résoudre un soucis lié à la gestion du clavier pour une application que je voudrais faire avec mes élèves.
    Cette partie étant la plus complexe, je trouve, c'est donc à moi de la mettre en place sous forme de librairie de fonctions que mes élèves intégreront à leur projet.

    Nous sommes en train de développer un bomberman (simulation de) en mode console, sur Linux dans notre laboratoire.
    Pour ce faire, nous avons besoin d'un gestionnaire de clavier qui détecte que la touche enfoncée est relevée à un moment avant de prendre en compte la touche appuyée.

    Le concept est le suivant: je modifie le terminal linux pour que les entrées ne soient pas bloquantes, ainsi si il n'y a rien en entrée (aucune touche appuyée) la fonction retourne -1.
    Cela me permet de savoir si une touche est maintenue enfoncée ou pas... si j'obtiens -1 à un moment dans la boucle de saisie, cela veut dire qu'on a relâché la touche.

    Je ne vais pas revenir sur ma logique bizarroïde concernant la détection de la touche relevée et pourquoi je n'ai pas choisi d'utiliser SDL2 pour la gestion clavier: concernant SDL2, la gestion du clavier n'est pas indépendante
    de l'environnement graphique, et pour mes débutants j'avais pas envie d'attaquer de suite SDL2 et le mode graphique.

    Dans ma librairie de fonction j'ai nbgetchEx() (pour non bloquing getch Extended) définie comme ceci:

    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
     
    //*****************************************************************************
    // Fonction nbgetchEx (sans écho/affichage du caractère saisi)
    //
    // Entrée:	néant
    //            	
    // Sortie: le caractère entré au clavier
    //*****************************************************************************
    #ifdef LINUX
    int nbgetchEx(void)
    {
    	char				Buffer;
    	struct termios		oldt;
    	struct termios		newt;
     
    	tcgetattr(STDIN_FILENO, &oldt);
            newt = oldt;
     
    	// mode non bloquant...
     
    	newt.c_cc[VMIN] = 0;
    	newt.c_cc[VTIME] = 2;						// 0 ça pousse le processeur à 100% (faire gaffe à ce que l'on fait)
    	newt.c_lflag &= ~(ICANON|ECHOCTL|ECHO);		// n'a pas besoin d'appuyer sur "entrée" (caractère non bloquant de la procédure) sans écho
    	tcsetattr(STDIN_FILENO, TCSANOW, &newt);
     
    	Buffer=getchar();	                                               // retourne EOF (-1) si il y a rien dans le buffer
     
    	// on restitue "l'ancienne configuration"
    	tcsetattr(STDIN_FILENO, TCSANOW, &oldt); 
    	return Buffer;
    }
    #endif
    ...qui ne fait pas l'écho des caractères une fois la touche appuyée.

    Ca fonctionne plutôt bien sauf que: vu la logique un peu scabreuse, comme ce "gestionnaire de clavier" est exécuté en parallèle avec le programme principal, j'ai besoin d'une synchronisation pour indiquer au processus père (la fonction principale dans mon cas) que un caractère a été saisi, lorsque je me suis assuré que la touche a été relevée. En effet, je considère qu'un caractère a été saisi si la séquence APPUI/RELEVE de la touche a été opérée et pas avant.

    J'ai choisi les files de messages pour synchroniser le thread gestionnaire clavier avec la fonction principale.

    J'ai créé deux structures pour échanger des messages entre les deux processus:

    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
     
    typedef struct s_KeyEvent
    {
      char      cKey;
      wchar_t   wKey;
      bool      bMultiByte;
      bool      bFunction;
     
      bool      bStatus;      // true: touche relevée, false: touche enfoncée
    }t_KeyEvent;
     
    typedef struct s_MSGQ_ACK
    {
    	bool bAck;
    }t_MSGQ_ACK;
    s_KeyEvent est une structure contenant des informations relatives à la touche appuyée, cKey contient le code de la touche et les autres champs indiquent si il s'agit d'un caractère multibyte ou une touche de fonction, je considère comme "multibyte" les séquences d'échappement ANSI qui ne sont pas des fonctions comme PAGEUP, HOME, les touches de direction, etc...

    s_MSGQ_ACK est une structure me permettant d'indiquer au thread, à partir de la fonction principale, que le caractère (le message) a bien été reçu et que le thread peut continuer à détecter l'appui d'une touche.

    Le "protocole" est le suivant:

    THREAD: SI la touche appuyée est relevée ALORS envoyer message sur la file de message pour les données de type t_KeyEvent
    MAIN: attendre qu'un message soit disponible dans la file de message
    MAIN:traiter le message
    MAIN:indiquer que le message a été traité
    THREAD: se mettre en attente de l'ACK (acknowledgement) de la part de la fonction principale (MAIN)
    THREAD: continuer à détecter une touche

    Dans le code de la fonction main, je crée donc deux files de messages: l'une pour les données et l'autre pour l'ACK, j'ai voulu utiliser une seule file de message pour les deux synchronisations et je ne sais pour quelle raison
    cela n'avait jamais fonctionné comme je l'entendais, mais peut-être était-ce lié au "bug" que j'ai découvert...

    En effet, lorsque je place ma fonction msgget() qui permet de "se brancher" sur une file de message et d'obtenir un identifiant (censé être positif ou égal à zéro) en dehors de ma boucle où je me mets en attente
    des messages provenant de la file de messages véhiculant les caractères appuyés, et qu'ensuite toujours dans cette boucle, je tente d'envoyer l'ACK, je ne sais pour quelle(s) raison(s) l'identifiant de la file de message
    devient soudainement négatif, donc invalide et je me choppe un "invalid argument" lorsque je tente un msgsnd() pour envoyer l'ACK au thread.

    Par contre, si je place le msgget() dans la boucle (ce que je trouve absurde), là je suis bon, l'identifiant ne deviendra jamais négatif et mon gestionnaire de clavier fonctionne à merveille.

    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
    ...
    #ifdef BUGME
    	server_ACK_queue=msgget(ftok(ACKQ,'A'),IPC_CREAT|0660);
    	if(server_ACK_queue<0)
    	{
    		perror("[main] -S- Erreur de création de la file de messages ");
    		return (EXIT_FAILURE);
    	}
    #endif
      while(bRunning)
      {
        Log(logFile,"[main] attente...");
        coderetour=msgrcv(client_TRN_queue,(void*)&c_SaisieClavier,sizeof(t_KeyEvent),0,0); // est censé bloquer le programme jusqu'à ce qu'un message arrive...
        if(coderetour==-1)
        {
    			bRunning=false;
    			continue;
        }
     
    ...
     
    		// Si je ne déplace pas ce bloc ici, j'ai un bug --> server_ACK_queue devient négatif (???)
     
    		server_ACK_queue=msgget(ftok(ACKQ,'A'),IPC_CREAT|0660);
    		if(server_ACK_queue<0)
    		{
    			perror("[main] -S- Erreur de création de la file de messages ");
    			return (EXIT_FAILURE);
    		}
     
    ...
     
        coderetour=msgsnd(server_ACK_queue,(void*)&s_Ack,sizeof(t_MSGQ_ACK),0);
    		if(coderetour==-1)
    		{
    			perror("[main] Erreur msgq snd -> ");
    			break;
    		}
    ...
      }
    Est-ce que j'aurais raté un épisode concernant la fonction msgget() et le mécanisme des files messages ou alors (et j'ai vérifié tant que verse peu) il y aurait un effet de bord qui modifie mon identifiant de file de message... ou
    sommes nous dans un cas de figure qui nous laissera dans le flou le plus total ?

  2. #2
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 859
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 859
    Points : 218 580
    Points
    218 580
    Billets dans le blog
    120
    Par défaut
    Bonjour,

    Pour aider à la compréhension de l'erreur, n'oubliez pas d'utiliser errno/strerrro().
    Je pense que vous n'avez pas besoin de faire d'acknoledgment. En effet, le client (thread principal ici), doit prendre les touches qui ont été appuyée (et donc les sortir de la queue), mais le thread de lecture de touche se fiche de savoir si le client lit ou non les touches qui ont été envoyées.

    Aussi, une chose que je n'aime pas avec cette méthode d'input, c'est qu'il n'y a pas de répétition de touche (il faut continuellement appuyer pour faire avancer le personnage) et qu'il n'y a pas moyen d'avoir une information de relachement (dans le but de faire ce que fait la SDL : mettre à disposition un tableau de booléen recençant les touches qui ont été appuyées (et donc permettant de gérer les multiples appuis)).
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  3. #3
    Membre averti

    Homme Profil pro
    Enseignant
    Inscrit en
    Septembre 2012
    Messages
    313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Septembre 2012
    Messages : 313
    Points : 354
    Points
    354
    Par défaut
    oui merci LikkleWhite (ou whitey à la jamaïquaine ^^)

    Effectivement, le ack n'est plus nécessaire si je fais mon msgsnd() dans la partie de code qui assure que la touche à été préalablement relevée.

    Du coup je vais réessayer et je dis quoi.

    Au fait, dommage que la gestion SDL du clavier est inhérente à la fenêtre créée, si c'était un module séparé comme SDL_mixer (SDL2_mixer) ou SDL_gfx ce serait vraiment le top.
    Je n'ai pas encore vraiment été voir l'implémentation du gestionnaire de clavier de SDL, mais je le ferais.

  4. #4
    Membre averti

    Homme Profil pro
    Enseignant
    Inscrit en
    Septembre 2012
    Messages
    313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Septembre 2012
    Messages : 313
    Points : 354
    Points
    354
    Par défaut
    <Suite>

    Oui, je devais avoir bu ou avoir de la fièvre...
    Effectivement pas besoin de deux files de messages et encore moins d'un ACK.

  5. #5
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 859
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 859
    Points : 218 580
    Points
    218 580
    Billets dans le blog
    120
    Par défaut
    Du coup, avez-vous une solution fonctionnelle, ou cela bogue ?
    Au fait, dommage que la gestion SDL du clavier est inhérente à la fenêtre créée, si c'était un module séparé comme SDL_mixer (SDL2_mixer) ou SDL_gfx ce serait vraiment le top.
    En réalité, c'est obligatoire/forcé que ce soit fait ainsi. C'est le serveur X (pour Linux) ou plus globalement, le gestionnaire d'affichage qui envoie les signaux d'interaction utilisateur à la fenêtre. C'est en traitant ces signaux, que l'on peut savoir ce qui se passe. Une telle interface n'est pas présente (et j'ose croire qu'elle n'est pas très utile) dans un monde console.
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

Discussions similaires

  1. [AC-2010] Bug incompréhensible sans message d'erreur avec un NOT IN
    Par SteffieLili dans le forum Requêtes et SQL.
    Réponses: 2
    Dernier message: 18/03/2014, 10h46
  2. Les messages queues et l'embarqué
    Par fveysseire dans le forum C
    Réponses: 2
    Dernier message: 29/05/2006, 13h43
  3. message d'erreur incompréhensible :s
    Par SanTa62 dans le forum Requêtes
    Réponses: 3
    Dernier message: 23/01/2006, 15h48
  4. bug incompréhensible
    Par petdelascar dans le forum MFC
    Réponses: 4
    Dernier message: 19/11/2005, 19h31
  5. [REDHAT] Problème d'installation de linux message d'erreur: pci:00:03
    Par spilliaert quentin dans le forum RedHat / CentOS / Fedora
    Réponses: 2
    Dernier message: 07/08/2005, 13h51

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