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