Question pour un champion [1]

Question pour un champion [1] - C++ - Programmation

Marsh Posté le 04-03-2004 à 15:30:20    

Soit une jolie instance de classe allouée en shared memory.
Soit un fou ne possédant pas gcc et n'ayant pas d'option pic ou équivalent sur son compilo.
Comment fera notre fou pour appeler les méthodes de son objet directement dans les différents process l'utilisant ?
 
En clair, comment fera-t-il :
 

Code :
  1. class blabla
  2. {
  3. public:
  4.   // ...
  5.   void toto(int);
  6.   // ...
  7. };
  8. // pObjetBlabla est en shared
  9. void func(blabla * pObjetBlabla)
  10. {
  11.   // ...
  12.   pObjetBlabla->Toto(0);
  13.   // ...
  14. }


 
astuce: c'est faisable.

Reply

Marsh Posté le 04-03-2004 à 15:30:20   

Reply

Marsh Posté le 04-03-2004 à 15:57:38    

Code :
  1. #include <iostream>
  2. #include <stdexcept>
  3. extern "C"
  4. {
  5. #include <unistd.h>
  6. #include <sys/ipc.h>                                                         
  7. #include <sys/shm.h>
  8. #include <string.h>
  9. #include <errno.h>
  10. #include <sys/types.h>
  11. #include <sys/wait.h>
  12. }
  13. class Foo
  14. {
  15.   char filler;
  16. public:
  17.   void bar()
  18.   {
  19.     std::cout << "Hello\t"
  20.       << getpid() << '\n';
  21.   }
  22. };
  23. class ErrnoError
  24.   : public std::runtime_error
  25. {
  26. public:
  27.   ErrnoError()
  28.     : std::runtime_error(strerror(errno))
  29.   {}
  30. };
  31. int main(int argc, char *argv[])
  32.   try
  33. {
  34.   key_t key = ftok(argv[0], 42);
  35.   if(key == -1) { throw ErrnoError(); }
  36.   int shm = shmget(key, sizeof(Foo), IPC_CREAT | 0600);
  37.   if(shm == -1) { throw ErrnoError(); }
  38.   void * const mem = shmat(shm, NULL, 0); 
  39.   if(not mem) { throw ErrnoError(); }
  40.   Foo *f =  new(mem) Foo;
  41.   switch(fork())
  42.     {
  43.     case -1:
  44.       throw ErrnoError();     
  45.     case 0:
  46.       std::cout << getpid() << " a été créé par " << getppid() << '\n';
  47.       f->bar();
  48.       shmdt(mem);
  49.       break;
  50.      
  51.     default:
  52.       wait(NULL);
  53.       f->bar();
  54.       shmdt(mem); 
  55.       if(shmctl(shm, IPC_RMID, 0) == -1) { throw ErrnoError(); }
  56.     }
  57. }
  58. catch(std::exception &e)
  59. {
  60.   std::cerr << "Aïe\t" << e.what() << std::endl;
  61. }

Reply

Marsh Posté le 04-03-2004 à 16:39:01    

Groumf, j'ai oublié de préciser que la classe se trouve dans une librairie chargée dynamiquement, par le code, au runtime.
 
Mea culpa.
 
