rc_driver_object.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_driver_object.h"
00038 
00039 namespace ReChannel {
00040 
00041 // static variables
00042 sc_process_handle rc_driver_object_base::s_hproc;
00043 
00044 rc_driver_object_base::write_call_vector
00045     rc_driver_object_base::s_write_call_vector;
00046 
00047 sc_event rc_driver_object_base::s_pending_write_event;
00048 
00049 bool rc_driver_object_base::s_pending_write_event_notified_flag = false;
00050 
00051 // shared static driver method process
00052 void rc_driver_object_base::s_writer_method_proc()
00053 {
00054     // the loop that executes the pending write calls
00055     for (write_call_iterator it = s_write_call_vector.begin();
00056      it != s_write_call_vector.end();
00057      ++it) {
00058         it->m_call();
00059     }
00060     // clear the write call vector
00061     s_write_call_vector.clear();
00062 
00063     // consume event
00064     s_pending_write_event_notified_flag = false;
00065 
00066     // prevent accidental change of sensitivity
00067     sc_core::next_trigger();
00068 }
00069 
00070 // constructor
00071 rc_driver_object_base::rc_driver_object_base()
00072     : m_write_call_vector(&s_write_call_vector),
00073       m_pending_write_event(&s_pending_write_event),
00074       m_pending_write_event_notified_flag(false),
00075       m_pending_write_event_notified(&s_pending_write_event_notified_flag)
00076 {
00077     // create the static driver method process if it does not exist
00078     if (s_hproc.valid() == false) {
00079         sc_spawn_options opt;
00080         opt.set_sensitivity(&s_pending_write_event);
00081         opt.dont_initialize();
00082         opt.spawn_method();
00083         s_hproc = sc_spawn(
00084             &rc_driver_object_base::s_writer_method_proc,
00085             sc_gen_unique_name("_rc_shared_nb_driver_object_proc"),
00086             &opt);
00087     }
00088     m_hproc = s_hproc;
00089 }
00090 
00091 rc_driver_object_base::~rc_driver_object_base()
00092 {
00093     // destroy the created objects
00094     if (m_write_call_vector != &s_write_call_vector) {
00095         delete m_write_call_vector;
00096         m_write_call_vector = NULL;
00097     }
00098     if (m_pending_write_event != &s_pending_write_event) {
00099         delete m_pending_write_event;
00100         m_pending_write_event = NULL;
00101     }
00102 }
00103 
00104 // driver method process
00105 void rc_driver_object_base::writer_method_proc()
00106 {
00107     for (write_call_iterator it = m_write_call_vector->begin();
00108      it != m_write_call_vector->end();
00109      ++it) {
00110         it->m_call();
00111     }
00112     m_write_call_vector->clear();
00113 
00114     // consume event
00115     *m_pending_write_event_notified = false;
00116 
00117     // prevent accidental change of sensitivity
00118     sc_core::next_trigger();
00119 }
00120 
00121 // driver thread process
00122 void rc_driver_object_base::writer_thread_proc()
00123 {
00124     while(true) {
00125         for (write_call_iterator it = m_write_call_vector->begin();
00126           it != m_write_call_vector->end();
00127           ++it) {
00128             try {
00129                 it->m_call();
00130             } catch(rc_throwable* thrown_obj) {
00131                 if (it->m_throw_dest != NULL) {
00132                     *(it->m_throw_dest) = thrown_obj;
00133                 } else {
00134                     delete thrown_obj;
00135                 }
00136             }
00137             if (it->m_write_done_event != NULL) {
00138                 it->m_write_done_event->notify();
00139             }
00140         }
00141         m_write_call_vector->clear();
00142 
00143         // consume event
00144         *m_pending_write_event_notified = false;
00145         // wait for next activation
00146         ::sc_core::wait();
00147     }
00148 }
00149 
00150 void rc_driver_object_base::safe_event_notify(sc_event& e)
00151 {
00152     static bool          s_is_update_phase = false;
00153     static sc_dt::uint64 s_last_delta = 0;
00154 
00155     if (s_is_update_phase == true) {
00156         if (s_last_delta == sc_delta_count()) {
00157             e.notify(SC_ZERO_TIME);
00158             return;
00159         } else {
00160             s_is_update_phase = false;
00161         }
00162     }
00163     try {
00164         e.notify();
00165     } catch(sc_report r) {
00166         s_is_update_phase = true;
00167         s_last_delta = sc_delta_count();
00168         e.notify(SC_ZERO_TIME);
00169     }
00170 }
00171 
00172 namespace internals {
00173 namespace driver_object {
00174 
00175 void nb_driver_access_call::operator()(
00176     driver_object_type& dobj, call_type call_obj)
00177 {
00178     // create the write call and append it to the write call vector
00179     dobj.m_write_call_vector->push_back(write_call(call_obj));
00180     // signal the driver object that a new write call is pending
00181     //   by notifying the pending write event
00182     if (!*dobj.m_pending_write_event_notified) {
00183         *dobj.m_pending_write_event_notified = true;    
00184         rc_driver_object_base::safe_event_notify(
00185             *dobj.m_pending_write_event);
00186     }
00187 }
00188 
00189 void driver_access_call<void>::operator()(
00190     driver_object_type& dobj, call_type call_obj) const
00191 {
00192     // create the event that will indicate the execution of the call
00193     sc_event write_done_event;
00194     // initialise the thrown_obj to NULL
00195     rc_throwable* thrown_obj = NULL;
00196     // create the write call and append it to the write call vector
00197     dobj.m_write_call_vector->push_back(
00198         write_call(call_obj, &write_done_event, &thrown_obj));
00199     // signal the driver object that a new write call is pending
00200     //   by notifying the pending write event
00201     if (!*dobj.m_pending_write_event_notified) {
00202         *dobj.m_pending_write_event_notified = true;
00203         rc_driver_object_base::safe_event_notify(
00204             *dobj.m_pending_write_event);
00205     }
00206     // wait for the call to be executed
00207     ::sc_core::wait(write_done_event);
00208     // if an event of type rc_throwable occured rethrow it in this context
00209     if (thrown_obj != NULL) {
00210         ::ReChannel::rc_throw(thrown_obj);
00211     }
00212     // execution was successful
00213 }
00214 
00215 } // namespace driver_object
00216 } // namespace internals
00217 
00218 } // namespace ReChannel
00219 
00220 //
00221 // $Id: rc_driver_object.cpp,v 1.5 2007/12/20 20:32:10 felke Exp $
00222 // $Source: /var/cvs/projekte/ReChannel-v2/src/ReChannel/util/rc_driver_object.cpp,v $
00223 //

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