00001 /***************************************************************************** 00002 00003 The following code is derived, directly or indirectly, from the SystemC 00004 source code Copyright (c) 1996-2005 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 #ifndef SC_RUNNABLE_INT_H 00039 #define SC_RUNNABLE_INT_H 00040 00041 00042 #include "sysc/kernel/sc_runnable.h" 00043 00044 namespace sc_core { 00045 00046 // The values below are used to indicate when a queue is empty. A non-zero 00047 // non-legal pointer value is used for this so that a zero value in the 00048 // m_execute_p field of an sc_process_b instance can be used to indicate 00049 // that is has not been queued for run. (If we did not use a non-zero 00050 // queue empty indicator then a sc_process_b instance that was queued 00051 // twice in a row might end up on the queue twice if it were the first 00052 // one that was queued!) 00053 00054 #define SC_NO_METHODS ((sc_method_handle)0xdb) 00055 #define SC_NO_THREADS ((sc_thread_handle)0xdb) 00056 00057 00058 //------------------------------------------------------------------------------ 00059 //"sc_runnable::init" 00060 // 00061 // This method initializes this object instance. Note we allocate the queue 00062 // heads if necessary. This is done here rather than in the constructor for 00063 // this class to eliminate CTOR processing errors with gcc. 00064 //------------------------------------------------------------------------------ 00065 inline void sc_runnable::init() 00066 { 00067 m_methods_pop = SC_NO_METHODS; 00068 if ( !m_methods_push_head ) 00069 { 00070 m_methods_push_head = 00071 new sc_method_process(0, 0, 0); 00072 m_methods_push_head->do_initialize(false); 00073 } 00074 m_methods_push_tail = m_methods_push_head; 00075 m_methods_push_head->set_next_runnable(SC_NO_METHODS); 00076 00077 m_threads_pop = SC_NO_THREADS; 00078 if ( !m_threads_push_head ) 00079 { 00080 m_threads_push_head = 00081 new sc_thread_process(0, 0, 0); 00082 m_threads_push_head->do_initialize(false); 00083 } 00084 m_threads_push_head->set_next_runnable(SC_NO_THREADS); 00085 m_threads_push_tail = m_threads_push_head; 00086 } 00087 00088 00089 //------------------------------------------------------------------------------ 00090 //"sc_runnable::is_empty" 00091 // 00092 // This method returns true if the push queue is empty, or false if not. 00093 //------------------------------------------------------------------------------ 00094 inline bool sc_runnable::is_empty() const 00095 { 00096 return m_methods_push_head->next_runnable() == SC_NO_METHODS && 00097 m_threads_push_head->next_runnable() == SC_NO_THREADS; 00098 } 00099 00100 00101 //------------------------------------------------------------------------------ 00102 //"sc_runnable::push_back_method" 00103 // 00104 // This method pushes the supplied method process onto the back of the queue of 00105 // runnable method processes. 00106 // method_h -> method process to add to the queue. 00107 //------------------------------------------------------------------------------ 00108 inline void sc_runnable::push_back_method( sc_method_handle method_h ) 00109 { 00110 // assert( method_h->next_runnable() == 0 ); // Can't queue twice. 00111 method_h->set_next_runnable(SC_NO_METHODS); 00112 m_methods_push_tail->set_next_runnable(method_h); 00113 m_methods_push_tail = method_h; 00114 } 00115 00116 00117 //------------------------------------------------------------------------------ 00118 //"sc_runnable::push_back_thread" 00119 // 00120 // This method pushes the supplied thread process onto the back of the queue of 00121 // runnable thread processes. 00122 // thread_h -> thread process to add to the queue. 00123 //------------------------------------------------------------------------------ 00124 inline void sc_runnable::push_back_thread( sc_thread_handle thread_h ) 00125 { 00126 // assert( thread_h->next_runnable() == 0 ); // Can't queue twice. 00127 thread_h->set_next_runnable(SC_NO_THREADS); 00128 m_threads_push_tail->set_next_runnable(thread_h); 00129 m_threads_push_tail = thread_h; 00130 } 00131 00132 00133 //------------------------------------------------------------------------------ 00134 //"sc_runnable::push_front_method" 00135 // 00136 // This method pushes the supplied method process onto the front of the queue of 00137 // runnable method processes. If the queue is empty the process is the tail 00138 // also. 00139 // method_h -> method process to add to the queue. 00140 //------------------------------------------------------------------------------ 00141 inline void sc_runnable::push_front_method( sc_method_handle method_h ) 00142 { 00143 // assert( method_h->next_runnable() == 0 ); // Can't queue twice. 00144 method_h->set_next_runnable(m_methods_push_head->next_runnable()); 00145 if ( m_methods_push_tail == m_methods_push_head ) // Empty queue. 00146 { 00147 m_methods_push_tail->set_next_runnable(method_h); 00148 m_methods_push_tail = method_h; 00149 } 00150 else // Non-empty queue. 00151 { 00152 m_methods_push_head->set_next_runnable(method_h); 00153 } 00154 } 00155 00156 00157 //------------------------------------------------------------------------------ 00158 //"sc_runnable::push_front_thread" 00159 // 00160 // This method pushes the supplied thread process onto the front of the queue of 00161 // runnable thread processes. If the queue is empty the process is the tail 00162 // also. 00163 // thread_h -> thread process to add to the queue. 00164 //------------------------------------------------------------------------------ 00165 inline void sc_runnable::push_front_thread( sc_thread_handle thread_h ) 00166 { 00167 // assert( thread_h->next_runnable() == 0 ); // Can't queue twice. 00168 thread_h->set_next_runnable(m_threads_push_head->next_runnable()); 00169 if ( m_threads_push_tail == m_threads_push_head ) // Empty queue. 00170 { 00171 m_threads_push_tail->set_next_runnable(thread_h); 00172 m_threads_push_tail = thread_h; 00173 } 00174 else // Non-empty queue. 00175 { 00176 m_threads_push_head->set_next_runnable(thread_h); 00177 } 00178 } 00179 00180 00181 //------------------------------------------------------------------------------ 00182 //"sc_runnable::pop_method" 00183 // 00184 // This method pops the next method process to be executed, or returns a null 00185 // if no method processes are available for execution. 00186 //------------------------------------------------------------------------------ 00187 inline sc_method_handle sc_runnable::pop_method() 00188 { 00189 sc_method_handle result_p; 00190 00191 result_p = m_methods_pop; 00192 if ( result_p != SC_NO_METHODS ) 00193 { 00194 m_methods_pop = result_p->next_runnable(); 00195 result_p->set_next_runnable(0); 00196 } 00197 else 00198 { 00199 result_p = 0; 00200 } 00201 return result_p; 00202 00203 } 00204 00205 //------------------------------------------------------------------------------ 00206 //"sc_runnable::pop_thread" 00207 // 00208 // This method pops the next thread process to be executed, or returns a null 00209 // if no thread processes are available for execution. 00210 //------------------------------------------------------------------------------ 00211 inline sc_thread_handle sc_runnable::pop_thread() 00212 { 00213 sc_thread_handle result_p; 00214 00215 result_p = m_threads_pop; 00216 if ( result_p != SC_NO_THREADS ) 00217 { 00218 m_threads_pop = result_p->next_runnable(); 00219 result_p->set_next_runnable(0); 00220 } 00221 else 00222 { 00223 result_p = 0; 00224 } 00225 return result_p; 00226 } 00227 00228 00229 //------------------------------------------------------------------------------ 00230 //"sc_runnable::remove_method" 00231 // 00232 // This method removes the supplied method process from the push queue if it is 00233 // present. Note we clear the method's next pointer so that it may be queued 00234 // again. 00235 // remove_p -> method process to remove from the run queue. 00236 //------------------------------------------------------------------------------ 00237 inline void sc_runnable::remove_method( sc_method_handle remove_p ) 00238 { 00239 sc_method_handle now_p; // Method now checking. 00240 sc_method_handle prior_p; // Method prior to now_p. 00241 00242 prior_p = m_methods_push_head; 00243 for ( now_p = m_methods_push_head; now_p; now_p = now_p->next_runnable() ) 00244 { 00245 if ( remove_p == now_p ) 00246 { 00247 prior_p->set_next_runnable( now_p->next_runnable() ); 00248 if (now_p == m_methods_push_tail) { 00249 m_methods_push_tail = prior_p; 00250 } 00251 now_p->set_next_runnable(0); 00252 break; 00253 } 00254 prior_p = now_p; 00255 } 00256 } 00257 00258 00259 //------------------------------------------------------------------------------ 00260 //"sc_runnable::remove_thread" 00261 // 00262 // This method removes the supplied thread process from the push queue if it is 00263 // present. Note we clear the thread's next pointer so that it may be queued 00264 // again. 00265 // remove_p -> thread process to remove from the run queue. 00266 //------------------------------------------------------------------------------ 00267 inline void sc_runnable::remove_thread( sc_thread_handle remove_p ) 00268 { 00269 sc_thread_handle now_p; // Thread now checking. 00270 sc_thread_handle prior_p; // Thread prior to now_p. 00271 00272 prior_p = m_threads_push_head; 00273 for ( now_p = m_threads_push_head; now_p; now_p = now_p->next_runnable() ) 00274 { 00275 if ( remove_p == now_p ) 00276 { 00277 prior_p->set_next_runnable( now_p->next_runnable() ); 00278 if (now_p == m_threads_push_tail) { 00279 m_threads_push_tail = prior_p; 00280 } 00281 now_p->set_next_runnable(0); 00282 break; 00283 } 00284 prior_p = now_p; 00285 } 00286 } 00287 00288 //------------------------------------------------------------------------------ 00289 //"sc_runnable::sc_runnable" 00290 // 00291 // This is the object instance constructor for this class. 00292 //------------------------------------------------------------------------------ 00293 inline sc_runnable::sc_runnable() 00294 { 00295 m_methods_pop = 0; 00296 m_methods_push_head = 0; 00297 m_methods_push_tail = 0; 00298 m_threads_pop = 0; 00299 m_threads_push_head = 0; 00300 m_threads_push_tail = 0; 00301 } 00302 00303 00304 //------------------------------------------------------------------------------ 00305 //"sc_runnable::~sc_runnable" 00306 // 00307 // This is the object instance destructor for this class. 00308 //------------------------------------------------------------------------------ 00309 inline sc_runnable::~sc_runnable() 00310 { 00311 delete m_methods_push_head; 00312 delete m_threads_push_head; 00313 } 00314 00315 00316 //------------------------------------------------------------------------------ 00317 //"sc_runnable::toggle" 00318 // 00319 // This method moves the push queue to the pop queue and zeros the push 00320 // queue. 00321 //------------------------------------------------------------------------------ 00322 inline void sc_runnable::toggle() 00323 { 00324 m_methods_pop = m_methods_push_head->next_runnable(); 00325 m_methods_push_head->set_next_runnable(SC_NO_METHODS); 00326 m_methods_push_tail = m_methods_push_head; 00327 m_threads_pop = m_threads_push_head->next_runnable(); 00328 m_threads_push_head->set_next_runnable(SC_NO_THREADS); 00329 m_threads_push_tail = m_threads_push_head; 00330 } 00331 00332 #undef SC_NO_METHODS 00333 #undef SC_NO_THREADS 00334 00335 } // namespace sc_core 00336 00337 #endif // SC_RUNNABLE_INT_H 00338 00339 // Taf!
1.5.1