00001 /***************************************************************************** 00002 00003 The following code is derived, directly or indirectly, from the SystemC 00004 source code Copyright (c) 1996-2006 by all Contributors. 00005 All Rights reserved. 00006 00007 The contents of this file are subject to the restrictions and limitations 00008 set forth in the SystemC Open Source License Version 2.4 (the "License"); 00009 You may not use this file except in compliance with such restrictions and 00010 limitations. You may obtain instructions on how to receive a copy of the 00011 License at http://www.systemc.org/. Software distributed by Contributors 00012 under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF 00013 ANY KIND, either express or implied. See the License for the specific 00014 language governing rights and limitations under the License. 00015 00016 *****************************************************************************/ 00017 00018 /***************************************************************************** 00019 00020 sc_runnable_int.h -- For inline definitions of some utility functions. 00021 DO NOT EXPORT THIS INCLUDE FILE. Include this file 00022 after "sc_process_int.h" so that we can get the base 00023 class right. 00024 00025 Original Author: Bishnupriya Bhattacharya , Cadence Design, 28th July, 2003 00026 00027 *****************************************************************************/ 00028 00029 /***************************************************************************** 00030 00031 MODIFICATION LOG - modifiers, enter your name, affiliation, date and 00032 changes you are making here. 00033 Andy Goodrich, Forte Design Systems, 2 September 2003 00034 Changed queue heads to instances to eliminate the checks for null heads. 00035 00036 *****************************************************************************/ 00037 00038 // $Log: sc_runnable_int.h,v $ 00039 // Revision 1.1.1.1 2006/12/15 20:31:37 acg 00040 // SystemC 2.2 00041 // 00042 // Revision 1.4 2006/04/20 17:08:17 acg 00043 // Andy Goodrich: Changed loop end checks to use non-zero unique values 00044 // rather than erroneous check for zero values. 00045 // 00046 // Revision 1.3 2006/01/13 18:44:30 acg 00047 // Added $Log to record CVS changes into the source. 00048 // 00049 00050 #ifndef SC_RUNNABLE_INT_H 00051 #define SC_RUNNABLE_INT_H 00052 00053 00054 #include "sysc/kernel/sc_runnable.h" 00055 #include "sysc/kernel/sc_method_process.h" 00056 #include "sysc/kernel/sc_thread_process.h" 00057 00058 namespace sc_core { 00059 00060 // The values below are used to indicate when a queue is empty. A non-zero 00061 // non-legal pointer value is used for this so that a zero value in the 00062 // m_execute_p field of an sc_process_b instance can be used to indicate 00063 // that is has not been queued for run. (If we did not use a non-zero 00064 // queue empty indicator then a sc_process_b instance that was queued 00065 // twice in a row might end up on the queue twice if it were the first 00066 // one that was queued!) 00067 00068 #define SC_NO_METHODS ((sc_method_handle)0xdb) 00069 #define SC_NO_THREADS ((sc_thread_handle)0xdb) 00070 00071 00072 //------------------------------------------------------------------------------ 00073 //"sc_runnable::init" 00074 // 00075 // This method initializes this object instance. Note we allocate the queue 00076 // heads if necessary. This is done here rather than in the constructor for 00077 // this class to eliminate CTOR processing errors with gcc. 00078 //------------------------------------------------------------------------------ 00079 inline void sc_runnable::init() 00080 { 00081 m_methods_pop = SC_NO_METHODS; 00082 if ( !m_methods_push_head ) 00083 { 00084 m_methods_push_head = 00085 new sc_method_process((const char*)0, true, (SC_ENTRY_FUNC)0, 0, 0); 00086 m_methods_push_head->dont_initialize(true); 00087 } 00088 m_methods_push_tail = m_methods_push_head; 00089 m_methods_push_head->set_next_runnable(SC_NO_METHODS); 00090 00091 m_threads_pop = SC_NO_THREADS; 00092 if ( !m_threads_push_head ) 00093 { 00094 m_threads_push_head = 00095 new sc_thread_process((const char*)0, true, (SC_ENTRY_FUNC)0, 0, 0); 00096 m_threads_push_head->dont_initialize(true); 00097 } 00098 m_threads_push_head->set_next_runnable(SC_NO_THREADS); 00099 m_threads_push_tail = m_threads_push_head; 00100 } 00101 00102 00103 //------------------------------------------------------------------------------ 00104 //"sc_runnable::is_empty" 00105 // 00106 // This method returns true if the push queue is empty, or false if not. 00107 //------------------------------------------------------------------------------ 00108 inline bool sc_runnable::is_empty() const 00109 { 00110 return m_methods_push_head->next_runnable() == SC_NO_METHODS && 00111 m_threads_push_head->next_runnable() == SC_NO_THREADS; 00112 } 00113 00114 00115 //------------------------------------------------------------------------------ 00116 //"sc_runnable::push_back_method" 00117 // 00118 // This method pushes the supplied method process onto the back of the queue of 00119 // runnable method processes. 00120 // method_h -> method process to add to the queue. 00121 //------------------------------------------------------------------------------ 00122 inline void sc_runnable::push_back_method( sc_method_handle method_h ) 00123 { 00124 // assert( method_h->next_runnable() == 0 ); // Can't queue twice. 00125 method_h->set_next_runnable(SC_NO_METHODS); 00126 m_methods_push_tail->set_next_runnable(method_h); 00127 m_methods_push_tail = method_h; 00128 } 00129 00130 00131 //------------------------------------------------------------------------------ 00132 //"sc_runnable::push_back_thread" 00133 // 00134 // This method pushes the supplied thread process onto the back of the queue of 00135 // runnable thread processes. 00136 // thread_h -> thread process to add to the queue. 00137 //------------------------------------------------------------------------------ 00138 inline void sc_runnable::push_back_thread( sc_thread_handle thread_h ) 00139 { 00140 // assert( thread_h->next_runnable() == 0 ); // Can't queue twice. 00141 thread_h->set_next_runnable(SC_NO_THREADS); 00142 m_threads_push_tail->set_next_runnable(thread_h); 00143 m_threads_push_tail = thread_h; 00144 } 00145 00146 00147 //------------------------------------------------------------------------------ 00148 //"sc_runnable::push_front_method" 00149 // 00150 // This method pushes the supplied method process onto the front of the queue of 00151 // runnable method processes. If the queue is empty the process is the tail 00152 // also. 00153 // method_h -> method process to add to the queue. 00154 //------------------------------------------------------------------------------ 00155 inline void sc_runnable::push_front_method( sc_method_handle method_h ) 00156 { 00157 // assert( method_h->next_runnable() == 0 ); // Can't queue twice. 00158 method_h->set_next_runnable(m_methods_push_head->next_runnable()); 00159 if ( m_methods_push_tail == m_methods_push_head ) // Empty queue. 00160 { 00161 m_methods_push_tail->set_next_runnable(method_h); 00162 m_methods_push_tail = method_h; 00163 } 00164 else // Non-empty queue. 00165 { 00166 m_methods_push_head->set_next_runnable(method_h); 00167 } 00168 } 00169 00170 00171 //------------------------------------------------------------------------------ 00172 //"sc_runnable::push_front_thread" 00173 // 00174 // This method pushes the supplied thread process onto the front of the queue of 00175 // runnable thread processes. If the queue is empty the process is the tail 00176 // also. 00177 // thread_h -> thread process to add to the queue. 00178 //------------------------------------------------------------------------------ 00179 inline void sc_runnable::push_front_thread( sc_thread_handle thread_h ) 00180 { 00181 // assert( thread_h->next_runnable() == 0 ); // Can't queue twice. 00182 thread_h->set_next_runnable(m_threads_push_head->next_runnable()); 00183 if ( m_threads_push_tail == m_threads_push_head ) // Empty queue. 00184 { 00185 m_threads_push_tail->set_next_runnable(thread_h); 00186 m_threads_push_tail = thread_h; 00187 } 00188 else // Non-empty queue. 00189 { 00190 m_threads_push_head->set_next_runnable(thread_h); 00191 } 00192 } 00193 00194 00195 //------------------------------------------------------------------------------ 00196 //"sc_runnable::pop_method" 00197 // 00198 // This method pops the next method process to be executed, or returns a null 00199 // if no method processes are available for execution. 00200 //------------------------------------------------------------------------------ 00201 inline sc_method_handle sc_runnable::pop_method() 00202 { 00203 sc_method_handle result_p; 00204 00205 result_p = m_methods_pop; 00206 if ( result_p != SC_NO_METHODS ) 00207 { 00208 m_methods_pop = result_p->next_runnable(); 00209 result_p->set_next_runnable(0); 00210 } 00211 else 00212 { 00213 result_p = 0; 00214 } 00215 return result_p; 00216 00217 } 00218 00219 //------------------------------------------------------------------------------ 00220 //"sc_runnable::pop_thread" 00221 // 00222 // This method pops the next thread process to be executed, or returns a null 00223 // if no thread processes are available for execution. 00224 //------------------------------------------------------------------------------ 00225 inline sc_thread_handle sc_runnable::pop_thread() 00226 { 00227 sc_thread_handle result_p; 00228 00229 result_p = m_threads_pop; 00230 if ( result_p != SC_NO_THREADS ) 00231 { 00232 m_threads_pop = result_p->next_runnable(); 00233 result_p->set_next_runnable(0); 00234 } 00235 else 00236 { 00237 result_p = 0; 00238 } 00239 return result_p; 00240 } 00241 00242 00243 //------------------------------------------------------------------------------ 00244 //"sc_runnable::remove_method" 00245 // 00246 // This method removes the supplied method process from the push queue if it is 00247 // present. Note we clear the method's next pointer so that it may be queued 00248 // again. 00249 // remove_p -> method process to remove from the run queue. 00250 //------------------------------------------------------------------------------ 00251 inline void sc_runnable::remove_method( sc_method_handle remove_p ) 00252 { 00253 sc_method_handle now_p; // Method now checking. 00254 sc_method_handle prior_p; // Method prior to now_p. 00255 00256 prior_p = m_methods_push_head; 00257 for ( now_p = m_methods_push_head; now_p!= SC_NO_METHODS; 00258 now_p = now_p->next_runnable() ) 00259 { 00260 if ( remove_p == now_p ) 00261 { 00262 prior_p->set_next_runnable( now_p->next_runnable() ); 00263 if (now_p == m_methods_push_tail) { 00264 m_methods_push_tail = prior_p; 00265 } 00266 now_p->set_next_runnable(0); 00267 break; 00268 } 00269 prior_p = now_p; 00270 } 00271 } 00272 00273 00274 //------------------------------------------------------------------------------ 00275 //"sc_runnable::remove_thread" 00276 // 00277 // This method removes the supplied thread process from the push queue if it is 00278 // present. Note we clear the thread's next pointer so that it may be queued 00279 // again. 00280 // remove_p -> thread process to remove from the run queue. 00281 //------------------------------------------------------------------------------ 00282 inline void sc_runnable::remove_thread( sc_thread_handle remove_p ) 00283 { 00284 sc_thread_handle now_p; // Thread now checking. 00285 sc_thread_handle prior_p; // Thread prior to now_p. 00286 00287 prior_p = m_threads_push_head; 00288 for ( now_p = m_threads_push_head; now_p != SC_NO_THREADS; 00289 now_p = now_p->next_runnable() ) 00290 { 00291 if ( remove_p == now_p ) 00292 { 00293 prior_p->set_next_runnable( now_p->next_runnable() ); 00294 if (now_p == m_threads_push_tail) { 00295 m_threads_push_tail = prior_p; 00296 } 00297 now_p->set_next_runnable(0); 00298 break; 00299 } 00300 prior_p = now_p; 00301 } 00302 } 00303 00304 //------------------------------------------------------------------------------ 00305 //"sc_runnable::sc_runnable" 00306 // 00307 // This is the object instance constructor for this class. 00308 //------------------------------------------------------------------------------ 00309 inline sc_runnable::sc_runnable() 00310 { 00311 m_methods_pop = 0; 00312 m_methods_push_head = 0; 00313 m_methods_push_tail = 0; 00314 m_threads_pop = 0; 00315 m_threads_push_head = 0; 00316 m_threads_push_tail = 0; 00317 } 00318 00319 00320 //------------------------------------------------------------------------------ 00321 //"sc_runnable::~sc_runnable" 00322 // 00323 // This is the object instance destructor for this class. 00324 //------------------------------------------------------------------------------ 00325 inline sc_runnable::~sc_runnable() 00326 { 00327 delete m_methods_push_head; 00328 delete m_threads_push_head; 00329 } 00330 00331 00332 //------------------------------------------------------------------------------ 00333 //"sc_runnable::toggle" 00334 // 00335 // This method moves the push queue to the pop queue and zeros the push 00336 // queue. 00337 //------------------------------------------------------------------------------ 00338 inline void sc_runnable::toggle() 00339 { 00340 m_methods_pop = m_methods_push_head->next_runnable(); 00341 m_methods_push_head->set_next_runnable(SC_NO_METHODS); 00342 m_methods_push_tail = m_methods_push_head; 00343 m_threads_pop = m_threads_push_head->next_runnable(); 00344 m_threads_push_head->set_next_runnable(SC_NO_THREADS); 00345 m_threads_push_tail = m_threads_push_head; 00346 } 00347 00348 #undef SC_NO_METHODS 00349 #undef SC_NO_THREADS 00350 00351 } // namespace sc_core 00352 00353 #endif // SC_RUNNABLE_INT_H 00354 00355 // Taf!