(mais c'était tellement facile que t'aurais pu te douter qu'il y avait une couille dans le steak là)

Reply

Marsh Posté le 04-03-2004 à 16:41:10    

DocMaboul a écrit :

Groumf, j'ai oublié de préciser que la classe se trouve dans une librairie chargée dynamiquement, par le code, au runtime.

et ça change quoi ?
 

DocMaboul a écrit :


(mais c'était tellement facile que t'aurais pu te douter qu'il y avait une couille dans le steak là)

t'as jamais fait la preuve de tes compétences

Reply

Marsh Posté le 04-03-2004 à 16:43:23    

DocMaboul a écrit :

la classe se trouve dans une librairie chargée dynamiquement


 

DocMaboul a écrit :

Soit une jolie instance de classe allouée en shared memory.

 
 
et après si tu commençais à bien nommer les choses, on comprendrais mieux. la provenance de la classe n'a aucune importance. dès que t'en as la définition, tu cases tes instances où tu veux

Reply

Marsh Posté le 04-03-2004 à 16:51:24    

Taz a écrit :


et après si tu commençais à bien nommer les choses, on comprendrais mieux.


 
Mea culpa again.
 
"la provenance de la classe n'a aucune importance. dès que t'en as la définition, tu cases tes instances où tu veux"
 
pas tout à fait. Si tu ne fais pas un fork mais que tu utilises réellement deux programmes différents, l'histoire n'est pas la même.
 
En plus, je ne te demande pas du code mais la méthode à utiliser (mais si tu veux mettre le code, libre à toi). Et je précise bien, cette fois, : que la méthode en question marche aussi sous windows.


Message édité par docmaboul le 04-03-2004 à 16:52:16
Reply

Marsh Posté le 04-03-2004 à 17:03:16    

mais tu veux faire quoi ? si tu veux partager une instance, il faut de la mémoire partagée ou tout autre mécanisme de communication à la IPC

Reply

Marsh Posté le 04-03-2004 à 17:04:52    

Taz a écrit :

t'as jamais fait la preuve de tes compétences


 
Oui : je n'ai rien à prouver. Ni à toi ni à personne d'ailleurs.
 
Bon, et pour revenir au sujet, t'as trouvé la solution, champion ?

Reply

Marsh Posté le 04-03-2004 à 17:08:52    

Taz a écrit :

mais tu veux faire quoi ? si tu veux partager une instance, il faut de la mémoire partagée ou tout autre mécanisme de communication à la IPC


 
Bon, je reformule. Le contexte est :
Soit deux programmes partageant une même zone de mémoire (la méthode de sharing, je m'en fous)
Les deux programmes chargent la même librairie au runtime.
Un des deux (peu importe lequel) crée une instance de classe dans la mémoire partagée.
La classe en question est définie dans la librarie.
 
Le problème est :
trouver une méthode pour pouvoir utiliser les méthodes de la classe directement dans les deux programmes (la méthode doit aussi marcher sous windows).

Reply

Marsh Posté le 04-03-2004 à 17:12:04    

ben mon code réponds à ton problème. le processus initial crée un segment de mémoire partagée, y instancie un objet, et un autre processus (ici créé par fork pour avoir à réécrire les instructions pour attacher le segment de mémoire). et les deux programmes utilisent le même objet. le processus initial a également la charge de détruire le segment partagé

Reply

Marsh Posté le 04-03-2004 à 17:12:04   

Reply

Marsh Posté le 04-03-2004 à 17:16:23    

Taz a écrit :

ben mon code réponds à ton problème. le processus initial crée un segment de mémoire partagée, y instancie un objet, et un autre processus (ici créé par fork pour avoir à réécrire les instructions pour attacher le segment de mémoire). et les deux programmes utilisent le même objet. le processus initial a également la charge de détruire le segment partagé


 
malheureusement non car sans pic, les fonctions de l'objet pointeront sur des adresses relatives à l'adressage du programme ayant créé l'objet. Et l'autre plantera.

Reply

Marsh Posté le 04-03-2004 à 17:17:27    

ben vois avec ton système.
 
chaimoiçamarche

Reply

Marsh Posté le 04-03-2004 à 17:31:49    

Taz a écrit :

ben vois avec ton système.
 
chaimoiçamarche


 
A d'autres : c'est du pipeau.

Reply

Marsh Posté le 04-03-2004 à 18:59:52    

en passant par une interface et en faisant un allocateur commun ?
 
c le 1er truc qui me passe par la tete, je v tester ^^


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 04-03-2004 à 19:00:36    

BlackGoddess a écrit :

en passant par une interface et en faisant un allocateur commun ?
 
c le 1er truc qui me passe par la tete, je v tester ^^

ben c'est en simple ce que fait le placement de new. et ça fonctionne bien

Reply

Marsh Posté le 04-03-2004 à 20:25:37    

bon, j'ai trouvé une solution sous windows, je sais pas si c'est ce qui etait attendu ...
 
je pars du principe d'une shared section, et du principe que le code dans la dll est aussi bien utilisable par un prog que par l'autre.
 
j'ai donc fait 3 executables : une dll contenant une classe contenant une variable, un exe changeant cette variable, et un exe la lisant.
 
header commun :
 

Code :
  1. struct i_test
  2. {
  3. virtual int get() const = 0;
  4. virtual void set(const int & ) = 0;
  5. };


 
dll :

Code :
  1. #include <windows.h>
  2. #include <iostream>
  3. #include "hdr.h"
  4. #pragma section("myshared", shared)
  5. class test : public i_test
  6. {
  7. int i;
  8. public:
  9. int get() const
  10. {
  11.  return i;
  12. }
  13. void set(const int & var)
  14. {
  15.  i = var;
  16. }
  17. };
  18. __declspec(allocate("myshared" )) test shared_test;
  19. i_test * WINAPI get_test()
  20. {
  21. return &shared_test;
  22. }


 
(on lui fait exporter le symbole get_test)
 
programme changeant la variable :

Code :
  1. #include <windows.h>
  2. #include <iostream>
  3. #include "../dlltest/hdr.h"
  4. typedef i_test *(WINAPI*p_alloc_test)();
  5. typedef i_test *(WINAPI*p_get_test)();
  6. int main()
  7. {
  8. HMODULE hm = LoadLibrary("dlltest.dll" );
  9. //p_alloc_test alloc_test = (p_alloc_test)GetProcAddress(hm, "alloc_test" );
  10. p_get_test get_test = (p_get_test)GetProcAddress(hm, "get_test" );
  11. i_test *t = get_test();
  12. t->set(3);
  13. MessageBox(NULL, "test->set(3);", "test_alloc", NULL);
  14. FreeLibrary(hm);
  15. }


 
programme lisant la variable :
 

Code :
  1. #include <windows.h>
  2. #include <iostream>
  3. #include "../dlltest/hdr.h"
  4. typedef i_test *(WINAPI*p_alloc_test)();
  5. typedef i_test *(WINAPI*p_get_test)();
  6. int main()
  7. {
  8. HMODULE hm = LoadLibrary("dlltest.dll" );
  9. //p_alloc_test alloc_test = (p_alloc_test)GetProcAddress(hm, "alloc_test" );
  10. p_get_test get_test = (p_get_test)GetProcAddress(hm, "get_test" );
  11. i_test *t = get_test();
  12. if(t->get() == 3)
  13.  MessageBox(NULL, "test->get() == 3;", "test_get", NULL);
  14. else
  15.  MessageBox(NULL, "test->get() != 3;", "test_get", NULL);
  16. FreeLibrary(hm);
  17. }


 
(j'ai codé comme un cochon, c'etait juste pour voir si la solution que j'ai imaginé fonctionne)


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 05-03-2004 à 10:18:50    

sinon pour plus de dynamisme, il faudrait déclarer un buffer dans la mémoire partagée, et faire un allocateur/libérateur pour gérer ce buffer.


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 05-03-2004 à 16:10:47    

Taz a écrit :

ben c'est en simple ce que fait le placement de new. et ça fonctionne bien


 
c'est faux. Tout ce que fait un new placement, par défaut et qui n'a donc pas été surchargé, c'est :
inline void * operator new(size_t, void * p){return p;}

Reply

Marsh Posté le 05-03-2004 à 16:14:13    

DocMaboul a écrit :


 
c'est faux. Tout ce que fait un new placement, par défaut et qui n'a donc pas été surchargé, c'est :
inline void * operator new(size_t, void * p){return p;}

et ça n'est pas bien suffisant dans un cas simple ? franchement t'es lourd. tu sors connerie sur conneries, tu te le joues mais on voit rien de concret ... si y a bien quelqu'un de capable d'écire un allocateur ici, c'est moi. seulement, pas là peine de sortir le marteau pour écraser une mouche, d'autant plus que tout ça me parait une très mauvaise idée, je préfère à ce moment utiliser un processus proxy avec une petite zone de mémoire partagée servant de tampon de communication, ou utiliser les autres mécanismes classiques de communication inter-processus

Reply

Marsh Posté le 05-03-2004 à 16:23:12    

BlackGoddess a écrit :

bon, j'ai trouvé une solution sous windows, je sais pas si c'est ce qui etait attendu ...


 
Non mais j'en suis responsable. Le problème est vieux et je l'ai très mal posé. Allez, la dernière mouture :
 
Soit une librairie dynamique tout ce qu'il y a de plus normale, comportant un bon gros millier de classes codées convenablement : à savoir sans saloperies comme les membres "static" et avec des allocateurs. Il y a des héritages entre ces classes et des jolies fonctions virtuelles à gogo. De plus, vous n'avez pas accès au code de la librairie. Quelle méthode utiliser pour pouvoir allouer les objets en shared memory et appeler les méthodes "normalement".
 
astuce 1: comme d'habitude, c'est faisable
astuce 2: la problématique se situe au niveau de la vtable des classes
astuce 3: on ne peut pas exécuter une fonction dont le code se trouve en shared avec la plupart des implémentations d'unix
astuce 4: si vous trouvez la seule méthode (à ma connaissance) clean, robuste et élégante, il y a peu de chance que vous puissiez l'implémenter

Reply

Marsh Posté le 05-03-2004 à 16:25:32    

1) ne pas allouer en mémoire partagée
2) ne pas allouer en mémoire partagée
3) ne pas allouer en mémoire partagée
4) ne pas allouer en mémoire partagée
 
 
5) me rappelez de ne plus jamais lire tes conneries

