1/***************************************************************************** 2 3 Licensed to Accellera Systems Initiative Inc. (Accellera) under one or 4 more contributor license agreements. See the NOTICE file distributed 5 with this work for additional information regarding copyright ownership. 6 Accellera licenses this file to you under the Apache License, Version 2.0 7 (the "License"); you may not use this file except in compliance with the 8 License. You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 implied. See the License for the specific language governing 16 permissions and limitations under the License. 17 18 *****************************************************************************/ 19 20/***************************************************************************** 21 22 sc_simcontext_int.h -- For inline definitions of some utility functions. 23 DO NOT EXPORT THIS INCLUDE FILE. Include this file 24 after "sc_process_int.h" so that we can get the base 25 class right. 26 27 Original Author: Stan Y. Liao, Synopsys, Inc. 28 29 CHANGE LOG AT THE END OF THE FILE 30 *****************************************************************************/ 31 32#ifndef SC_SIMCONTEXT_INT_H 33#define SC_SIMCONTEXT_INT_H 34 35#include "sysc/kernel/sc_simcontext.h" 36#include "sysc/kernel/sc_runnable.h" 37#include "sysc/kernel/sc_runnable_int.h" 38 39// DEBUGGING MACROS: 40// 41// DEBUG_MSG(NAME,P,MSG) 42// MSG = message to print 43// NAME = name that must match the process for the message to print, or 44// null if the message should be printed unconditionally. 45// P = pointer to process message is for, or NULL in which case the 46// message will not print. 47#if 0 48# define DEBUG_NAME "" 49# define DEBUG_MSG(NAME,P,MSG) \ 50 { \ 51 if ( P && ( (strlen(NAME)==0) || !strcmp(NAME,P->name())) ) \ 52 std::cout << "**** " << sc_time_stamp() << " (" \ 53 << sc_get_current_process_name() << "): " << MSG \ 54 << " - " << P->name() << std::endl; \ 55 } 56#else 57# define DEBUG_MSG(NAME,P,MSG) 58#endif 59 60 61namespace sc_core { 62 63inline 64const char* 65sc_get_current_process_name() 66{ 67 sc_process_b* active_p; // active process to get name of. 68 const char* result; // name of active process. 69 70 active_p = sc_get_curr_simcontext()->get_curr_proc_info()->process_handle; 71 if ( active_p ) 72 result = active_p->name(); 73 else 74 result = "** NONE **"; 75 return result; 76} 77 78// We use m_current_writer rather than m_curr_proc_info.process_handle to 79// return the active process for sc_signal<T>::check_write since that lets 80// us turn it off a library compile time, and only incur the overhead at 81// the time of process switches rather than having to interrogate an 82// additional switch every time a signal is written. 83 84inline 85void 86sc_simcontext::set_curr_proc( sc_process_b* process_h ) 87{ 88 m_curr_proc_info.process_handle = process_h; 89 m_curr_proc_info.kind = process_h->proc_kind(); 90 m_current_writer = m_write_check ? process_h : (sc_object*)0; 91} 92 93inline 94void 95sc_simcontext::reset_curr_proc() 96{ 97 m_curr_proc_info.process_handle = 0; 98 m_curr_proc_info.kind = SC_NO_PROC_; 99 m_current_writer = 0; 100 sc_process_b::m_last_created_process_p = 0; 101} 102 103inline 104void 105sc_simcontext::execute_method_next( sc_method_handle method_h ) 106{ 107 m_runnable->execute_method_next( method_h ); 108} 109 110inline 111void 112sc_simcontext::execute_thread_next( sc_thread_handle thread_h ) 113{ 114 m_runnable->execute_thread_next( thread_h ); 115} 116 117// +---------------------------------------------------------------------------- 118// |"sc_simcontext::preempt_with" 119// | 120// | This method executes the supplied thread immediately, suspending the 121// | caller. After executing the supplied thread the caller's execution will 122// | be restored. It is used to allow a thread to immediately throw an 123// | exception, e.g., when the thread's kill_process() method was called. 124// | There are three cases to consider: 125// | (1) The caller is a method, e.g., murder by method. 126// | (2) The caller is another thread instance, e.g., murder by thread. 127// | (3) The caller is this thread instance, e.g., suicide. 128// | 129// | Arguments: 130// | thread_h -> thread to be executed. 131// +---------------------------------------------------------------------------- 132inline 133void 134sc_simcontext::preempt_with( sc_thread_handle thread_h ) 135{ 136 sc_thread_handle active_p; // active thread or null. 137 sc_curr_proc_info caller_info; // process info for caller. 138 139 // Determine the active process and take the thread to be run off the 140 // run queue, if its there, since we will be explicitly causing its 141 // execution. 142 143 active_p = DCAST<sc_thread_handle>(sc_get_current_process_b()); 144 if ( thread_h->next_runnable() != NULL ) 145 remove_runnable_thread( thread_h ); 146 147 // THE CALLER IS A METHOD: 148 // 149 // (a) Set the current process information to our thread. 150 // (b) If the method was called by an invoker thread push that thread 151 // onto the front of the run queue, this will cause the method 152 // to be resumed after this thread waits. 153 // (c) Invoke our thread directly by-passing the run queue. 154 // (d) Restore the process info to the caller. 155 // (e) Check to see if the calling method should throw an exception 156 // because of activity that occurred during the preemption. 157 158 if ( active_p == NULL ) 159 { 160 std::vector<sc_thread_handle>* invokers_p; // active invokers stack. 161 sc_thread_handle invoke_thread_p; // latest invocation thread. 162 sc_method_handle method_p; // active method. 163 164 method_p = DCAST<sc_method_handle>(sc_get_current_process_b()); 165 invokers_p = &get_active_invokers(); 166 caller_info = m_curr_proc_info; 167 if ( invokers_p->size() != 0 ) 168 { 169 invoke_thread_p = invokers_p->back(); 170 DEBUG_MSG( DEBUG_NAME, invoke_thread_p, 171 "queueing invocation thread to execute next" ); 172 execute_thread_next(invoke_thread_p); 173 } 174 DEBUG_MSG( DEBUG_NAME, thread_h, "preempting method with thread" ); 175 set_curr_proc( (sc_process_b*)thread_h ); 176 m_cor_pkg->yield( thread_h->m_cor_p ); 177 m_curr_proc_info = caller_info; 178 DEBUG_MSG(DEBUG_NAME, thread_h, "back from preempting method w/thread"); 179 method_p->check_for_throws(); 180 } 181 182 // CALLER IS A THREAD, BUT NOT THE THREAD TO BE RUN: 183 // 184 // (a) Push the calling thread onto the front of the runnable queue 185 // so it be the first thread to be run after this thread. 186 // (b) Push the thread to be run onto the front of the runnable queue so 187 // it will execute when we suspend the calling thread. 188 // (c) Suspend the active thread. 189 190 else if ( active_p != thread_h ) 191 { 192 DEBUG_MSG( DEBUG_NAME, thread_h, 193 "preempting active thread with thread" ); 194 execute_thread_next( active_p ); 195 execute_thread_next( thread_h ); 196 active_p->suspend_me(); 197 } 198 199 // CALLER IS THE THREAD TO BE RUN: 200 // 201 // (a) Push the thread to be run onto the front of the runnable queue so 202 // it will execute when we suspend the calling thread. 203 // (b) Suspend the active thread. 204 205 else 206 { 207 DEBUG_MSG(DEBUG_NAME,thread_h,"self preemption of active thread"); 208 execute_thread_next( thread_h ); 209 active_p->suspend_me(); 210 } 211} 212 213 214inline 215void 216sc_simcontext::push_runnable_method( sc_method_handle method_h ) 217{ 218 m_runnable->push_back_method( method_h ); 219} 220 221inline 222void 223sc_simcontext::push_runnable_method_front( sc_method_handle method_h ) 224{ 225 m_runnable->push_front_method( method_h ); 226} 227 228inline 229void 230sc_simcontext::push_runnable_thread( sc_thread_handle thread_h ) 231{ 232 m_runnable->push_back_thread( thread_h ); 233} 234 235inline 236void 237sc_simcontext::push_runnable_thread_front( sc_thread_handle thread_h ) 238{ 239 m_runnable->push_front_thread( thread_h ); 240} 241 242 243inline 244sc_method_handle 245sc_simcontext::pop_runnable_method() 246{ 247 sc_method_handle method_h = m_runnable->pop_method(); 248 if( method_h == 0 ) { 249 reset_curr_proc(); 250 return 0; 251 } 252 set_curr_proc( (sc_process_b*)method_h ); 253 return method_h; 254} 255 256inline 257sc_thread_handle 258sc_simcontext::pop_runnable_thread() 259{ 260 sc_thread_handle thread_h = m_runnable->pop_thread(); 261 if( thread_h == 0 ) { 262 reset_curr_proc(); 263 return 0; 264 } 265 set_curr_proc( (sc_process_b*)thread_h ); 266 return thread_h; 267} 268 269inline 270void 271sc_simcontext::remove_runnable_method( sc_method_handle method_h ) 272{ 273 m_runnable->remove_method( method_h ); 274} 275 276inline 277void 278sc_simcontext::remove_runnable_thread( sc_thread_handle thread_h ) 279{ 280 m_runnable->remove_thread( thread_h ); 281} 282 283inline 284std::vector<sc_thread_handle>& 285sc_simcontext::get_active_invokers() 286{ 287 return m_active_invokers; 288} 289 290// ---------------------------------------------------------------------------- 291 292extern void sc_defunct_process_function( sc_module* ); 293 294 295} // namespace sc_core 296 297#undef DEBUG_MSG 298#undef DEBUG_NAME 299 300// $Log: sc_simcontext_int.h,v $ 301// Revision 1.14 2011/08/29 18:04:32 acg 302// Philipp A. Hartmann: miscellaneous clean ups. 303// 304// Revision 1.13 2011/08/26 20:46:11 acg 305// Andy Goodrich: moved the modification log to the end of the file to 306// eliminate source line number skew when check-ins are done. 307// 308// Revision 1.12 2011/07/29 22:45:06 acg 309// Andy Goodrich: added invocation of sc_method_process::check_for_throws() 310// to the preempt_with() code to handle case where the preempting process 311// causes a throw on the invoking method process. 312// 313// Revision 1.11 2011/04/13 02:45:11 acg 314// Andy Goodrich: eliminated warning message that occurred if the DEBUG_MSG 315// macro was used. 316// 317// Revision 1.10 2011/04/11 22:05:48 acg 318// Andy Goodrich: use the DEBUG_NAME macro in DEBUG_MSG invocations. 319// 320// Revision 1.9 2011/04/10 22:12:32 acg 321// Andy Goodrich: adding debugging macros. 322// 323// Revision 1.8 2011/04/08 18:26:07 acg 324// Andy Goodrich: added execute_method_next() to handle method dispatch 325// for asynchronous notifications that occur outside the evaluation phase. 326// 327// Revision 1.7 2011/02/18 20:27:14 acg 328// Andy Goodrich: Updated Copyrights. 329// 330// Revision 1.6 2011/02/13 21:47:38 acg 331// Andy Goodrich: update copyright notice. 332// 333// Revision 1.5 2011/02/08 08:17:50 acg 334// Andy Goodrich: fixed bug in preempt_with() where I was resetting the 335// process context rather than saving and restoring it. 336// 337// Revision 1.4 2011/02/01 21:12:56 acg 338// Andy Goodrich: addition of preempt_with() method to allow immediate 339// execution of threads for throws. 340// 341// Revision 1.3 2011/01/25 20:50:37 acg 342// Andy Goodrich: changes for IEEE 1666 2011. 343// 344// Revision 1.2 2008/05/22 17:06:26 acg 345// Andy Goodrich: updated copyright notice to include 2008. 346// 347// Revision 1.1.1.1 2006/12/15 20:20:05 acg 348// SystemC 2.3 349// 350// Revision 1.6 2006/05/26 20:33:16 acg 351// Andy Goodrich: changes required by additional platform compilers (i.e., 352// Microsoft VC++, Sun Forte, HP aCC). 353// 354// Revision 1.5 2006/01/19 00:29:52 acg 355// Andy Goodrich: Yet another implementation for signal write checking. This 356// one uses an environment variable SC_SIGNAL_WRITE_CHECK, that when set to 357// DISABLE will disable write checking on signals. 358// 359// Revision 1.4 2006/01/18 21:42:37 acg 360// Andy Goodrich: Changes for check writer support. 361// 362// Revision 1.3 2006/01/13 18:44:30 acg 363// Added $Log to record CVS changes into the source. 364 365#endif 366