rc_abstract_exportal.cpp

Go to the documentation of this file.
00001 // vim:set et sts=4 ts=4 tw=75 sw=4 ai ci cin cino=g0,t0:
00002 /*
00003  * Copyright (C) 2007, Technical Computer Science Group,
00004  *                     University of Bonn
00005  *
00006  * This file is part of the ReChannel library.
00007  *
00008  * The ReChannel library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU General Public License as
00010  * published by the Free Software Foundation; either version 2 of the
00011  * License, or (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be
00014  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this library; see the file COPYING. If not, write to the
00020  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
00021  * Boston, MA 02110-1301, USA.
00022  *
00023  * Authors: Andreas Raabe and Armin Felke. Implementation by Armin Felke.
00024  *          {raabe, felke}@cs.uni-bonn.de
00025  */
00037 #include "rc_abstract_exportal.h"
00038 
00039 namespace ReChannel {
00040 
00041 rc_exportal_base::rc_exportal_base(
00042     const sc_module_name& module_name,
00043     state_type& state, unsigned int& transaction_count,
00044     wrapper_pool& s_wrapper_pool_)
00045     : sc_module(module_name), p_state(state),
00046       p_transaction_count(transaction_count),
00047       s_wrapper_pool(s_wrapper_pool_),
00048       p_first_dyn_filter(NULL), p_dyn_module(NULL),
00049       p_exclusive_wrapper(NULL)
00050 { }
00051 
00052 sc_interface* rc_exportal_base::get_dynamic_interface() const
00053 {
00054     if (p_dyn_wrapper_handle.valid()) {
00055         return &p_dyn_wrapper_handle->get_wrapped_interface();
00056     } else {
00057         return NULL;
00058     }
00059 }
00060 
00061 void rc_exportal_base::bind_dynamic(rc_export_handle export_)
00062 {
00063     if (!export_.valid()) {
00064         RC_REPORT_ERROR(RC_ID_NULL_POINTER_,
00065             "binding failed: invalid export handle given (in exportal '"
00066             << this->name() << "')");
00067     }
00068     if (sc_is_running()) {
00069         RC_REPORT_ERROR(RC_ID_SWITCH_BINDING_ERROR_,
00070             "binding attempt with export '" << export_->name()
00071             << "' at simulation time (in exportal '"
00072             << this->name() << "')");
00073     }
00074 
00075     rc_reconfigurable* module =
00076         rc_get_reconfigurable_context(export_->get_parent_object());
00077     if (module == NULL) {
00078         RC_REPORT_ERROR(RC_ID_SWITCH_BINDING_ERROR_,
00079             "binding attempt with non-reconfigurable export '"
00080             << export_->name()
00081             << "' (in exportal '" << this->name() << "')");
00082     }
00083     sc_interface* dyn_if = export_.get_interface();
00084     if (dyn_if == NULL) {
00085         RC_REPORT_ERROR(RC_ID_SWITCH_BINDING_ERROR_,
00086             "export '" << export_->name()
00087             << "' is unbound: interface expected"
00088             "(in exportal '" << this->name() << "')");
00089     }
00090     this->register_reconfigurable(*module, *dyn_if);
00091     module->rc_register_switch(*this, export_);
00092 }
00093 
00094 void rc_exportal_base::bind_dynamic(sc_interface& dynamic_if_)
00095 {
00096     if (sc_is_running()) {
00097         RC_REPORT_ERROR(RC_ID_SWITCH_BINDING_ERROR_,
00098             "binding attempt with an interface"
00099             << " at simulation time (in exportal '"
00100             << this->name() << "')");
00101     }
00102     sc_object* channel_ = dynamic_cast<sc_object*>(&dynamic_if_);
00103     if (channel_ == NULL) {
00104         RC_REPORT_ERROR(RC_ID_SWITCH_BINDING_ERROR_,
00105             "binding attempt with an interface"
00106             << " that is no sc_object (in exportal '"
00107             << this->name() << "')");
00108     }
00109     rc_reconfigurable* module = rc_get_reconfigurable_context(channel_);
00110     if (module == NULL) {
00111         RC_REPORT_ERROR(RC_ID_SWITCH_BINDING_ERROR_,
00112             "binding attempt with an interface"
00113             << " from a non-reconfigurable context (in exportal '"
00114             << this->name() << "')");
00115     }
00116     this->register_reconfigurable(*module, dynamic_if_);
00117     module->rc_register_switch(*this, *channel_);
00118 }
00119 
00120 void rc_exportal_base::bind_exclusively(rc_interface_wrapper_base& wrapper)
00121 {
00122     if (sc_is_running()) {
00123         RC_REPORT_ERROR(RC_ID_SWITCH_BINDING_ERROR_,
00124             "binding attempt with an interface"
00125             << " at simulation time (in exportal '"
00126             << this->name() << "')");
00127     }
00128     if (p_exclusive_wrapper != NULL) {
00129         RC_REPORT_ERROR(RC_ID_SWITCH_BINDING_ERROR_,
00130             "only one exclusively bound interface"
00131             " can be registered (in exportal '"
00132             << this->name() << "')");
00133     }
00134     sc_interface& dynamic_if_ = wrapper.get_wrapped_interface();
00135     sc_object* channel_ = dynamic_cast<sc_object*>(&dynamic_if_);
00136     if (channel_ == NULL) {
00137         RC_REPORT_ERROR(RC_ID_SWITCH_BINDING_ERROR_,
00138             "binding attempt with an interface"
00139             << " that is no sc_object (in exportal '"
00140             << this->name() << "')");
00141     }
00142     rc_reconfigurable* module = rc_get_reconfigurable_context(channel_);
00143     if (module == NULL) {
00144         module = &rc_non_reconfigurable::get_instance();
00145     }
00146     this->register_reconfigurable(*module, dynamic_if_);
00147     module->rc_register_switch(*this, *channel_);
00148     p_exclusive_wrapper = &wrapper;
00149 }
00150 
00151 void rc_exportal_base::open()
00152 {
00153     if (p_state == rc_switch::CLOSED) {
00154         // check whether module is active
00155         if (p_dyn_module != NULL && p_dyn_module->rc_is_active()) {
00156             this->open(*p_dyn_module, p_dyn_filter_chain);
00157         } else {
00158             this->set_undefined();
00159         }
00160     }
00161 }
00162 
00163 void rc_exportal_base::open(
00164     rc_reconfigurable& module, const filter_chain& filters)
00165 {
00166     // check whether module is bound to this exportal
00167     sc_interface* dyn_if = this->get_registered_interface(module);
00168     if (dyn_if == NULL) {
00169         // binding error, module is not registered at this exportal
00170         RC_REPORT_ERROR(RC_ID_SWITCH_BINDING_ERROR_,
00171             "dynamic module '" << module.rc_get_name()
00172             << "' is not registered (in exportal '"
00173             << this->name() << "')");
00174     }
00175     // is exportal open?
00176     if (p_state == rc_switch::OPEN) {
00177         if (&module == p_dyn_module) {
00178             if (filters != p_dyn_filter_chain) {
00179                 // report "change of filter chain while open" error
00180                 RC_REPORT_ERROR(RC_ID_SWITCH_CONFLICT_,
00181                     "cannot change interface filter chain while"
00182                     " exportal is open (in exportal '"
00183                     << this->name() << "')");
00184             } else {
00185                 // exportal already open for this module (no changes)
00186                 return;
00187             }
00188         } else {
00189             // report conflict with another module
00190             RC_REPORT_ERROR(RC_ID_SWITCH_CONFLICT_,
00191                 "opening exportal for dynamic module '"
00192                 << module.rc_get_name()
00193                 << "' conflicts with currently active dynamic module"
00194                 " '" << p_dyn_module->rc_get_name() << "'"
00195                 << " (in exportal '" << this->name() << "')");
00196         }
00197     } else {
00198         // check if the previous wrapper handle was released
00199         assert(p_dyn_wrapper_handle.valid() == false);
00200     }
00201 
00202     // check whether module is active
00203     if (!module.rc_is_active()) {
00204         this->set_undefined();
00205         return;
00206     }
00207 
00208     // check whether given interface is compatible
00209     if (this->_rc_check_interface_type(dyn_if) == false) {
00210         RC_REPORT_ERROR(RC_ID_SWITCH_BINDING_ERROR_,
00211             "an invalid interface type '"  << typeid(dyn_if).name()
00212             << "' has been registered for dynamic module '"
00213             << module.rc_get_name()
00214             << " (in exportal '" << this->name() << "')");
00215     }
00216 
00217     // acquire the dynamic wrapper
00218     if (p_reserved_wrapper_handle.valid()
00219     && &p_reserved_wrapper_handle->get_wrapped_interface() == dyn_if) {
00220         // fetch the wrapper from the reserve slot
00221         p_dyn_wrapper_handle = p_reserved_wrapper_handle;
00222         // check if the reserve slot was invalidated correctly
00223         assert(p_reserved_wrapper_handle.valid() == false);
00224     } else {
00225         // check if we own an exclusive wrapper for this interface
00226         if (p_exclusive_wrapper != NULL
00227         && &p_exclusive_wrapper->get_wrapped_interface() == dyn_if) {
00228             // the exclusive wrapper is the new dynamic wrapper
00229             p_dyn_wrapper_handle = p_exclusive_wrapper;
00230         } else {
00231             // get the dynamic wrapper from the pool
00232             wrapper_handle handle = 
00233                 rc_exportal_base::s_wrapper_pool.get(*dyn_if, this);
00234             p_dyn_wrapper_handle = handle;
00235 
00236             // set this exportal as the new owner of the interface wrapper
00237             // (this requires the interface wrapper to be of the internal
00238             //    interface wrapper type)
00239             this->_rc_set_interface_wrapper_owner(
00240                 p_dyn_wrapper_handle.get_object());
00241         }
00242         // clear the restore slot
00243         p_reserved_wrapper_handle.release();
00244     }
00245 
00246     // get the static accessor
00247     accessor_base_type& static_accessor = this->_rc_get_static_accessor();
00248 
00249     // check if an interface filter shall be applied or not
00250     if (filters.empty()) {
00251         // connect the accessor with the wrapper
00252         static_accessor.rc_set_target(*p_dyn_wrapper_handle);
00253     } else {
00254         accessor_base_type* first_dyn_filter = NULL;
00255         rc_interface_filter* const last_dyn_filter = filters.back();
00256 
00257         // check if filter chain is different from the stored filter chain
00258         //   (may be the same if opened from within this exportal)
00259         if (&filters != &p_dyn_filter_chain) {
00260             // check if filters are compatible
00261             for (filter_chain::const_reverse_iterator it = filters.rbegin();
00262                 it != filters.rend();
00263                 ++it)
00264             {
00265                 rc_interface_filter* filter_ = *it;
00266                 first_dyn_filter =
00267                     dynamic_cast<accessor_base_type*>(filter_);
00268                 if (first_dyn_filter == NULL
00269                 || _rc_check_accessor_if_type(first_dyn_filter) == false)
00270                 {
00271                     RC_REPORT_ERROR(RC_ID_SWITCH_INVALID_FILTER_,
00272                         "imcompatible filter object type '"
00273                         << typeid(filter_).name()
00274                         << "' supplied by dynamic module '"
00275                         << module.rc_get_name()
00276                         << "': accessor type expected"
00277                            " (in portal '" << this->name() << "')");
00278                 }
00279             }
00280             // store a copy of the active filter chain
00281             p_dyn_filter_chain = filters;
00282         } else {
00283             // the filter chain has not changed
00284             // and thus the first filter is already known
00285             first_dyn_filter = p_first_dyn_filter;
00286         }
00287 
00288         // connect the first filter with the interface wrapper
00289         first_dyn_filter->rc_set_target(*p_dyn_wrapper_handle);
00290         // store the pointer of the applied filter
00291         p_first_dyn_filter = first_dyn_filter;
00292         // let the event forwarder target at the first filter
00293         this->add_event_forwarder_target(
00294             *first_dyn_filter, first_dyn_filter->rc_get_event_filter());
00295         // get the filter count
00296         const unsigned int count = filters.size();
00297         // connect the rest of the filter chain
00298         for (unsigned int i=1; i < count; ++i) {
00299             if (filters[i]->rc_set_target(*filters[i-1]) == false) {
00300                 RC_REPORT_ERROR(RC_ID_SWITCH_INVALID_FILTER_,
00301                     "connecting the filter chain for "
00302                     " dynamic module '" << module.rc_get_name()
00303                     << "' failed (in exportal '" << this->name() << "')");
00304             }
00305             // let the event forwarder target at the filter
00306             this->add_event_forwarder_target(
00307                 *filters[i], filters[i]->rc_get_event_filter());
00308         }
00309         // connect the accessor with the last filter
00310         if (static_accessor.rc_set_target(
00311             *last_dyn_filter, module.rc_get_process_control()) == false)
00312         {
00313             RC_REPORT_ERROR(RC_ID_SWITCH_INVALID_FILTER_,
00314                 "connecting the accessor of "
00315                 " dynamic module '" << module.rc_get_name()
00316                 << "' failed (in exportal '" << this->name() << "')");
00317         }
00318     }
00319     // let the event forwarder target at the accessor
00320     this->add_event_forwarder_target(
00321         static_accessor, static_accessor.rc_get_event_filter());
00322     // store the pointer of the module
00323     p_dyn_module = &module;
00324     // set portal to opened state
00325     p_state = rc_switch::OPEN;
00326     // call user-defined event handler (if simulation is running)
00327     if (sc_is_running()) {
00328         this->rc_on_open();
00329     }
00330 }
00331 
00332 void rc_exportal_base::close()
00333 {
00334     // check whether communication is currently taking place
00335     if (p_transaction_count > 0) {
00336         RC_REPORT_ERROR(RC_ID_SWITCH_CONFLICT_,
00337             "closing portal while communication in progress"
00338             " (in portal '" << this->name() << "')");
00339     }
00340     // set portal to closed state
00341     if (p_state != rc_switch::CLOSED) {
00342         //note: p_dyn_module and p_dyn_filter are kept (in contrast to
00343         //      method set_undefined()), because the module is still in
00344         //      place
00345         this->_rc_get_static_accessor().rc_clear_target();
00346         for (int i=p_dyn_filter_chain.size()-1; i >= 1; --i) {
00347             p_dyn_filter_chain[i]->rc_clear_target();
00348         }
00349         // cease event forwarding
00350         this->clear_event_forwarder_targets();
00351         // move wrapper to the reserve slot (equals a swapping)
00352         p_reserved_wrapper_handle = p_dyn_wrapper_handle;
00353         // set state to CLOSED
00354         p_state = rc_switch::CLOSED;
00355         // call user-defined event handler (if simulation is running)
00356         if (sc_is_running()) {
00357             this->rc_on_close();
00358         }
00359     }
00360 }
00361 
00362 void rc_exportal_base::set_undefined()
00363 {
00364     // check whether communication is currently taking place
00365     if (p_transaction_count > 0) {
00366         RC_REPORT_ERROR(RC_ID_SWITCH_CONFLICT_,
00367             "changing portal to undefined state while communication"
00368             " in progress (in portal '" << this->name() << "')");
00369     }
00370     // set portal to undefined state
00371     if (p_state != rc_switch::UNDEF) {
00372         p_dyn_module = NULL;
00373         this->_rc_get_static_accessor().rc_clear_target();
00374         for (int i=p_dyn_filter_chain.size()-1; i >= 1; --i) {
00375             p_dyn_filter_chain[i]->rc_clear_target();
00376         }
00377         p_dyn_filter_chain.clear();
00378         p_first_dyn_filter = NULL;
00379         // cease event forwarding
00380         this->clear_event_forwarder_targets();
00381         // move wrapper to the reserve slot (equals a swapping)
00382         p_reserved_wrapper_handle = p_dyn_wrapper_handle;
00383         // set state to UNDEF
00384         p_state = rc_switch::UNDEF;
00385         // call user-defined event handler (if simulation is running)
00386         if (sc_is_running()) {
00387             // exportals do not have a special callback for undefined state
00388             this->rc_on_close();
00389         }
00390     }
00391 }
00392 
00393 void rc_exportal_base::register_reconfigurable(
00394         rc_reconfigurable& module, sc_interface& dyn_if)
00395 {
00396     // check whether the dynamic interface is compatible
00397     if (this->_rc_check_interface_type(&dyn_if) == false) {
00398         RC_REPORT_ERROR(RC_ID_SWITCH_BINDING_ERROR_,
00399             "registering dynamic module '" << module.rc_get_name()
00400             << "' failed: compatible interface expected"
00401                " (in portal '" << this->name() << "')");
00402     }
00403 }
00404 
00405 void rc_exportal_base::unregister_reconfigurable(
00406     rc_reconfigurable& module)
00407 {
00408     // there is only something to do if module is currently in use
00409     if (p_dyn_module == &module) {
00410         if (p_state == rc_switch::OPEN) {
00411             RC_REPORT_ERROR(RC_ID_SWITCH_BINDING_ERROR_,
00412                 "unregistering dynamic module '" << module.rc_get_name()
00413                 << "' while portal is open"
00414                    " (in portal '" << this->name() << "')");
00415         }
00416         assert(
00417             p_state == rc_switch::CLOSED
00418             || p_state == rc_switch::UNDEF);
00419         // reset members that are still storing module specific data
00420         p_reserved_wrapper_handle.release();
00421         p_first_dyn_filter = NULL;
00422         p_dyn_filter_chain.clear();
00423         p_dyn_module = NULL;
00424     }
00425 }
00426 
00427 void rc_exportal_base::notify_event(const std::string& event_name)
00428 {
00429     if (p_dyn_wrapper_handle.valid()) {
00430         rc_event_forwarder_host* const event_forwarder_host =
00431             p_dyn_wrapper_handle->get_event_forwarder_host();
00432         if (event_forwarder_host != NULL) {
00433             event_forwarder_host->notify_event(event_name);
00434         }
00435     }
00436 }
00437 
00438 rc_interface_wrapper_base*
00439 rc_exportal_base::get_interface_wrapper_base() const
00440 {
00441     if (p_dyn_wrapper_handle.valid()) {
00442         return p_dyn_wrapper_handle.get_object();
00443     } else if (p_reserved_wrapper_handle.valid()) {
00444         return p_reserved_wrapper_handle.get_object();
00445     } else {
00446         return NULL;
00447     }
00448 }
00449 
00450 void rc_exportal_base::add_event_forwarder_target(
00451     sc_interface& target_if, rc_event_filter* filter)
00452 {
00453     rc_event_forwarder_host* const event_finder_host =
00454         p_dyn_wrapper_handle->get_event_forwarder_host();
00455     if (event_finder_host == NULL) {
00456         RC_REPORT_ERROR(RC_ID_INTERNAL_ERROR_,
00457             "interface wrapper doesn't support event forarding"
00458                " (in exportal '" << this->name() << "')");
00459     }
00460     event_finder_host->add_event_forwarder_target(target_if, filter);
00461 }
00462 
00463 void rc_exportal_base::clear_event_forwarder_targets()
00464 {
00465     rc_event_forwarder_host* const event_finder_host =
00466         p_dyn_wrapper_handle->get_event_forwarder_host();
00467     if (event_finder_host != NULL) {
00468         event_finder_host->clear_event_forwarder_targets();
00469     }
00470 }
00471 
00472 } // namespace ReChannel
00473 
00474 //
00475 // $Id: rc_abstract_exportal.cpp,v 1.16 2007/12/27 00:25:44 felke Exp $
00476 // $Source: /var/cvs/projekte/ReChannel-v2/src/ReChannel/communication/exportals/rc_abstract_exportal.cpp,v $
00477 //

Generated on Tue Jan 1 23:13:29 2008 for ReChannel by  doxygen 1.5.3