Version: 7.8.0
GenericPort.hxx
Go to the documentation of this file.
1 // Copyright (C) 2007-2016 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, or (at your option) any later version.
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
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
87 
88  // Indicateur que le destinataire attend une instance particuliere de données
90  // Indicateur que le destinataire attend n'importe qu'elle instance de données
92 
93  // Identificateur de la donné que le destinataire (propriétaire du port) attend
95  // Sauvegarde du DataId courant pour la méthode next
98  // Exclusion mutuelle d'acces a la table des données reçues
100  // Condition d'attente d'une instance (Le processus du Get attend la condition declaree par le processus Put)
102 
103 };
104 
105 template < typename DataManipulator, typename COUPLING_POLICY >
107  cond_instance(& this->storedDatas_mutex),waitingForConvenientDataId(false),
108  waitingForAnyDataId(false),lastDataIdSet(false) {}
109 
110 template < typename DataManipulator, typename COUPLING_POLICY>
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
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
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>
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();
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
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
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
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
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