Forum Programmation.c Le mystère du pointeur global

Posté par  .
Étiquettes : aucune
0
30
déc.
2004
Bonjour à tous :)

J'ai encore un problème étrange pour lequel je n'arrive pas à trouver de documentation...

J'utilise dans mon programme une structure server_t avec plein de choses dedans. J'ai fait une collection de fonctions ServerFaitQuelqueChose pour modifier cette structure. Pour plus de confort, et étant donné qu'il ne peut n'y avoir qu'une structure server_t fonctionnelle à la fois, j'ai déclaré un pointeur global appelé this qui pointe dessus. Auparavant, quand tout allait bien, tout ceci se trouvait dans un même fichier server.c, qui était devenu assez volumineux.

J'ai donc nettoyé mon code et éparpillé mes fonctions ServerBidule dans divers fichiers suivant ce qu'elles faisaient, et j'ai donc modifié la déclaration de this en conséquence : avant, j'utilisais static server_t *this = NULL dans mon server.c, maintenant j'ai extern server_t *this; dans mon server.h et server_t *this = NULL; dans mon server.c. Tous les fichiers contenant des fonctions ServerMachin #includent "server.h".

Mais là où les choses se corsent, c'est que mon programme ne marche plus correctement depuis. Il compile, il tourne, mais ce que font les fonctions externes ServerTruc n'est plus répercuté sur la structure.

Par exemple, l'une d'entre elle est sensée me charger un plugin et créer des sockets, tous stockés dans des tableaux dynamiques au sein de la structure server_t. A la fin de la fonction, qui tourne sans anicroche, je fait un printf sur this->iSocketCount, ça affiche 1 : cohérent. Dans mon thread serveur (codé dans le fichier où est déclaré this), je fais un printf sur la même variable et il m'affiche triomphalement 0... Là, je ne saisis pas... O_o'

