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 //