]> SALOME platform Git repositories - modules/kernel.git/blob - src/DSC/DSC_User/Datastream/GenericPort.hxx
Salome HOME
merge from branch BR_For40_DSC tag mergeto_BR_Dev_For_4_0_16apr07
[modules/kernel.git] / src / DSC / DSC_User / Datastream / GenericPort.hxx
1 //  Copyright (C) 2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
2 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
3 // 
4 //  This library is free software; you can redistribute it and/or 
5 //  modify it under the terms of the GNU Lesser General Public 
6 //  License as published by the Free Software Foundation; either 
7 //  version 2.1 of the License. 
8 // 
9 //  This library is distributed in the hope that it will be useful, 
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of 
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
12 //  Lesser General Public License for more details. 
13 // 
14 //  You should have received a copy of the GNU Lesser General Public 
15 //  License along with this library; if not, write to the Free Software 
16 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA 
17 // 
18 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 //
20 //
21 //
22 //  File   : GenericPort.hxx
23 //  Author : Eric Fayolle (EDF)
24 //  Module : KERNEL
25 // Modified by : $LastChangedBy$
26 // Date        : $LastChangedDate: 2007-02-28 15:26:32 +0100 (mer, 28 fév 2007) $
27 // Id          : $Id$
28
29 #ifndef _GENERIC_PORT_HXX_
30 #define _GENERIC_PORT_HXX_
31
32 #include "CorbaTypeManipulator.hxx"
33
34 // SALOME CORBA Exception
35 #include "Utils_CorbaException.hxx"
36 // SALOME C++   Exception
37 #include "Utils_SALOME_Exception.hxx"
38
39 #include <iostream>
40 #include <map>
41
42 // Inclusions pour l'affichage
43 #include <algorithm>
44 #include <iterator>
45
46 // Classe GenericPort
47 // --------------------------------
48 //
49 // Definition: Implemente un port de type "data-stream"
50 // Cette implémentation gère tous les types de données définies par DataManipulator::type
51 // Ce port est soumis à une politique d'itération sur les identificateurs de données (DataId)
52 // Un identificateur de données est construit à partir d'un ou plusieurs paramètres de la méthode put
53 // tels que :  une date, une itération, un pas de temps ou une combinaison de ces paramètres.
54
55 template < typename DataManipulator, class COUPLING_POLICY >
56 class GenericPort : public COUPLING_POLICY  {
57 public:
58   // Type de données manipulés 
59   typedef typename DataManipulator::Type         DataType;
60   typedef typename DataManipulator::CorbaInType  CorbaInDataType;
61
62   GenericPort(); 
63   virtual ~GenericPort();
64
65   template <typename TimeType,typename TagType> void     put(CorbaInDataType data,  TimeType time, TagType tag);
66   template <typename TimeType,typename TagType> DataType get(TimeType time, TagType tag);
67   template <typename TimeType,typename TagType> DataType get(TimeType ti, TimeType tf, TagType tag = 0);
68   template <typename TimeType,typename TagType> DataType next(TimeType &t, TagType  &tag );
69   void      close (PortableServer::POA_var poa, PortableServer::ObjectId_var id);
70   void wakeupWaiting();
71
72 private:
73
74   // Type identifiant une instance de donnee. Exemple (time,tag) 
75   typedef typename COUPLING_POLICY::DataId DataId;
76   typedef std::map< DataId, DataType>      DataTable;
77
78   // Stockage des donnees recues et non encore distribuées
79   DataTable storedDatas ;
80
81   // Indicateur que le destinataire attend une instance particuliere de données
82   bool     waitingForConvenientDataId;
83   // Indicateur que le destinataire attend n'importe qu'elle instance de données
84   bool     waitingForAnyDataId;
85
86   // Identificateur de la donné que le destinataire (propriétaire du port) attend
87   DataId   expectedDataId ;
88   // Sauvegarde du DataId courant pour la méthode next 
89   DataId   lastDataId;
90   bool     lastDataIdSet;
91   // Exclusion mutuelle d'acces a la table des données reçues
92   omni_mutex     storedDatas_mutex;
93   // Condition d'attente d'une instance (Le processus du Get attend la condition declaree par le processus Put)
94   omni_condition cond_instance;
95
96 };
97
98 template < typename DataManipulator, typename COUPLING_POLICY >
99 GenericPort<DataManipulator, COUPLING_POLICY >::GenericPort() :
100   cond_instance(& this->storedDatas_mutex),waitingForConvenientDataId(false),
101   waitingForAnyDataId(false),lastDataIdSet(false) {}
102
103 template < typename DataManipulator, typename COUPLING_POLICY>
104 GenericPort<DataManipulator, COUPLING_POLICY>::~GenericPort() {
105   typename DataTable::iterator it;
106   //   for (it=storedDatas.begin(); it!=storedDatas.end(); ++it) {
107   //     std::cout << "~GenericPort() : destruction de la donnnée associée au DataId :"<<  (*it).first << std::endl;
108   //     DataManipulator::delete_data( (*it).second );
109   //   }
110 }
111
112 template < typename DataManipulator, typename COUPLING_POLICY> void 
113 GenericPort<DataManipulator, COUPLING_POLICY>::close (PortableServer::POA_var poa, 
114                                                       PortableServer::ObjectId_var id) {
115   // Ferme le port en supprimant le servant
116   // La desactivation du servant du POA provoque sa suppression
117   poa->deactivate_object (id);
118 }
119
120 template < typename DataManipulator, typename COUPLING_POLICY> void
121 GenericPort<DataManipulator, COUPLING_POLICY>::wakeupWaiting()
122 {
123   std::cout << "-------- wakeupWaiting ------------------" << std::endl;
124   if (waitingForAnyDataId || waitingForConvenientDataId)
125   {
126     std::cout << "-------- wakeupWaiting:signal --------" << std::endl;
127     std::cout << std::flush;
128     cond_instance.signal();
129   }
130 }
131
132 /* Methode put_generique
133  *
134  * Stocke en memoire une instance de donnee (pointeur) que l'emetteur donne a l'intention du destinataire.
135  * Reveille le destinataire, si il y a lieu.
136  */
137 template < typename DataManipulator, typename COUPLING_POLICY>
138 template < typename TimeType,typename TagType>
139 void GenericPort<DataManipulator, COUPLING_POLICY>::put(CorbaInDataType dataParam, 
140                                                         TimeType time, 
141                                                         TagType  tag) {
142   fflush(stdout);
143   fflush(stderr);
144   try {
145     // Affichage des donnees pour DEBUGging
146     cerr << "parametres emis: " << time << ", " << tag << endl;
147     DataManipulator::dump(dataParam);
148   
149     // L'intérêt des paramètres time et tag pour ce port est décidé dans la politique de couplage
150     // Il est possible de filtrer en prenant en compte uniquement un paramètre time/tag ou les deux
151     // Il est également possible de convertir les données recues ou bien de les dupliquer
152     // pour plusieurs  valeurs de time et/ou tag (d'où la notion de container dans la politique de couplage)
153     typedef typename COUPLING_POLICY::DataIdContainer DataIdContainer;  
154     typedef typename COUPLING_POLICY::DataId          DataId;
155
156     DataId          dataId(time,tag);
157     // Effectue les traitements spécifiques à la politique de couplage 
158     // pour construire une liste d'ids (par filtrage, conversion ...)
159     // DataIdContainer dataIds(dataId,*(static_cast<const COUPLING_POLICY *>(this)));   
160     DataIdContainer dataIds(dataId, *this);   
161
162     typename DataIdContainer::iterator dataIdIt = dataIds.begin();
163
164     bool expectedDataReceived = false;
165
166     std::cout << "-------- Put : MARK 1 ------------------" << std::endl;
167     if ( dataIds.empty() ) return;
168     std::cout << "-------- Put : MARK 1bis ------------------" << std::endl;
169
170     // Recupere les donnees venant de l'ORB et relâche les structures CORBA 
171     // qui n'auraient plus cours en sortie de méthode put
172     DataType data = DataManipulator::get_data(dataParam);
173
174
175     int nbOfIter = 0;
176
177     std::cout << "-------- Put : MARK 2 ------ "<< (dataIdIt == dataIds.end()) << "------------" << std::endl;
178     std::cout << "-------- Put : MARK 2bis "<< (*dataIdIt) <<"------------------" << std::endl;
179     storedDatas_mutex.lock();
180
181     for (;dataIdIt != dataIds.end();++dataIdIt) {
182
183       std::cout << "-------- Put : MARK 3 ------------------" << std::endl;
184       // Duplique l'instance de donnée pour les autres dataIds 
185       if (nbOfIter > 0) data = DataManipulator::clone(data);
186       std::cout << "-------- Put : MARK 3bis -----"<< dataIdIt.operator*() <<"------------" << std::endl;
187     
188       DataId currentDataId=*dataIdIt;
189
190       std::cerr << "processing dataId : "<< currentDataId << std::endl;
191
192       std::cout << "-------- Put : MARK 4 ------------------" << std::endl;
193  
194       // Ajoute l'instance de la donnee a sa place dans la table de données
195       // ou remplace une instance précédente si elle existe
196     
197       // Recherche la première clé telle quelle ne soit pas <  currentDataId
198       // pour celà l'opérateur de comparaison storedDatas.key_comp() est utilisé
199       // <=> premier emplacement où l'on pourrait insérer notre DataId
200       // <=> en général équivaux à (*wDataIt).first >= currentDataId
201       typename DataTable::iterator wDataIt = storedDatas.lower_bound(currentDataId);
202       std::cout << "-------- Put : MARK 5 ------------------" << std::endl;
203
204       // On n'a pas trouvé de dataId supérieur au notre ou 
205       // on a trouvé une clé >  à cet Id          
206       if (wDataIt == storedDatas.end() || storedDatas.key_comp()(currentDataId,(*wDataIt).first) ) {
207         std::cout << "-------- Put : MARK 6 ------------------" << std::endl;
208         // Ajoute la donnee dans la table
209         wDataIt = storedDatas.insert(wDataIt, make_pair (currentDataId, data));
210       } else  {
211         // Si on n'est pas en fin de liste et qu'il n'y a pas de relation d'ordre strict
212         // entre notre dataId et le DataId pointé c'est qu'ils sont identiques
213         std::cout << "-------- Put : MARK 7 ------------------" << std::endl;
214         // Les données sont remplacées par les nouvelles valeurs
215         // lorsque que le dataId existe déjà
216         DataType old_data = (*wDataIt).second;
217         (*wDataIt).second = data;
218         // Detruit la vieille donnee
219         DataManipulator::delete_data (old_data);
220       }
221   
222       std::cout << "-------- Put : MARK 8 ------------------" << std::endl;
223       // Compte le nombre de dataIds à traiter
224       ++nbOfIter;
225
226       std::cout << "-------- Put : waitingForConvenientDataId : " << waitingForConvenientDataId <<"---" << std::endl;
227       std::cout << "-------- Put : waitingForAnyDataId : " << waitingForAnyDataId <<"---" << std::endl;
228       std::cout << "-------- Put : currentDataId  : " << currentDataId <<"---" << std::endl;
229       std::cout << "-------- Put : expectedDataId : " << expectedDataId <<"---" << std::endl;
230       std::cout << "-------- Put : MARK 9 ------------------" << std::endl;
231
232       // A simplifier mais :
233       // - pas possible de mettre des arguments optionnels à cause
234       //   du type itérator qui n'est pas connu (pas de possibilité de déclarer un static )
235       // - compliquer de créer une méthode sans les paramètres inutiles tout en réutilisant
236       //   la méthode initiale car cette dernière ne peut pas être déclarée virtuelle 
237       //   à cause de ses paramètres templates. Du coup, il faudrait aussi redéfinir la
238       //   méthode simplifiée dans les classes définissant une politique 
239       //   de couplage particulière ...
240       bool dummy1,dummy2; typename DataTable::iterator dummy3;
241       // Par construction, les valeurs de waitingForAnyDataId, waitingForConvenientDataId et de 
242       // expectedDataId ne peuvent pas être modifiées pendant le traitement de la boucle
243       // sur les dataIds (à cause du lock utilisé dans la méthode put et les méthodes get )
244       // rem : Utilisation de l'évaluation gauche droite su logical C or
245       if ( waitingForAnyDataId || 
246            ( waitingForConvenientDataId && 
247              isDataIdConveniant(storedDatas, expectedDataId, dummy1, dummy2, dummy3) ) 
248            ) {
249         std::cout << "-------- Put : MARK 10 ------------------" << std::endl;
250         //Doit pouvoir réveiller le get ici (a vérifier)
251         expectedDataReceived = true;
252       }
253     }
254    
255     if (expectedDataReceived) {
256       std::cout << "-------- Put : MARK 11 ------------------" << std::endl;
257       // si waitingForAnyDataId était positionné, c'est forcément lui qui a activer
258       // expectedDataReceived à true
259       if (waitingForAnyDataId) 
260         waitingForAnyDataId        = false;
261       else 
262         waitingForConvenientDataId = false;
263       // Reveille le thread du destinataire (stoppe son attente)
264       // Ne faudrait-il pas réveiller plutôt tous les threads ?
265       // Celui  réveillé ne correspond pas forcément à celui qui demande
266       // cet expectedDataReceived.
267       // Pb1 : cas d'un un get séquentiel et d'un get sur un dataId que l'on vient de recevoir.
268       // Si l'on reveille le mauvais thread, l'autre va attendre indéfiniment ! (sauf timeout)
269       // Pb2 : également si deux attentes de DataIds même différents car on n'en stocke qu'un !
270       // Conclusion : Pour l'instant on ne gère pas un service multithreadé qui effectue
271       // des lectures simultanées sur le même port !
272       std::cout << "-------- Put : new datas available ------------------" << std::endl;
273       fflush(stdout);fflush(stderr);
274       cond_instance.signal();
275     }
276     std::cout << "-------- Put : MARK 12 ------------------" << std::endl;
277
278     // Deverouille l'acces a la table : On peut remonter l'appel au dessus de expected...
279     storedDatas_mutex.unlock();
280
281     std::cout << "-------- Put : MARK 13 ------------------" << std::endl;
282     fflush(stdout);
283     fflush(stderr);
284
285   } // Catch les exceptions SALOME//C++ pour la transformer en une exception SALOME//CORBA  
286   catch ( const SALOME_Exception & ex ) {
287     // On évite de laisser un  mutex
288     storedDatas_mutex.unlock();
289     
290     std::cerr << ex;
291     THROW_SALOME_CORBA_EXCEPTION(ex.what(), SALOME::INTERNAL_ERROR);
292   }
293
294 }
295
296
297 // Version du Get en 0 copy
298 // ( n'effectue pas de recopie de la donnée trouvée dans storedDatas )
299 // ( L'utilisateur devra être attentif à la politique de gestion de l'historique
300 //   spécifique au mode de couplage car il peut y avoir une suppression potentielle 
301 //   d'une donnée utilisée directement dans le code utilisateur )
302 //  Le code doit prendre connaissance du transfert de propriété ou non des données
303 //  auprès du mode de couplage choisi. 
304 template < typename DataManipulator, typename COUPLING_POLICY >
305 template < typename TimeType,typename TagType>
306 typename DataManipulator::Type 
307 GenericPort<DataManipulator, COUPLING_POLICY>::get(TimeType time, 
308                                                    TagType  tag)
309 // REM : Laisse passer toutes les exceptions
310 //       En particulier les SALOME_Exceptions qui viennent de la COUPLING_POLICY
311 //       Pour déclarer le throw avec l'exception spécifique il faut que je vérifie
312 //       qu'un setunexpeted est positionné sinon le C++ arrête tout par appel à terminate
313 {
314   typedef typename COUPLING_POLICY::DataId DataId;
315   // (Pointeur sur séquence) ou valeur..
316   DataType dataToTransmit ;
317   bool     isEqual, isBounded;
318   typedef typename DataManipulator::InnerType InnerType;
319
320   std::cout << "-------- Get : MARK 1 ------------------" << std::endl;
321   expectedDataId   = DataId(time,tag);
322   std::cout << "-------- Get : MARK 2 ------------------" << std::endl;
323  
324   typename DataTable::iterator wDataIt1;
325
326   try {
327     storedDatas_mutex.lock(); // Gérer les Exceptions ds le corps de la méthode
328   
329     while ( true ) {
330  
331       // Renvoie isEqual si le dataId attendu est trouvé dans storedDatas :
332       //   - l'itérateur wDataIt1 pointe alors sur ce dataId
333       // Renvoie isBounded si le dataId attendu n'est pas trouvé mais encadrable et 
334       // que la politique  gére ce cas de figure 
335       //   - l'itérateur wDataIt1 est tel que wDataIt1->first < wdataId < (wDataIt1+1)->first
336       // Méthode provenant de la COUPLING_POLICY
337       isDataIdConveniant(storedDatas,expectedDataId,isEqual,isBounded,wDataIt1);
338       std::cout << "-------- Get : MARK 3 ------------------" << std::endl;
339
340       // L'ordre des différents tests est important
341       if ( isEqual ) {
342  
343         std::cout << "-------- Get : MARK 4 ------------------" << std::endl;
344         // La propriété de la données N'EST PAS transmise à l'utilisateur en mode CALCIUM.
345         // Si l'utilisateur supprime la donnée, storedDataIds devient incohérent
346         // C'est EraseDataId qui choisi ou non de supprimer la donnée
347         // Du coup interaction potentielle entre le 0 copy et gestion de l'historique
348         dataToTransmit = (*wDataIt1).second; 
349
350         std::cout << "-------- Get : MARK 5 ------------------" << std::endl;
351         std::cout << "-------- Get : Données trouvées à t : " << std::endl;
352         typename DataManipulator::InnerType const * const InIt1 = DataManipulator::getPointer(dataToTransmit);
353         size_t   N = DataManipulator::size(dataToTransmit);
354         std::copy(InIt1,        InIt1 + N,
355                   std::ostream_iterator< InnerType > (std::cout," "));
356         std::cout << std::endl;
357
358         // Décide de la suppression de certaines  instances de données 
359         // La donnée contenu dans la structure CORBA et son dataId sont désallouées
360         // Méthode provenant de la COUPLING_POLICY 
361         typename COUPLING_POLICY::template EraseDataIdProcessor<DataManipulator> processEraseDataId(*this);
362         processEraseDataId.apply(storedDatas,wDataIt1);
363         std::cout << "-------- Get : MARK 6 ------------------" << std::endl;
364         break;
365
366       }
367       std::cout << "-------- Get : MARK 7 ------------------" << std::endl;
368
369       //if (  isBounded() && COUPLING_POLICY::template needToProcessBoundedDataId() ) {
370       // Le DataId demandé n'est pas trouvé mais est encadré ET la politique de couplage
371       // implémente une méthode processBoundedDataId capable de générer les données à retourner
372       if (  isBounded ) {
373         // Pour être cohérent avec la politique du bloc précédent
374         // on stocke la paire (dataId,données interpolées ).
375         // CALCIUM ne stockait pas les données interpolées. 
376         // Cependant  comme les données sont censées être produites
377         // par ordre croissant de DataId, de nouvelles données ne devrait pas améliorer
378         // l'interpolation.
379         // Les données calciulées sont donc  stockées dans storedDatas. 
380         // La propriété des données N'EST PAS transférée à l'utilisateur en mode CALCIUM.
381         std::cout << "-------- Get : MARK 8 ------------------" << std::endl;
382
383         typename COUPLING_POLICY::template BoundedDataIdProcessor<DataManipulator> processBoundedDataId(*this);
384         //si static BDIP::apply(dataToTransmit,expectedDataId,wDataIt1);
385         //ancienne version template processBoundedDataId<DataManipulator>(dataToTransmit,expectedDataId,wDataIt1);
386         //BDIP processBoundedDataId;
387         processBoundedDataId.apply(dataToTransmit,expectedDataId,wDataIt1);
388   
389         // Il ne peut pas y avoir déjà une clé expectedDataId dans storedDatas (utilisation de la notation [] )
390         // Cette opération n'a peut être pas un caractère générique.
391         // A déplacer en paramètre de la méthode précédente ?
392         storedDatas[expectedDataId]=dataToTransmit;
393
394         std::cout << "-------- Get : Données calculées à t : " << std::endl;
395         typename DataManipulator::InnerType const * const InIt1 = DataManipulator::getPointer(dataToTransmit);
396         size_t   N = DataManipulator::size(dataToTransmit);
397  
398         std::copy(InIt1,        InIt1 + N,
399                   std::ostream_iterator< InnerType > (std::cout," "));
400         std::cout << std::endl;
401         std::cout << "-------- Get : MARK 9 ------------------" << std::endl;
402
403         typename COUPLING_POLICY::template EraseDataIdProcessor<DataManipulator> processEraseDataId(*this);
404         processEraseDataId.apply(storedDatas,wDataIt1);
405    
406         break;
407       }
408   
409       // Délègue au mode de couplage la gestion d'une demande de donnée non disponible 
410       // si le port est deconnecté
411       typename COUPLING_POLICY::template DisconnectProcessor<DataManipulator> processDisconnect(*this);
412       if ( processDisconnect.apply(storedDatas, expectedDataId, wDataIt1) ) continue;
413     
414       // Réception bloquante sur le dataId demandé
415       // Si l'instance de donnée n'est pas trouvee
416       std::cout << "-------- Get : MARK 10 ------------------" << std::endl;
417       //Positionné à faux dans la méthode put
418       waitingForConvenientDataId = true; 
419       std::cout << "-------- Get : MARK 11 ------------------" << std::endl;
420      
421       // Ici on attend que la méthode put recoive la donnée 
422       std::cout << "-------- Get : waiting datas ------------------" << std::endl;
423       fflush(stdout);fflush(stderr);
424       cond_instance.wait();
425
426       std::cout << "-------- Get : MARK 12 ------------------" << std::endl;
427     }
428
429   } catch (...) {
430     storedDatas_mutex.unlock();
431     throw;
432   }
433
434   // Deverouille l'acces a la table
435   storedDatas_mutex.unlock();
436   std::cout << "-------- Get : MARK 13 ------------------" << std::endl;
437
438   // La propriété de la données N'EST PAS transmise à l'utilisateur en mode CALCIUM
439   // Si l'utilisateur supprime la donnée, storedDataIds devient incohérent
440   // c'est eraseDataId qui choisi ou non de supprimer la donnée
441   // Du coup interaction potentielle entre le 0 copy et gestion des niveaux 
442   return dataToTransmit; 
443
444 }
445
446 template < typename DataManipulator, typename COUPLING_POLICY >
447 template < typename TimeType,typename TagType>
448 typename DataManipulator::Type 
449 GenericPort<DataManipulator, COUPLING_POLICY>::get(TimeType ti,
450                                                    TimeType tf, 
451                                                    TagType  tag ) {
452   TimeType t = COUPLING_POLICY::getEffectiveTime(ti,tf);
453   return get(t,tag);
454 }
455
456
457 // Version du next en 0 copy
458 // ( n'effectue pas de recopie de la donnée trouvée dans storedDatas )
459 template < typename DataManipulator, typename COUPLING_POLICY >
460 template < typename TimeType,typename TagType>
461 typename DataManipulator::Type 
462 GenericPort<DataManipulator, COUPLING_POLICY>::next(TimeType &t,
463                                                     TagType  &tag ) {
464  
465   typedef  typename COUPLING_POLICY::DataId DataId;
466
467   DataType dataToTransmit;
468   DataId   dataId;
469
470   try {
471     storedDatas_mutex.lock();// Gérer les Exceptions ds le corps de la méthode
472
473     std::cout << "-------- Next : MARK 1 ---lastDataIdSet ("<<lastDataIdSet<<")---------------" << std::endl;
474
475     typename DataTable::iterator wDataIt1;
476     wDataIt1 = storedDatas.end();
477
478     //Recherche le prochain dataId à renvoyer
479     if (lastDataIdSet) 
480       wDataIt1 = storedDatas.upper_bound(lastDataId);
481     else if ( !storedDatas.empty() ) {
482       lastDataIdSet = true;
483       wDataIt1      = storedDatas.begin();
484     }
485
486     while ( storedDatas.empty() || wDataIt1 == storedDatas.end() ) {
487
488       // Délègue au mode de couplage la gestion d'une demande de donnée non disponible 
489       // si le port est deconnecté
490       typename COUPLING_POLICY::template DisconnectProcessor<DataManipulator> processDisconnect(*this);
491       if ( processDisconnect.apply(storedDatas, lastDataId, wDataIt1) ) break;
492
493       std::cout << "-------- Next : MARK 2 ------------------" << std::endl;
494       //Positionné à faux dans la méthode put
495       waitingForAnyDataId   = true;
496       std::cout << "-------- Next : MARK 3 ------------------" << std::endl;
497       // Ici on attend que la méthode put recoive la donnée 
498       std::cout << "-------- Next : waiting datas ------------------" << std::endl;
499       fflush(stdout);fflush(stderr);
500       cond_instance.wait();
501     
502       if (lastDataIdSet) {
503         std::cout << "-------- Next : MARK 4 ------------------" << std::endl;
504         wDataIt1 = storedDatas.upper_bound(lastDataId);
505       } else {
506         std::cout << "-------- Next : MARK 5 ------------------" << std::endl;
507         lastDataIdSet = true;
508         wDataIt1      = storedDatas.begin();
509       }
510     }
511
512     std::cout << "-------- Next : MARK 6 ------------------" << std::endl;
513
514     t   = getTime( (*wDataIt1).first );
515     tag = getTag ( (*wDataIt1).first );
516     dataToTransmit = (*wDataIt1).second;
517  
518     std::cout << "-------- Next : MARK 7 ------------------" << std::endl;
519     lastDataId    = (*wDataIt1).first;
520
521     typename COUPLING_POLICY::template EraseDataIdProcessor<DataManipulator> processEraseDataId(*this);
522     processEraseDataId.apply(storedDatas, wDataIt1);
523
524     std::cout << "-------- Next : MARK 8 ------------------" << std::endl;   
525   } catch (...) {
526     storedDatas_mutex.unlock();
527     throw;
528   }
529   storedDatas_mutex.unlock();
530   
531   std::cout << "-------- Next : MARK 9 ------------------" << std::endl;
532
533   // La propriété de la données N'EST PAS transmise à l'utilisateur en mode CALCIUM
534   // Si l'utilisateur supprime la donnée, storedDataIds devient incohérent
535   // c'est eraseDataId qui choisi ou non de supprimer la donnée
536   // Du coup interaction potentielle entre le 0 copy et gestion des niveaux 
537   return dataToTransmit; 
538
539 };
540
541 #endif