Reply

Marsh Posté le 05-03-2004 à 16:26:00    

Taz a écrit :

et ça n'est pas bien suffisant dans un cas simple ? franchement t'es lourd. tu sors connerie sur conneries, tu te le joues mais on voit rien de concret ... si y a bien quelqu'un de capable d'écire un allocateur ici, c'est moi. seulement, pas là peine de sortir le marteau pour écraser une mouche, d'autant plus que tout ça me parait une très mauvaise idée, je préfère à ce moment utiliser un processus proxy avec une petite zone de mémoire partagée servant de tampon de communication, ou utiliser les autres mécanismes classiques de communication inter-processus


 
Mais je suis toujours près à admettre que je me trompe. Aussi montre moi donc le code de ce new qui ferait cet interfaçage. Pour le reste, tu peux toujours me sortir l'implémentation de com, ça fait dix ans que ça existe.
 
edit: ou presque...


Message édité par docmaboul le 05-03-2004 à 16:29:04
Reply

Marsh Posté le 05-03-2004 à 16:27:31    

Taz a écrit :

1) ne pas allouer en mémoire partagée
2) ne pas allouer en mémoire partagée
3) ne pas allouer en mémoire partagée
4) ne pas allouer en mémoire partagée
 
 
5) me rappelez de ne plus jamais lire tes conneries


 
6) et faire un vi de new.h [:ambesanch]

