Back to index

salome-kernel  6.5.0
GenericPort.hxx
Go to the documentation of this file.
00001 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
00002 //
00003 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
00004 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
00005 //
00006 // This library is free software; you can redistribute it and/or
00007 // modify it under the terms of the GNU Lesser General Public
00008 // License as published by the Free Software Foundation; either
00009 // version 2.1 of the License.
00010 //
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 // Lesser General Public License for more details.
00015 //
00016 // You should have received a copy of the GNU Lesser General Public
00017 // License along with this library; if not, write to the Free Software
00018 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00019 //
00020 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
00021 //
00022 
00023 //  File   : GenericPort.hxx
00024 //  Author : Eric Fayolle (EDF)
00025 //  Module : KERNEL
00026 // Modified by : $LastChangedBy$
00027 // Date        : $LastChangedDate: 2007-02-28 15:26:32 +0100 (mer, 28 fév 2007) $
00028 // Id          : $Id: GenericPort.hxx,v 1.3.2.4.14.2.12.1 2012-04-12 14:05:06 vsr Exp $
00029 //
00030 #ifndef _GENERIC_PORT_HXX_
00031 #define _GENERIC_PORT_HXX_
00032 
00033 #include "CorbaTypeManipulator.hxx"
00034 
00035 #include "Superv_Component_i.hxx"
00036 // SALOME CORBA Exception
00037 #include "Utils_CorbaException.hxx"
00038 // SALOME C++   Exception
00039 #include "Utils_SALOME_Exception.hxx"
00040 #include "DSC_Exception.hxx"
00041 #include "utilities.h"
00042 
00043 #include <iostream>
00044 #include <map>
00045 
00046 // Inclusions pour l'affichage
00047 #include <algorithm>
00048 #include <iterator>
00049 
00050 //#define MYDEBUG
00051 
00052 // Classe GenericPort
00053 // --------------------------------
00054 //
00055 // Definition: Implemente un port de type "data-stream"
00056 // Cette implémentation gère tous les types de données définies par DataManipulator::type
00057 // Ce port est soumis à une politique d'itération sur les identificateurs de données (DataId)
00058 // Un identificateur de données est construit à partir d'un ou plusieurs paramètres de la méthode put
00059 // tels que :  une date, une itération, un pas de temps ou une combinaison de ces paramètres.
00060 
00061 template < typename DataManipulator, class COUPLING_POLICY >
00062 class GenericPort : public COUPLING_POLICY  {
00063 public:
00064   // Type de données manipulés 
00065   typedef typename DataManipulator::Type         DataType;
00066   typedef typename DataManipulator::CorbaInType  CorbaInDataType;
00067 
00068   GenericPort(); 
00069   virtual ~GenericPort();
00070 
00071   template <typename TimeType,typename TagType> void     put(CorbaInDataType data,  TimeType time, TagType tag);
00072   template <typename TimeType,typename TagType> DataType get(TimeType time, TagType tag);
00073   template <typename TimeType,typename TagType> DataType get(TimeType& ti, TimeType tf, TagType tag = 0);
00074   template <typename TimeType,typename TagType> DataType next(TimeType &t, TagType  &tag );
00075   void      close (PortableServer::POA_var poa, PortableServer::ObjectId_var id);
00076   void wakeupWaiting();
00077   template <typename TimeType,typename TagType> void erase(TimeType time, TagType tag, bool before );
00078 
00079 private:
00080 
00081   // Type identifiant une instance de donnee. Exemple (time,tag) 
00082   typedef typename COUPLING_POLICY::DataId DataId;
00083   typedef std::map< DataId, DataType>      DataTable;
00084 
00085   // Stockage des donnees recues et non encore distribuées
00086   DataTable storedDatas ;
00087 
00088   // Indicateur que le destinataire attend une instance particuliere de données
00089   bool     waitingForConvenientDataId;
00090   // Indicateur que le destinataire attend n'importe qu'elle instance de données
00091   bool     waitingForAnyDataId;
00092 
00093   // Identificateur de la donné que le destinataire (propriétaire du port) attend
00094   DataId   expectedDataId ;
00095   // Sauvegarde du DataId courant pour la méthode next 
00096   DataId   lastDataId;
00097   bool     lastDataIdSet;
00098   // Exclusion mutuelle d'acces a la table des données reçues
00099   omni_mutex     storedDatas_mutex;
00100   // Condition d'attente d'une instance (Le processus du Get attend la condition declaree par le processus Put)
00101   omni_condition cond_instance;
00102 
00103 };
00104 
00105 template < typename DataManipulator, typename COUPLING_POLICY >
00106 GenericPort<DataManipulator, COUPLING_POLICY >::GenericPort() :
00107   cond_instance(& this->storedDatas_mutex),waitingForConvenientDataId(false),
00108   waitingForAnyDataId(false),lastDataIdSet(false) {}
00109 
00110 template < typename DataManipulator, typename COUPLING_POLICY>
00111 GenericPort<DataManipulator, COUPLING_POLICY>::~GenericPort() {
00112   typename DataTable::iterator it;
00113   for (it=storedDatas.begin(); it!=storedDatas.end(); ++it) {
00114 #ifdef MYDEBUG
00115     std::cerr << "~GenericPort() : destruction de la donnnée associée au DataId :"<<  (*it).first << std::endl;
00116 #endif
00117     DataManipulator::delete_data( (*it).second );
00118   }
00119 }
00120 
00121 template < typename DataManipulator, typename COUPLING_POLICY> void 
00122 GenericPort<DataManipulator, COUPLING_POLICY>::close (PortableServer::POA_var poa, 
00123                                                       PortableServer::ObjectId_var id) {
00124   // Ferme le port en supprimant le servant
00125   // La desactivation du servant du POA provoque sa suppression
00126   poa->deactivate_object (id);
00127 }
00128 
00129 template < typename DataManipulator, typename COUPLING_POLICY> void
00130 GenericPort<DataManipulator, COUPLING_POLICY>::wakeupWaiting()
00131 {
00132 #ifdef MYDEBUG
00133   std::cout << "-------- wakeupWaiting ------------------" << std::endl;
00134 #endif
00135   storedDatas_mutex.lock();
00136   if (waitingForAnyDataId || waitingForConvenientDataId) {
00137 #ifdef MYDEBUG
00138     std::cout << "-------- wakeupWaiting:signal --------" << std::endl;
00139     std::cout << std::flush;
00140 #endif
00141     cond_instance.signal();
00142    }
00143   storedDatas_mutex.unlock();
00144 
00145 }
00146 
00147 /* Methode put_generique
00148  *
00149  * Stocke en memoire une instance de donnee (pointeur) que l'emetteur donne a l'intention du destinataire.
00150  * Reveille le destinataire, si il y a lieu.
00151  */
00152 template < typename DataManipulator, typename COUPLING_POLICY>
00153 template < typename TimeType,typename TagType>
00154 void GenericPort<DataManipulator, COUPLING_POLICY>::put(CorbaInDataType dataParam, 
00155                                                         TimeType time, 
00156                                                         TagType  tag) {
00157   fflush(stdout);
00158   fflush(stderr);
00159   try {
00160 #ifdef MYDEBUG
00161     // Affichage des donnees pour DEBUGging
00162     std::cerr << "parametres emis: " << time << ", " << tag << std::endl;
00163     DataManipulator::dump(dataParam);
00164 #endif
00165   
00166     // L'intérêt des paramètres time et tag pour ce port est décidé dans la politique de couplage
00167     // Il est possible de filtrer en prenant en compte uniquement un paramètre time/tag ou les deux
00168     // Il est également possible de convertir les données recues ou bien de les dupliquer
00169     // pour plusieurs  valeurs de time et/ou tag (d'où la notion de container dans la politique de couplage)
00170     typedef typename COUPLING_POLICY::DataIdContainer DataIdContainer;  
00171     typedef typename COUPLING_POLICY::DataId          DataId;
00172 
00173     DataId          dataId(time,tag);
00174     // Effectue les traitements spécifiques à la politique de couplage 
00175     // pour construire une liste d'ids (par filtrage, conversion ...)
00176     // DataIdContainer dataIds(dataId,*(static_cast<const COUPLING_POLICY *>(this)));   
00177     DataIdContainer dataIds(dataId, *this);   
00178 
00179     typename DataIdContainer::iterator dataIdIt = dataIds.begin();
00180 
00181     bool expectedDataReceived = false;
00182 
00183 #ifdef MYDEBUG
00184     std::cout << "-------- Put : MARK 1 ------------------" << std::endl;
00185 #endif
00186     if ( dataIds.empty() ) return;
00187 #ifdef MYDEBUG
00188     std::cout << "-------- Put : MARK 1bis ------------------" << std::endl;
00189 #endif
00190 
00191     // Recupere les donnees venant de l'ORB et relâche les structures CORBA 
00192     // qui n'auraient plus cours en sortie de méthode put
00193     DataType data = DataManipulator::get_data(dataParam);
00194 
00195 
00196     int nbOfIter = 0;
00197 
00198 #ifdef MYDEBUG
00199     std::cout << "-------- Put : MARK 2 ------ "<< (dataIdIt == dataIds.end()) << "------------" << std::endl;
00200     std::cout << "-------- Put : MARK 2bis "<< (*dataIdIt) <<"------------------" << std::endl;
00201 #endif
00202     storedDatas_mutex.lock();
00203 
00204     for (;dataIdIt != dataIds.end();++dataIdIt) {
00205 
00206 #ifdef MYDEBUG
00207       std::cout << "-------- Put : MARK 3 ------------------" << std::endl;
00208 #endif
00209       // Duplique l'instance de donnée pour les autres dataIds 
00210       if (nbOfIter > 0) data = DataManipulator::clone(data);
00211 #ifdef MYDEBUG
00212       std::cout << "-------- Put : MARK 3bis -----"<< dataIdIt.operator*() <<"------------" << std::endl;
00213 #endif
00214     
00215       DataId currentDataId=*dataIdIt;
00216 
00217 #ifdef MYDEBUG
00218       std::cerr << "processing dataId : "<< currentDataId << std::endl;
00219 
00220       std::cout << "-------- Put : MARK 4 ------------------" << std::endl;
00221 #endif
00222  
00223       // Ajoute l'instance de la donnee a sa place dans la table de données
00224       // ou remplace une instance précédente si elle existe
00225     
00226       // Recherche la première clé telle quelle ne soit pas <  currentDataId
00227       // pour celà l'opérateur de comparaison storedDatas.key_comp() est utilisé
00228       // <=> premier emplacement où l'on pourrait insérer notre DataId
00229       // <=> en général équivaux à (*wDataIt).first >= currentDataId
00230       typename DataTable::iterator wDataIt = storedDatas.lower_bound(currentDataId);
00231 #ifdef MYDEBUG
00232       std::cout << "-------- Put : MARK 5 ------------------" << std::endl;
00233 #endif
00234 
00235       // On n'a pas trouvé de dataId supérieur au notre ou 
00236       // on a trouvé une clé >  à cet Id          
00237       if (wDataIt == storedDatas.end() || storedDatas.key_comp()(currentDataId,(*wDataIt).first) ) {
00238 #ifdef MYDEBUG
00239         std::cout << "-------- Put : MARK 6 ------------------" << std::endl;
00240 #endif
00241         // Ajoute la donnee dans la table
00242         wDataIt = storedDatas.insert(wDataIt, make_pair (currentDataId, data));
00243       } else  {
00244         // Si on n'est pas en fin de liste et qu'il n'y a pas de relation d'ordre strict
00245         // entre notre dataId et le DataId pointé c'est qu'ils sont identiques
00246 #ifdef MYDEBUG
00247         std::cout << "-------- Put : MARK 7 ------------------" << std::endl;
00248 #endif
00249         // Les données sont remplacées par les nouvelles valeurs
00250         // lorsque que le dataId existe déjà
00251         DataType old_data = (*wDataIt).second;
00252         (*wDataIt).second = data;
00253         // Detruit la vieille donnee
00254         DataManipulator::delete_data (old_data);
00255       }
00256   
00257 #ifdef MYDEBUG
00258       std::cout << "-------- Put : MARK 8 ------------------" << std::endl;
00259 #endif
00260       // Compte le nombre de dataIds à traiter
00261       ++nbOfIter;
00262 
00263 #ifdef MYDEBUG
00264       std::cout << "-------- Put : waitingForConvenientDataId : " << waitingForConvenientDataId <<"---" << std::endl;
00265       std::cout << "-------- Put : waitingForAnyDataId : " << waitingForAnyDataId <<"---" << std::endl;
00266       std::cout << "-------- Put : currentDataId  : " << currentDataId <<"---" << std::endl;
00267       std::cout << "-------- Put : expectedDataId : " << expectedDataId <<"---" << std::endl;
00268       std::cout << "-------- Put : MARK 9 ------------------" << std::endl;
00269 #endif
00270 
00271       // A simplifier mais :
00272       // - pas possible de mettre des arguments optionnels à cause
00273       //   du type itérator qui n'est pas connu (pas de possibilité de déclarer un static )
00274       // - compliquer de créer une méthode sans les paramètres inutiles tout en réutilisant
00275       //   la méthode initiale car cette dernière ne peut pas être déclarée virtuelle 
00276       //   à cause de ses paramètres templates. Du coup, il faudrait aussi redéfinir la
00277       //   méthode simplifiée dans les classes définissant une politique 
00278       //   de couplage particulière ...
00279       bool dummy1,dummy2; typename DataTable::iterator dummy3;
00280       // Par construction, les valeurs de waitingForAnyDataId, waitingForConvenientDataId et de 
00281       // expectedDataId ne peuvent pas être modifiées pendant le traitement de la boucle
00282       // sur les dataIds (à cause du lock utilisé dans la méthode put et les méthodes get )
00283       // rem : Utilisation de l'évaluation gauche droite du logical C or
00284       if ( waitingForAnyDataId || 
00285            ( waitingForConvenientDataId && 
00286              isDataIdConveniant(storedDatas, expectedDataId, dummy1, dummy2, dummy3) ) 
00287            ) {
00288 #ifdef MYDEBUG
00289         std::cout << "-------- Put : MARK 10 ------------------" << std::endl;
00290 #endif
00291         //Doit pouvoir réveiller le get ici (a vérifier)
00292         expectedDataReceived = true;
00293       }
00294     }
00295    
00296     if (expectedDataReceived) {
00297 #ifdef MYDEBUG
00298       std::cout << "-------- Put : MARK 11 ------------------" << std::endl;
00299 #endif
00300       // si waitingForAnyDataId était positionné, c'est forcément lui qui a activer
00301       // expectedDataReceived à true
00302       if (waitingForAnyDataId) 
00303         waitingForAnyDataId        = false;
00304       else 
00305         waitingForConvenientDataId = false;
00306       // Reveille le thread du destinataire (stoppe son attente)
00307       // Ne faudrait-il pas réveiller plutôt tous les threads ?
00308       // Celui  réveillé ne correspond pas forcément à celui qui demande
00309       // cet expectedDataReceived.
00310       // Pb1 : cas d'un un get séquentiel et d'un get sur un dataId que l'on vient de recevoir.
00311       // Si l'on reveille le mauvais thread, l'autre va attendre indéfiniment ! (sauf timeout)
00312       // Pb2 : également si deux attentes de DataIds même différents car on n'en stocke qu'un !
00313       // Conclusion : Pour l'instant on ne gère pas un service multithreadé qui effectue
00314       // des lectures simultanées sur le même port !
00315 #ifdef MYDEBUG
00316       std::cerr << "-------- Put : new datas available ------------------" << std::endl;
00317 #endif
00318       fflush(stdout);fflush(stderr);
00319       cond_instance.signal();
00320     }
00321 #ifdef MYDEBUG
00322     std::cout << "-------- Put : MARK 12 ------------------" << std::endl;
00323 #endif
00324 
00325     // Deverouille l'acces a la table : On peut remonter l'appel au dessus de expected...
00326     storedDatas_mutex.unlock();
00327 
00328 #ifdef MYDEBUG
00329     std::cout << "-------- Put : MARK 13 ------------------" << std::endl;
00330 #endif
00331     fflush(stdout);
00332     fflush(stderr);
00333 
00334   } // Catch les exceptions SALOME//C++ pour la transformer en une exception SALOME//CORBA  
00335   catch ( const SALOME_Exception & ex ) {
00336     // On évite de laisser un  mutex
00337     storedDatas_mutex.unlock();
00338     THROW_SALOME_CORBA_EXCEPTION(ex.what(), SALOME::INTERNAL_ERROR);
00339   }
00340 
00341 }
00342 
00343 // erase data before time or tag
00344 template < typename DataManipulator, typename COUPLING_POLICY >
00345 template <typename TimeType,typename TagType>
00346 void
00347 GenericPort<DataManipulator, COUPLING_POLICY>::erase(TimeType time, TagType  tag, bool before)
00348 {
00349   typename COUPLING_POLICY::template EraseDataIdBeforeOrAfterTagProcessor<DataManipulator> processEraseDataId(*this);
00350   processEraseDataId.apply(storedDatas,time,tag,before);
00351 }
00352 
00353 // Version du Get en 0 copy
00354 // ( n'effectue pas de recopie de la donnée trouvée dans storedDatas )
00355 // ( L'utilisateur devra être attentif à la politique de gestion de l'historique
00356 //   spécifique au mode de couplage car il peut y avoir une suppression potentielle 
00357 //   d'une donnée utilisée directement dans le code utilisateur )
00358 //  Le code doit prendre connaissance du transfert de propriété ou non des données
00359 //  auprès du mode de couplage choisi. 
00360 template < typename DataManipulator, typename COUPLING_POLICY >
00361 template < typename TimeType,typename TagType>
00362 typename DataManipulator::Type 
00363 GenericPort<DataManipulator, COUPLING_POLICY>::get(TimeType time, 
00364                                                    TagType  tag)
00365 // REM : Laisse passer toutes les exceptions
00366 //       En particulier les SALOME_Exceptions qui viennent de la COUPLING_POLICY
00367 //       Pour déclarer le throw avec l'exception spécifique il faut que je vérifie
00368 //       qu'un setunexpeted est positionné sinon le C++ arrête tout par appel à terminate
00369 {
00370   typedef typename COUPLING_POLICY::DataId DataId;
00371   // (Pointeur sur séquence) ou valeur..
00372   DataType dataToTransmit ;
00373   bool     isEqual, isBounded;
00374   typedef typename DataManipulator::InnerType InnerType;
00375 
00376 #ifdef MYDEBUG
00377   std::cout << "-------- Get : MARK 1 ------------------" << std::endl;
00378 #endif
00379   expectedDataId   = DataId(time,tag);
00380 #ifdef MYDEBUG
00381   std::cout << "-------- Get : MARK 2 ------------------" << std::endl;
00382 #endif
00383  
00384   typename DataTable::iterator wDataIt1;
00385 
00386   try {
00387     storedDatas_mutex.lock(); // Gérer les Exceptions ds le corps de la méthode
00388   
00389     while ( true ) {
00390  
00391       // Renvoie isEqual si le dataId attendu est trouvé dans storedDatas :
00392       //   - l'itérateur wDataIt1 pointe alors sur ce dataId
00393       // Renvoie isBounded si le dataId attendu n'est pas trouvé mais encadrable et 
00394       // que la politique  gére ce cas de figure 
00395       //   - l'itérateur wDataIt1 est tel que wDataIt1->first < wdataId < (wDataIt1+1)->first
00396       // Méthode provenant de la COUPLING_POLICY
00397       isDataIdConveniant(storedDatas,expectedDataId,isEqual,isBounded,wDataIt1);
00398 #ifdef MYDEBUG
00399       std::cout << "-------- Get : MARK 3 ------------------" << std::endl;
00400 #endif
00401 
00402       // L'ordre des différents tests est important
00403       if ( isEqual ) {
00404  
00405 #ifdef MYDEBUG
00406         std::cout << "-------- Get : MARK 4 ------------------" << std::endl;
00407 #endif
00408         // La propriété de la données N'EST PAS transmise à l'utilisateur en mode CALCIUM.
00409         // Si l'utilisateur supprime la donnée, storedDataIds devient incohérent
00410         // C'est EraseDataId qui choisi ou non de supprimer la donnée
00411         // Du coup interaction potentielle entre le 0 copy et gestion de l'historique
00412         dataToTransmit = (*wDataIt1).second; 
00413 
00414 #ifdef MYDEBUG
00415         std::cout << "-------- Get : MARK 5 ------------------" << std::endl;
00416         std::cout << "-------- Get : Données trouvées à t : " << std::endl;
00417         typename DataManipulator::InnerType const * const InIt1 = DataManipulator::getPointer(dataToTransmit);
00418         size_t   N = DataManipulator::size(dataToTransmit);
00419         std::copy(InIt1,        InIt1 + N,
00420                   std::ostream_iterator< InnerType > (std::cout," "));
00421         std::cout << std::endl;
00422 #endif
00423 
00424         // Décide de la suppression de certaines  instances de données 
00425         // La donnée contenu dans la structure CORBA et son dataId sont désallouées
00426         // Méthode provenant de la COUPLING_POLICY 
00427         typename COUPLING_POLICY::template EraseDataIdProcessor<DataManipulator> processEraseDataId(*this);
00428         processEraseDataId.apply(storedDatas,wDataIt1);
00429 #ifdef MYDEBUG
00430         std::cout << "-------- Get : MARK 6 ------------------" << std::endl;
00431 #endif
00432         break;
00433 
00434       }
00435 #ifdef MYDEBUG
00436       std::cout << "-------- Get : MARK 7 ------------------" << std::endl;
00437 #endif
00438 
00439       //if (  isBounded() && COUPLING_POLICY::template needToProcessBoundedDataId() ) {
00440       // Le DataId demandé n'est pas trouvé mais est encadré ET la politique de couplage
00441       // implémente une méthode processBoundedDataId capable de générer les données à retourner
00442       if (  isBounded ) {
00443         // Pour être cohérent avec la politique du bloc précédent
00444         // on stocke la paire (dataId,données interpolées ).
00445         // CALCIUM ne stockait pas les données interpolées. 
00446         // Cependant  comme les données sont censées être produites
00447         // par ordre croissant de DataId, de nouvelles données ne devrait pas améliorer
00448         // l'interpolation.
00449 #ifdef MYDEBUG
00450         std::cout << "-------- Get : MARK 8 ------------------" << std::endl;
00451 #endif
00452 
00453         typedef typename COUPLING_POLICY::template BoundedDataIdProcessor<DataManipulator> BDI;
00454         BDI processBoundedDataId(*this);
00455         //        typename COUPLING_POLICY::template BoundedDataIdProcessor<DataManipulator> processBoundedDataId(*this);
00456         //si static BDIP::apply(dataToTransmit,expectedDataId,wDataIt1);
00457         //ancienne version template processBoundedDataId<DataManipulator>(dataToTransmit,expectedDataId,wDataIt1);
00458         //BDIP processBoundedDataId;
00459         processBoundedDataId.apply(dataToTransmit,expectedDataId,wDataIt1);
00460   
00461         // Il ne peut pas y avoir déjà une clé expectedDataId dans storedDatas (utilisation de la notation [] )
00462         // La nouvelle donnée produite est stockée, ce n'était pas le cas dans CALCIUM
00463         // Cette opération n'a peut être pas un caractère générique.
00464         // A déplacer en paramètre de la méthode précédente ? ou déléguer ce choix au mode de couplage ?
00465         storedDatas[expectedDataId]=dataToTransmit;
00466 
00467 #ifdef MYDEBUG
00468         std::cout << "-------- Get : Données calculées à t : " << std::endl;
00469         typename DataManipulator::InnerType const * const InIt1 = DataManipulator::getPointer(dataToTransmit);
00470         size_t   N = DataManipulator::size(dataToTransmit);
00471  
00472         std::copy(InIt1,        InIt1 + N,
00473                   std::ostream_iterator< InnerType > (std::cout," "));
00474         std::cout << std::endl;
00475         std::cout << "-------- Get : MARK 9 ------------------" << std::endl;
00476 #endif
00477 
00478         typename COUPLING_POLICY::template EraseDataIdProcessor<DataManipulator> processEraseDataId(*this);
00479         processEraseDataId.apply(storedDatas,wDataIt1);
00480    
00481         break;
00482       }
00483   
00484       // Délègue au mode de couplage la gestion d'une demande de donnée non disponible 
00485       // si le port est deconnecté
00486       typename COUPLING_POLICY::template DisconnectProcessor<DataManipulator> processDisconnect(*this);
00487       if ( processDisconnect.apply(storedDatas, expectedDataId, wDataIt1) ) continue;
00488     
00489       // Réception bloquante sur le dataId demandé
00490       // Si l'instance de donnée n'est pas trouvee
00491 #ifdef MYDEBUG
00492       std::cout << "-------- Get : MARK 10 ------------------" << std::endl;
00493 #endif
00494       //Positionné à faux dans la méthode put
00495       waitingForConvenientDataId = true; 
00496 #ifdef MYDEBUG
00497       std::cout << "-------- Get : MARK 11 ------------------" << std::endl;
00498      
00499       // Ici on attend que la méthode put recoive la donnée 
00500       std::cout << "-------- Get : waiting datas ------------------" << std::endl;
00501 #endif
00502       fflush(stdout);fflush(stderr);
00503       unsigned long ts, tns,rs=Superv_Component_i::dscTimeOut;
00504       if(rs==0)
00505         cond_instance.wait();
00506       else
00507         {
00508           //Timed wait on omni condition
00509           omni_thread::get_time(&ts,&tns, rs,0);
00510           int success=cond_instance.timedwait(ts,tns);
00511           if(!success)
00512             {
00513               // Waiting too long probably blocking
00514               std::stringstream msg;
00515               msg<<"Timeout ("<<rs<<" s) exceeded";
00516               Engines_DSC_interface::writeEvent("BLOCKING","","","","Probably blocking",msg.str().c_str());
00517               throw DSC_Exception(msg.str());
00518             }
00519         }
00520 
00521 
00522 #ifdef MYDEBUG
00523       std::cout << "-------- Get : MARK 12 ------------------" << std::endl;
00524 #endif
00525     }
00526 
00527   } catch (...) {
00528     waitingForConvenientDataId = true;
00529     storedDatas_mutex.unlock();
00530     throw;
00531   }
00532 
00533   // Deverouille l'acces a la table
00534   storedDatas_mutex.unlock();
00535 #ifdef MYDEBUG
00536   std::cout << "-------- Get : MARK 13 ------------------" << std::endl;
00537 #endif
00538 
00539   // La propriété de la données N'EST PAS transmise à l'utilisateur en mode CALCIUM
00540   // Si l'utilisateur supprime la donnée, storedDataIds devient incohérent
00541   // c'est eraseDataId qui choisi ou non de supprimer la donnée
00542   // Du coup interaction potentielle entre le 0 copy et gestion des niveaux 
00543   return dataToTransmit; 
00544 
00545 }
00546 
00547 template < typename DataManipulator, typename COUPLING_POLICY >
00548 template < typename TimeType,typename TagType>
00549 typename DataManipulator::Type 
00550 GenericPort<DataManipulator, COUPLING_POLICY>::get(TimeType& ti,
00551                                                    TimeType tf, 
00552                                                    TagType  tag ) {
00553   ti = COUPLING_POLICY::getEffectiveTime(ti,tf);
00554   return get(ti,tag);
00555 }
00556 
00557 
00558 // Version du next en 0 copy
00559 // ( n'effectue pas de recopie de la donnée trouvée dans storedDatas )
00560 template < typename DataManipulator, typename COUPLING_POLICY >
00561 template < typename TimeType,typename TagType>
00562 typename DataManipulator::Type 
00563 GenericPort<DataManipulator, COUPLING_POLICY>::next(TimeType &t,
00564                                                     TagType  &tag ) {
00565  
00566   typedef  typename COUPLING_POLICY::DataId DataId;
00567 
00568   DataType dataToTransmit;
00569   DataId   dataId;
00570 
00571   try {
00572     storedDatas_mutex.lock();// Gérer les Exceptions ds le corps de la méthode
00573 
00574 #ifdef MYDEBUG
00575     std::cout << "-------- Next : MARK 1 ---lastDataIdSet ("<<lastDataIdSet<<")---------------" << std::endl;
00576 #endif
00577 
00578     typename DataTable::iterator wDataIt1;
00579     wDataIt1 = storedDatas.end();
00580 
00581     //Recherche le prochain dataId à renvoyer
00582     // - lastDataIdset == true indique que lastDataId
00583     // contient le dernier DataId renvoyé
00584     // - lastDataIdset == false indique que l'on renverra
00585     //   le premier dataId trouvé
00586     // - upper_bound(lastDataId) situe le prochain DataId
00587     // à renvoyer
00588     // Rem : les données renvoyées ne sont effacées par eraseDataIds
00589     //       si necessaire
00590     if (lastDataIdSet) 
00591       wDataIt1 = storedDatas.upper_bound(lastDataId);
00592     else if ( !storedDatas.empty() ) {
00593       lastDataIdSet = true;
00594       wDataIt1      = storedDatas.begin();
00595     }
00596 
00597     typename COUPLING_POLICY::template DisconnectProcessor<DataManipulator> processDisconnect(*this);
00598 
00599     while ( storedDatas.empty() || wDataIt1 == storedDatas.end() ) {
00600 
00601       // Délègue au mode de couplage la gestion d'une demande de donnée non disponible 
00602       // si le port est deconnecté
00603       if ( processDisconnect.apply(storedDatas, lastDataId, wDataIt1) )  {
00604         waitingForAnyDataId = false; break;
00605       }
00606   
00607 #ifdef MYDEBUG
00608       std::cout << "-------- Next : MARK 2 ------------------" << std::endl;
00609 #endif
00610       //Positionné à faux dans la méthode put
00611       waitingForAnyDataId   = true;
00612 #ifdef MYDEBUG
00613       std::cout << "-------- Next : MARK 3 ------------------" << std::endl;
00614       // Ici on attend que la méthode put recoive la donnée 
00615       std::cout << "-------- Next : waiting datas ------------------" << std::endl;
00616 #endif
00617       fflush(stdout);fflush(stderr);
00618       unsigned long ts, tns,rs=Superv_Component_i::dscTimeOut;
00619       if(rs==0)
00620         cond_instance.wait();
00621       else
00622         {
00623           //Timed wait on omni condition
00624           omni_thread::get_time(&ts,&tns, rs,0);
00625           int success=cond_instance.timedwait(ts,tns);
00626           if(!success)
00627             {
00628               // Waiting too long probably blocking
00629               std::stringstream msg;
00630               msg<<"Timeout ("<<rs<<" s) exceeded";
00631               Engines_DSC_interface::writeEvent("BLOCKING","","","","Probably blocking",msg.str().c_str());
00632               throw DSC_Exception(msg.str());
00633             }
00634         }
00635 
00636       if (lastDataIdSet) {
00637 #ifdef MYDEBUG
00638         std::cout << "-------- Next : MARK 4 ------------------" << std::endl;
00639 #endif
00640         wDataIt1 = storedDatas.upper_bound(lastDataId);
00641       } else  {
00642 #ifdef MYDEBUG
00643         std::cout << "-------- Next : MARK 5 ------------------" << std::endl;
00644 #endif
00645         lastDataIdSet = true;
00646         wDataIt1      = storedDatas.begin();
00647       }
00648     }
00649 
00650 #ifdef MYDEBUG
00651     std::cout << "-------- Next : MARK 6 ------------------" << std::endl;
00652 #endif
00653 
00654     t   = getTime( (*wDataIt1).first );
00655     tag = getTag ( (*wDataIt1).first );
00656     dataToTransmit = (*wDataIt1).second;
00657  
00658 #ifdef MYDEBUG
00659     std::cout << "-------- Next : MARK 7 ------------------" << std::endl;
00660 #endif
00661     lastDataId    = (*wDataIt1).first;
00662 
00663     typename COUPLING_POLICY::template EraseDataIdProcessor<DataManipulator> processEraseDataId(*this);
00664     processEraseDataId.apply(storedDatas, wDataIt1);
00665 
00666 #ifdef MYDEBUG
00667     std::cout << "-------- Next : MARK 8 ------------------" << std::endl;   
00668 #endif
00669   } catch (...) {
00670 #ifdef MYDEBUG
00671     std::cout << "-------- Next : MARK 8bis ------------------" << std::endl;
00672 #endif
00673     waitingForAnyDataId = false;
00674     storedDatas_mutex.unlock();
00675     throw;
00676   }
00677   storedDatas_mutex.unlock();
00678   
00679 #ifdef MYDEBUG
00680   std::cout << "-------- Next : MARK 9 ------------------" << std::endl;
00681 #endif
00682 
00683   // La propriété de la données N'EST PAS transmise à l'utilisateur en mode CALCIUM
00684   // Si l'utilisateur supprime la donnée, storedDataIds devient incohérent
00685   // c'est eraseDataId qui choisi ou non de supprimer la donnée
00686   // Du coup interaction potentielle entre le 0 copy et gestion des niveaux 
00687   return dataToTransmit; 
00688 
00689 };
00690 
00691 #endif