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