Reply

Marsh Posté le 05-03-2004 à 16:35:54    

DocMaboul a écrit :


avec des allocateurs.


 
bin l'allocateur de la lib va allouer sa mémoire a elle, dans l'espace du processus en cours, et aucun autre processus pourra la lire ...
 
sinon j'aurais dit recoder des allocateurs pour allouer sur un file mapping ...
 
ou sinon recoder un loader de librairie ...


Message édité par blackgoddess le 05-03-2004 à 16:39:39

---------------
-( BlackGoddess )-
Reply

Marsh Posté le 05-03-2004 à 16:41:24    

BlackGoddess a écrit :


 
bin l'allocateur de la lib va allouer sa mémoire a elle, dans l'espace du processus en cours, et aucun autre processus pourra la lire ...
 
sinon j'aurais dit recoder des allocateurs pour allouer sur un file mapping ...


 
Je voulais dire par là que tu peux lui faire utiliser un ou des allocateurs et que les classes fonctionneront donc 'à peu près' correctement en shared si l'allocateur leur donne de la shared.

Reply

Marsh Posté le 05-03-2004 à 16:42:04    

BlackGoddess a écrit :


ou sinon recoder un loader de librairie ...


 
Ca c'est intéressant. Pour quoi faire ?

Reply

Marsh Posté le 05-03-2004 à 16:44:53    