Je vous serais vraiment reconnaissant si vous pouviez me dire ce qui ne vas pas :)
  • # Thread ou processus ?

    Posté par  . Évalué à 2.

    > Dans mon thread serveur
    Déjà la programmation multi-threadée, ce n'est pas marrant à débugger lorsqu'on a les sources, alors quand on ne les a pas, difficile de dire ce qui ne va pas.

    A priori, vérifie encore l'adresse de "this" dans les deux modules. Ils ne devraient pas différer, mais puisque tu obtiens deux valeurs différentes, ce me semble être la seule explication possible. Et le seul cas où ça peut arriver, c'est lorsqu'on utilise des processus et non des threads.

    Tu n'aurais pas un lien sur tes sources ?
    • [^] # Re: Thread ou processus ?

      Posté par  . Évalué à 1.

      Voici un lien (site lycos, n'oublies pas ton adblock :( :
      http://membres.lycos.fr/jaguar_agency/(...)
      Je ne peux pas linker le fichier directement, il faut utiliser le lien Source sur la page.
      Le programme est loin d'être fini, j'espère que ça compilera chez toi.
      Il y a un makefile pour compiler le serveur, on peut tester les sockets en compilant les programmes de test dans net/test.
      Il faut que le plugin standard soit compilé, s'il ne l'est pas il y a un makefile dans plugin/standard.
      Voilà voilà, si tu vois des horreurs en passant n'hésites pas à m'en faire part :)
      • [^] # Re: Thread ou processus ?

        Posté par  . Évalué à 1.

        Arf, en passant voici les commandes du shell du serveur :
        ls [plugin|socket] pour voir les sockets/plugins actifs
        plugin [open|close] [nom de fichier] pour charger/décharger un plugin
        exit pour quitter proprement
        • [^] # Mouais ...

          Posté par  . Évalué à 3.

          24 threads au démarrage, tu n'as peur de rien toi ;-) Ton problème est trivial, et n'a rien à voir avec un problème de threads en fait.

          Le problème se situe dans la fonction ServerAlloc() : tu analyses ton fichier de configuration (mm.conf) qui positionne iPluginCount et iSocketCount puis quelques lignes après (toujours dans ServerAlloc) tu remets ces 2 variables à 0.

          J'ai essayé de remonter l'affectation des variables, mais ça segfault.

          PS: gdb est ton ami dans ces cas là (et un bon stock d'aspirine aussi).
          • [^] # Re: Mouais ...

            Posté par  . Évalué à 1.

            Aie, je l'aurais cherché longtemps celui là xD
            Merci beaucoup, j'ai déplacé la lecture du script et ça marche mieux maintenant :)
      • [^] # Re: Thread ou processus ?

        Posté par  . Évalué à 4.

        Quelques remarques:


        1) utilisation de select, donc de ses limitations, alors que tout
        est dynamique ->dommage pas scalable, et limité en nombre de fd.
        Pourquoi utiliser nap() et appeler également select() au début de
        la boucle ? Pourquoi appeler FD_ZERO à chaque fois alors que il
        suffit d'avoir un FD_SET déjà initialisé qui remettrait à 0
        'setSockets' ?
        FD_ZERO(&blankSockets)
        while ()
        setSockets = blankSockets;
        (mm_net_server.c) (mm_net_nap.c)

        2) remplacer tous les appels à strncpy par memcpy...

        2) le connect est bloquant, penser a mettre le fd on O_NONBLOCK et
        gerer le EINPROGRESS... Idem pour accept. (mm_net_socket.c)

        3) Le type string_t est nase, il aurait fallu avoir un unsigned int
        en plus dans la structure contenant le nombre exacte de bytes
        disponibles différent de la longeur de la string véritable, et
        allouer toujours un peu plus que necessaire. (mm_core_string.c)

        4) trop de semaphore.

        5) trop d'allocation mémoire dans tous les sens, penser à faire des
        pool ou alors allouer les maximums d'objets au début. Malloc est le
        point noir de toute application.

        Les threads c'est bien pour ne pas se prendre la tête à faire
        mieux. Mais pour un serveur c'est pas vraiment le top...

        http://www.kegel.com/c10k.html(...)
        • [^] # Re: Thread ou processus ?

          Posté par  . Évalué à 1.

          OK, je vais remanier tout ça :) Par contre, que puis-je utiliser à la place de select() pour trouver mes sockets lisibles sans limitation ? Au début, j'avais pensé utiliser une boucle avec ioctl() mais je ne sais pas si c'est très propre...

          J'ai utilisé select() dans nap() car c'est la seule fonction que j'ai trouvé qui permet de faire un sleep() de moins d'une seconde présente sous Linux et Windows.

          Merci pour tous ces conseils en tout cas :)
          • [^] # Re: Thread ou processus ?

            Posté par  . Évalué à 2.

            je crois qu'il veut dire que dans ta boucle, comme tu fais un select avec un timeout non nul, le nap() qui suit est inutile. Le 'select' endore le thread courant tant qu'il n'y a pas de données à lire, donc:
            - s'il y a des données à lire, on les lit et on recommence tout de suite
            - s'il n'y a pas de données, de toute façon le select ne rend pas la main et équivaut à un nap.
          • [^] # Re: Thread ou processus ?

            Posté par  . Évalué à 1.

            En fait il faut chercher du côté des fonctions qui porte un nom avec Select dedans :)
            Je veux dire par exemple AsyncSelect ou un truc du genre sous windows.

            Maintenant si ton programme est prévu pour supporter une lourde charge, je pense
            qu'il faut l'adapter a la plateforme.

            Penser Thread pour win et faire un choix sous linux entre Thread ou Automate...
            Apres choisir une bon implem de thread.

            Le top reste la possibilité de changer facilement le moteur afin d'avoir juste une
            modification minime a effectuer pour utiliser la fonction propre au systeme.
            Et du coup réaliser des benchs et enfin faire un choix...
        • [^] # Re: Thread ou processus ?

          Posté par  . Évalué à 3.

          interessant, le lien.
          mais select, ça reste portable. epoll, c'est bien , mais faut un kernel 2.6, et les autres trucs c'est pas pour linux... ça ne laissa pas beaucoup de choix tout ça. faudra que j'aille voir de plus près les implémentations.
  • # recompilation

    Posté par  . Évalué à 3.

    tente un chouette make clean et recompile tout.
    Chez moi, ça compile sans souci, et quand je passe dans gdb, une fois que j'ai chargé le plugin libstd.so, tous les thread voient bien this->iPluginCount et this->iSocketCount à 1 (Si j'ai bien compris, c'est là que ça bloque chez toi).

    Le seul truc, c'est un vilain SIGSEV au moment du exit, mais j'ai pas réussi à voir d'ou il sort, et la, il commence à être tard.
    je tenterais bien avec un valgrind ou un mpatrol ...

    sinon, quelque remarques sur la forme:
    pourquoi les fichiers sources ils sont exécutables ?

    il manque le -g dans le makefile du répertoire racine.
    En fait, les CFLAGS, je la mettrais plutot dans une variable d'environnement externe pour pas être obligé de modifier tous les makefile dès qu'on veut rajouter une option de compil

    pourquoi ne pas tirer partie des règles de compilation implicite de make

    genre
    .c.o:
    @$(CC) -c $< -o bin/$@ $(CFLAGS) # avec une tabulation en début de ligne


    au lieu d'une tripotée de cibles du genre

    mm_net_socket.o: mm_net_socket.c
    @echo "CC: mm_net_socket.o"
    @$(CC) -c mm_net_socket.c -o bin/mm_net_socket.o $(CFLAGS)


    on peut aussi remplacer
    OBJ = mm_net_socket.o mm_net_server.o mm_net_listen.o mm_net_reader.o mm_net_writer.o mm_net_shell.o mm_net_nap.o

    par
    OBJ=$(addsuffix ., $(basename $(wildcard *.c)))


    et si on est super motiv, on remplace tous les appels récursifs à make
    par des inclusions de make (cf
    http://www.tip.net.au/~millerp/rmch/recu-make-cons-harm.html(...) pour le pourqoi)
    • [^] # Re: recompilation

      Posté par  . Évalué à 3.

      c'est mieux en mettant le 'o' comme suffixe

      OBJ=$(addsuffix .o, $(basename $(wildcard *.c)))
      • [^] # Re: recompilation

        Posté par  . Évalué à 1.

        Le droit x sur mes sources c'est dû au umask de ma partition :)
        J'ai réécrit un makefile plus propre, merci pour tes indications :)

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.