• [^] # Re: E_NOENOUGH_INFO | E_UNNEEDED

    Posté par . En réponse au message Volatile, struct et interruptions.. Évalué à 2.

    Quelques remarques en attendant que tes algos soit spécifiés et que l'on puisse te donner une réponse précise.

    si ton interruption ne se fait pas interrompre, un volatile dans le code de l'interruption ne sert effectivement à rien.

    Effectivement, vu que la routine d'it est censée sauvegarder le contexte d'exécution du programme interrompu.

    un volatile dans le code "main" peut-être utile mais certainement pas suffisante (enfin faut voir ton algo toujours). Je conjecture que tu auras quand même besoin d'implémenter un mécanisme de type mutex pour te prémunir des problèmes de TOCTOU.

    C'est pour ça que je n'ai pas encore spécifié mon algo: je "sens" qu'il y a un truc à faire à ce niveau (d'ailleurs tu as mis le doigt dessus, voir plus bas).

    mettre volatile est souvent une fausse bonne idée. Je te laisse rechercher les références de Linus sur la LKML ;-) La démonstration suit...

    Je pars du principe que volatile est utile, mais pas suffisant. si j'ai bien compris, volatile sert à "forcer" le compilateur à insérer une instruction de relecture de la valeur depuis la mémoire (pour des questions d'optimisation, le compilateur ne force pas la relecture de la valeur lorsque celle-ci est déjà dans un des registres du processeur).
    Ca a son utilité lorsqu'une valeur est susceptible d'être écrite par un autre thread entre deux (ou plus de deux ) lectures successives (ou une interruption). Par contre ça ne règle pas les problèmes d'accès concurrents à une valeur, problème résolus par les mécanismes de mutex. L'un ne remplace pas l'autre, les deux ont une utilité différente.

    Admettons que ton main ressemble à cela:

    Ca y ressemble, au détail près que j'ai déporté la gestiuon du buffer dans des fonctions, appeléers par le main ou les routines d'IT.

    Au niveu de l'interruption:

    Tu en es pas très loin, au détail près que je ne calcule pas de taille, je me contente juste de comparer les index head et tail : s'ils ont la même valeur, ça signifie que le buffer est plein.

    NB: c'est une implémentation naïve d'un buffer circulaire. Je n'ai jamais fait ce genre de chose, je te conseille quand même de consulter wikipedia avant ;-)

    Mon implémentation n'est pas non plus très subtile non plus (j'ai fait au plus simple). Mais je peux (et devrai certainement) la modifier un peu (une idée m'est venu suite à vos remarques).

    Donc nous avons ton interruption qui modifie tail et ton main qui modifie head.

    La conclusion est bonne : l'interruption remplit, donc modifie le tail, et le main (et/ou une it) vide, donc modifie le head.

    Il y a-t-il un risque que l'interruption utilise une mauvaise valeur pour head ? C'est-à-dire entre le momen où tu calcules freesz et le moment où tu modifie tail.

    Comme je ne calcule pas (pour le moment) la taille, pas de risque.

    Il y a-t-il un risque que main utilise une mauvaise valeur de tail ? Idem, non je ne crois pas.

    Là par contre c'est peut-être possible. Le main est un classique : une boucle sans fin qui fait des trucs à chaquie itération. Comme je ne calcule pas de taille de buffer lors du remplissage, c'est peuit-être là que je devrais le calculer (pour déterminer le taux de remplissage de mon buffer et déclencher le transfert). Mais je pourrais simplifier en déclenchant le transfert dès que le buffer n'est pas vide.

    Le problème se situe au moment où l'on calcule sz et freesz !!

    Donc bref: tu copies tes volatiles dans des variables locales au début de ta routine pour être certain que tu n'accède pas à tes variables en ram directement.

    Ca me parait une bonne idée.

    Ton algo doit être conçu pour fonctionner sur des valeurs qui ne reflètent peut-être plus la réalité mais qui son cohérentes entre elles, pas pour fonctionner avec des valeurs certes actuelles mais qui changent au gré du vent/des lignes!!!

    Ca me parait logique. Pour moi, le seul moment ou j'ai besoin d'une représentation réelle est lorsque le buffer est vide ou lorsqu'il est plein.

    que se passerait-il si tail est accèdée en volatile et qu'une interruption fait wrapper tail et survient juste après que tu aies testé qu'il n'y a pas de wrap ? Oops un freesz < 0... ça sent pas bon hein... ;-)

    C'est justement pour ça que je n'ai pas encore spécifié définitivement mon algo : j'avais senti cette mauvaise odeur de loin, mais pas eu le temps d'approfondir et de détailler la réflexion.

    (Ma) conclusion :

    pas besoin de mutex,

    Je suis d'accord sur ce point.

    surtout pas besoin de volatile, sous réserve que le code "main" soit dans une fonction séparée

    Là je suis moins d'accord (en fait ça dépendra de mes choix) : je peux en avoir besoin si je calcule le taux d'occupation de mon buffer dans le main. Mais je crois que je vais éviter ...

    Maintenant si tu passes à plusieurs producteurs/consommateurs, ben ça se complique : ne le fais pas, utilise plusieurs buffers :p

    Je ne compte pas le faire.

    PS: je viens de me rendre compte que c'est l'inverse que tu veux faire, soit vider un buffer par une interruption. Cela revient au même.

    Pas encore décidé : Ce qui est sur c'est que je remplis via une interruption. Par contre pour vider je me tate : soit je vide dans le main, soit je vide via l'interruption UART. L'avantage de l'interruption, c'est que je suis sur qu'elle ne sera pas interrompue durant son exécution. L'inconvénient : un peu plus de taf.

    en tout cas merci pour ces indications qui me feront avancer. J'ai une ou deux idées que je vous présenterai si ça vous intéresse.