et bien un loader de librairie, qui devra intercepter les appels systemes de réservation/libération de la mémoire et les rediriger vers un endroit ou la mémoire est partagée (refaire un allocateur, mais à plus bas niveau)


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 05-03-2004 à 16:46:03    

BlackGoddess a écrit :

et bien un loader de librairie, qui devra intercepter les appels systemes de réservation/libération de la mémoire et les rediriger vers un endroit ou la mémoire est partagée (refaire un allocateur, mais à plus bas niveau)


 
Je suis déçu... Quelle problématique veux-tu résoudre ainsi ?

Reply

Marsh Posté le 05-03-2004 à 16:49:19    

et bien, si toute l'utilisation mémoire de la librairie est ainsi gérée dans une zone partagée, les processus différents pourront y avoir accès ?


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 05-03-2004 à 16:52:33    

BlackGoddess a écrit :

et bien, si toute l'utilisation mémoire de la librairie est ainsi gérée dans une zone partagée, les processus différents pourront y avoir accès ?


 
Ce n'est pas compliqué d'obtenir l'accès au data se trouvant dans la mémoire partagée. La problématique vient des tables virtuelles des différentes classes (mais je ne te dis pas exactement pourquoi histoire que tu te creuses un peu le neurone :-).

Reply

Marsh Posté le 05-03-2004 à 16:55:53    

de quoi, que le pointeur à la table soit inconsistant entre les deux process ?

Reply

Marsh Posté le 05-03-2004 à 16:57:22    

bjone a écrit :

de quoi, que le pointeur à la table soit inconsistant entre les deux process ?


 
grosso merdo : bingo !

Reply

Marsh Posté le 05-03-2004 à 16:58:48    

qq1 m'explique o_O ?


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 05-03-2004 à 17:02:14    

BlackGoddess a écrit :

qq1 m'explique o_O ?


 
La vtable d'une classe est globale et commune à toutes les instances. Elle est adressée dans l'espace du créateur de l'objet et donc relativement à celui-ci, idem pour les fonctions qu'elle référence. Dans un autre process, il y a très peu de chance que tu aies les mêmes adresses => access violation dès que tu appelles une virtuelle.

Reply

Marsh Posté le 05-03-2004 à 17:02:34    

DocMaboul a écrit :


 
grosso merdo : bingo !


 
c'est cool, mais si tu avais mis un "virtual" devant ton toto, ça aurait été un peu plus évident.
 
si la méthode est pas virtual, ça pose pas de problèmes...
(malgré qu'il y ait des méthodes virtuelles)


Message édité par bjone le 05-03-2004 à 17:07:05
Reply

Marsh Posté le 05-03-2004 à 17:04:19    

bien :) merci de l'explication :)
 
tu sais ou trouver une implémentation de ce truc ? :p


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 05-03-2004 à 17:07:24    

bjone a écrit :


 
c'est cool, mais si tu avais mis un "virtual" devant ton toto, ça aurait été un peu plus évident.
 
si la méthode est pas virtual, ça pose pas de problèmes...


 
C'est vrai et j'ai regretté d'avoir donné cet exemple qui n'était là que pour dire qu'en plus, je voulais une solution vraiment belle, c'est-à-dire sans un interfaçage à la mords-moi-le-com. Au lieu de clarifier, ça a embrouillé. Désolé.

Reply

Marsh Posté le 05-03-2004 à 17:10:35    

BlackGoddess a écrit :

bien :) merci de l'explication :)
 
tu sais ou trouver une implémentation de ce truc ? :p


 
Je n'en connais pas d'implémentation open source, ni même licenciée.

Reply

Marsh Posté le 05-03-2004 à 17:11:08    

ceci dit, donc l'astuce ce serait quoi ?
 
d'utiliser un XXXX_cast<blabla> pour court-circuiter l'accès au pointeur vtable de l'instance ?
 
nope ça marcherai po des classes dérivée....


Message édité par bjone le 05-03-2004 à 17:13:17
Reply

Marsh Posté le 05-03-2004 à 17:16:51    

bjone a écrit :

ceci dit, donc l'astuce ce serait quoi ?


 
Malheureusement, il n'y a pas d'astuce (ça se saurait).
 
Faut juste être complètement fou.

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed