sc_runnable_int.h revision 12027:1eb7dc7aa10b
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_runnable_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: Bishnupriya Bhattacharya , Cadence Design, 28th July, 2003 28 29 CHANGE LOG AT THE END OF THE FILE 30 ******************************************************************************/ 31 32#ifndef SC_RUNNABLE_INT_H 33#define SC_RUNNABLE_INT_H 34 35 36#include "sysc/kernel/sc_runnable.h" 37#include "sysc/kernel/sc_method_process.h" 38#include "sysc/kernel/sc_thread_process.h" 39 40// DEBUGGING MACROS: 41// 42// DEBUG_MSG(NAME,P,MSG) 43// MSG = message to print 44// NAME = name that must match the process for the message to print, or 45// null if the message should be printed unconditionally. 46// P = pointer to process message is for, or NULL in which case the 47// message will not print. 48#if 0 49# define DEBUG_NAME "" 50# define DEBUG_MSG(NAME,P,MSG) \ 51 { \ 52 if ( P && ( (strlen(NAME)==0) || !strcmp(NAME,P->name())) ) \ 53 std::cout << "**** " << sc_time_stamp() << " (" \ 54 << sc_get_current_process_name() << "): " << MSG \ 55 << " - " << P->name() << std::endl; \ 56 } 57#else 58# define DEBUG_MSG(NAME,P,MSG) 59#endif 60 61namespace sc_core { 62 63// The values below are used to indicate when a queue is empty. A non-zero 64// non-legal pointer value is used for this so that a zero value in the 65// m_execute_p field of an sc_process_b instance can be used to indicate 66// that is has not been queued for run. (If we did not use a non-zero 67// queue empty indicator then a sc_process_b instance that was queued 68// twice in a row might end up on the queue twice if it were the first 69// one that was queued!) 70 71#define SC_NO_METHODS ((sc_method_handle)0xdb) 72#define SC_NO_THREADS ((sc_thread_handle)0xdb) 73 74 75//------------------------------------------------------------------------------ 76//"sc_runnable::dump" 77// 78// This method dumps the contents of this object instance. 79//------------------------------------------------------------------------------ 80inline void sc_runnable::dump() const 81{ 82 // Dump the thread queues: 83 84 std::cout << "thread pop queue: " << std::endl; 85 for ( sc_thread_handle p = m_threads_pop; p != SC_NO_THREADS; 86 p = p->next_runnable() ) 87 { 88 std::cout << " " << p << std::endl; 89 } 90 91 std::cout << "thread push queue: " << std::endl; 92 for ( sc_thread_handle p = m_threads_push_head->next_runnable(); 93 p != SC_NO_THREADS; p = p->next_runnable() ) 94 { 95 std::cout << " " << p << std::endl; 96 } 97} 98 99//------------------------------------------------------------------------------ 100//"sc_runnable::execute_method_next" 101// 102// This method pushes the the supplied method to execute as the next process. 103// This is done by pushing it onto the front of the m_methods_pop. 104// method_h -> method process to add to the queue. 105//------------------------------------------------------------------------------ 106inline void sc_runnable::execute_method_next( sc_method_handle method_h ) 107{ 108 DEBUG_MSG(DEBUG_NAME,method_h,"pushing this method to execute next"); 109 method_h->set_next_runnable( m_methods_pop ); 110 m_methods_pop = method_h; 111} 112 113//------------------------------------------------------------------------------ 114//"sc_runnable::execute_thread_next" 115// 116// This method pushes the the supplied thread to execute as the next process. 117// This is done by pushing it onto the front of the m_threads_pop. 118// thread_h -> thread process to add to the queue. 119//------------------------------------------------------------------------------ 120inline void sc_runnable::execute_thread_next( sc_thread_handle thread_h ) 121{ 122 DEBUG_MSG(DEBUG_NAME,thread_h,"pushing this thread to execute next"); 123 thread_h->set_next_runnable( m_threads_pop ); 124 m_threads_pop = thread_h; 125} 126 127//------------------------------------------------------------------------------ 128//"sc_runnable::init" 129// 130// This method initializes this object instance. Note we allocate the queue 131// heads if necessary. This is done here rather than in the constructor for 132// this class to eliminate CTOR processing errors with gcc. 133//------------------------------------------------------------------------------ 134inline void sc_runnable::init() 135{ 136 m_methods_pop = SC_NO_METHODS; 137 if ( !m_methods_push_head ) 138 { 139 m_methods_push_head = new sc_method_process("methods_push_head", true, 140 (SC_ENTRY_FUNC)0, 0, 0); 141 m_methods_push_head->dont_initialize(true); 142 m_methods_push_head->detach(); 143 } 144 m_methods_push_tail = m_methods_push_head; 145 m_methods_push_head->set_next_runnable(SC_NO_METHODS); 146 147 m_threads_pop = SC_NO_THREADS; 148 if ( !m_threads_push_head ) 149 { 150 m_threads_push_head = new sc_thread_process("threads_push_head", true, 151 (SC_ENTRY_FUNC)0, 0, 0); 152 m_threads_push_head->dont_initialize(true); 153 m_threads_push_head->detach(); 154 } 155 m_threads_push_head->set_next_runnable(SC_NO_THREADS); 156 m_threads_push_tail = m_threads_push_head; 157} 158 159 160//------------------------------------------------------------------------------ 161//"sc_runnable::is_empty" 162// 163// This method returns true if the push queue is empty, or false if not. 164//------------------------------------------------------------------------------ 165inline bool sc_runnable::is_empty() const 166{ 167 return m_methods_push_head->next_runnable() == SC_NO_METHODS && 168 m_methods_pop == SC_NO_METHODS && 169 m_threads_push_head->next_runnable() == SC_NO_THREADS && 170 m_threads_pop == SC_NO_THREADS; 171} 172 173 174//------------------------------------------------------------------------------ 175//"sc_runnable::is_initialized" 176// 177// This method returns true if the push queue is already initialized. 178//------------------------------------------------------------------------------ 179inline bool sc_runnable::is_initialized() const 180{ 181 return m_methods_push_head && m_threads_push_head; 182} 183 184 185//------------------------------------------------------------------------------ 186//"sc_runnable::push_back_method" 187// 188// This method pushes the supplied method process onto the back of the queue of 189// runnable method processes. 190// method_h -> method process to add to the queue. 191//------------------------------------------------------------------------------ 192inline void sc_runnable::push_back_method( sc_method_handle method_h ) 193{ 194 // assert( method_h->next_runnable() == 0 ); // Can't queue twice. 195 DEBUG_MSG(DEBUG_NAME,method_h,"pushing back method"); 196 method_h->set_next_runnable(SC_NO_METHODS); 197 m_methods_push_tail->set_next_runnable(method_h); 198 m_methods_push_tail = method_h; 199} 200 201 202//------------------------------------------------------------------------------ 203//"sc_runnable::push_back_thread" 204// 205// This method pushes the supplied thread process onto the back of the queue of 206// runnable thread processes. 207// thread_h -> thread process to add to the queue. 208//------------------------------------------------------------------------------ 209inline void sc_runnable::push_back_thread( sc_thread_handle thread_h ) 210{ 211 // assert( thread_h->next_runnable() == 0 ); // Can't queue twice. 212 DEBUG_MSG(DEBUG_NAME,thread_h,"pushing back thread"); 213 thread_h->set_next_runnable(SC_NO_THREADS); 214 m_threads_push_tail->set_next_runnable(thread_h); 215 m_threads_push_tail = thread_h; 216} 217 218 219//------------------------------------------------------------------------------ 220//"sc_runnable::push_front_method" 221// 222// This method pushes the supplied method process onto the front of the queue of 223// runnable method processes. If the queue is empty the process is the tail 224// also. 225// method_h -> method process to add to the queue. 226//------------------------------------------------------------------------------ 227inline void sc_runnable::push_front_method( sc_method_handle method_h ) 228{ 229 // assert( method_h->next_runnable() == 0 ); // Can't queue twice. 230 DEBUG_MSG(DEBUG_NAME,method_h,"pushing front method"); 231 method_h->set_next_runnable(m_methods_push_head->next_runnable()); 232 if ( m_methods_push_tail == m_methods_push_head ) // Empty queue. 233 { 234 m_methods_push_tail->set_next_runnable(method_h); 235 m_methods_push_tail = method_h; 236 } 237 else // Non-empty queue. 238 { 239 m_methods_push_head->set_next_runnable(method_h); 240 } 241} 242 243 244//------------------------------------------------------------------------------ 245//"sc_runnable::push_front_thread" 246// 247// This method pushes the supplied thread process onto the front of the queue of 248// runnable thread processes. If the queue is empty the process is the tail 249// also. 250// thread_h -> thread process to add to the queue. 251//------------------------------------------------------------------------------ 252inline void sc_runnable::push_front_thread( sc_thread_handle thread_h ) 253{ 254 // assert( thread_h->next_runnable() == 0 ); // Can't queue twice. 255 DEBUG_MSG(DEBUG_NAME,thread_h,"pushing front thread"); 256 thread_h->set_next_runnable(m_threads_push_head->next_runnable()); 257 if ( m_threads_push_tail == m_threads_push_head ) // Empty queue. 258 { 259 m_threads_push_tail->set_next_runnable(thread_h); 260 m_threads_push_tail = thread_h; 261 } 262 else // Non-empty queue. 263 { 264 m_threads_push_head->set_next_runnable(thread_h); 265 } 266} 267 268//------------------------------------------------------------------------------ 269//"sc_runnable::pop_method" 270// 271// This method pops the next method process to be executed, or returns a null 272// if no method processes are available for execution. 273//------------------------------------------------------------------------------ 274inline sc_method_handle sc_runnable::pop_method() 275{ 276 sc_method_handle result_p; 277 278 result_p = m_methods_pop; 279 if ( result_p != SC_NO_METHODS ) 280 { 281 m_methods_pop = result_p->next_runnable(); 282 result_p->set_next_runnable(0); 283 } 284 else 285 { 286 result_p = 0; 287 } 288 DEBUG_MSG(DEBUG_NAME,result_p,"popping method"); 289 return result_p; 290 291} 292 293//------------------------------------------------------------------------------ 294//"sc_runnable::pop_thread" 295// 296// This method pops the next thread process to be executed, or returns a null 297// if no thread processes are available for execution. 298//------------------------------------------------------------------------------ 299inline sc_thread_handle sc_runnable::pop_thread() 300{ 301 sc_thread_handle result_p; 302 303 result_p = m_threads_pop; 304 if ( result_p != SC_NO_THREADS ) 305 { 306 m_threads_pop = result_p->next_runnable(); 307 result_p->set_next_runnable(0); 308 } 309 else 310 { 311 result_p = 0; 312 } 313 DEBUG_MSG(DEBUG_NAME,result_p,"popping thread for execution"); 314 return result_p; 315} 316 317 318//------------------------------------------------------------------------------ 319//"sc_runnable::remove_method" 320// 321// This method removes the supplied method process from the push queue if it is 322// present. Note we clear the method's next pointer so that it may be queued 323// again. 324// remove_p -> method process to remove from the run queue. 325//------------------------------------------------------------------------------ 326inline void sc_runnable::remove_method( sc_method_handle remove_p ) 327{ 328 sc_method_handle now_p; // Method now checking. 329 sc_method_handle prior_p; // Method prior to now_p. 330 331 // Don't try to remove things if we have not been initialized. 332 333 if ( !is_initialized() ) return; 334 335 // Search the push queue: 336 337 prior_p = m_methods_push_head; 338 for ( now_p = m_methods_push_head; now_p!= SC_NO_METHODS; 339 now_p = now_p->next_runnable() ) 340 { 341 if ( remove_p == now_p ) 342 { 343 prior_p->set_next_runnable( now_p->next_runnable() ); 344 if (now_p == m_methods_push_tail) { 345 m_methods_push_tail = prior_p; 346 } 347 now_p->set_next_runnable(0); 348 DEBUG_MSG(DEBUG_NAME,now_p,"removing method from push queue"); 349 return; 350 } 351 prior_p = now_p; 352 } 353 354 // Search the pop queue: 355 356 prior_p = NULL; 357 for ( now_p = m_methods_pop; now_p != SC_NO_METHODS; 358 now_p = now_p->next_runnable() ) 359 { 360 if ( remove_p == now_p ) 361 { 362 if ( prior_p ) 363 prior_p->set_next_runnable( now_p->next_runnable() ); 364 else 365 m_methods_pop = now_p->next_runnable(); 366 now_p->set_next_runnable(0); 367 DEBUG_MSG(DEBUG_NAME,now_p,"removing method from pop queue"); 368 return; 369 } 370 prior_p = now_p; 371 } 372} 373 374 375//------------------------------------------------------------------------------ 376//"sc_runnable::remove_thread" 377// 378// This method removes the supplied thread process from the push or pop 379// queue if it is present. Note we clear the thread's next pointer so that it 380// may be queued again. 381// remove_p -> thread process to remove from the run queue. 382//------------------------------------------------------------------------------ 383inline void sc_runnable::remove_thread( sc_thread_handle remove_p ) 384{ 385 sc_thread_handle now_p; // Thread now checking. 386 sc_thread_handle prior_p; // Thread prior to now_p. 387 388 // Don't try to remove things if we have not been initialized. 389 390 if ( !is_initialized() ) return; 391 392 // Search the push queue: 393 394 prior_p = m_threads_push_head; 395 for ( now_p = m_threads_push_head; now_p != SC_NO_THREADS; 396 now_p = now_p->next_runnable() ) 397 { 398 if ( remove_p == now_p ) 399 { 400 prior_p->set_next_runnable( now_p->next_runnable() ); 401 if (now_p == m_threads_push_tail) { 402 m_threads_push_tail = prior_p; 403 } 404 now_p->set_next_runnable(0); 405 DEBUG_MSG(DEBUG_NAME,now_p,"removing thread from push queue"); 406 return; 407 } 408 prior_p = now_p; 409 } 410 411 // Search the pop queue: 412 413 prior_p = NULL; 414 for ( now_p = m_threads_pop; now_p != SC_NO_THREADS; 415 now_p = now_p->next_runnable() ) 416 { 417 if ( remove_p == now_p ) 418 { 419 if ( prior_p ) 420 prior_p->set_next_runnable( now_p->next_runnable() ); 421 else 422 m_threads_pop = now_p->next_runnable(); 423 now_p->set_next_runnable(0); 424 DEBUG_MSG(DEBUG_NAME,now_p,"removing thread from pop queue"); 425 return; 426 } 427 prior_p = now_p; 428 } 429} 430 431//------------------------------------------------------------------------------ 432//"sc_runnable::sc_runnable" 433// 434// This is the object instance constructor for this class. 435//------------------------------------------------------------------------------ 436inline sc_runnable::sc_runnable() : 437 m_methods_push_head(0), m_methods_push_tail(0), m_methods_pop(SC_NO_METHODS), 438 m_threads_push_head(0), m_threads_push_tail(0), m_threads_pop(SC_NO_THREADS) 439{} 440 441//------------------------------------------------------------------------------ 442//"sc_runnable::~sc_runnable" 443// 444// This is the object instance destructor for this class. 445//------------------------------------------------------------------------------ 446inline sc_runnable::~sc_runnable() 447{ 448 delete m_methods_push_head; 449 delete m_threads_push_head; 450} 451 452 453//------------------------------------------------------------------------------ 454//"sc_runnable::toggle_methods" 455// 456// This method moves the methods push queue to the pop queue and zeros the push 457// queue. This will only be done if the pop queue is presently empty. 458//------------------------------------------------------------------------------ 459inline void sc_runnable::toggle_methods() 460{ 461 if ( m_methods_pop == SC_NO_METHODS ) 462 { 463 m_methods_pop = m_methods_push_head->next_runnable(); 464 m_methods_push_head->set_next_runnable(SC_NO_METHODS); 465 m_methods_push_tail = m_methods_push_head; 466 } 467} 468 469 470//------------------------------------------------------------------------------ 471//"sc_runnable::toggle_threads" 472// 473// This method moves the threads push queue to the pop queue and zeros the push 474// queue. This will only be done if the pop queue is presently empty. 475//------------------------------------------------------------------------------ 476inline void sc_runnable::toggle_threads() 477{ 478 if ( m_threads_pop == SC_NO_THREADS ) 479 { 480 m_threads_pop = m_threads_push_head->next_runnable(); 481 m_threads_push_head->set_next_runnable(SC_NO_THREADS); 482 m_threads_push_tail = m_threads_push_head; 483 } 484} 485 486#undef SC_NO_METHODS 487#undef SC_NO_THREADS 488#undef DEBUG_MSG 489 490} // namespace sc_core 491 492 493/******************************************************************************* 494 495 MODIFICATION LOG - modifiers, enter your name, affiliation, date and 496 changes you are making here. 497 Andy Goodrich, Forte Design Systems, 2 September 2003 498 Changed queue heads to instances to eliminate the checks for null heads. 499 500 ******************************************************************************/ 501 502// $Log: sc_runnable_int.h,v $ 503// Revision 1.19 2011/08/24 22:05:51 acg 504// Torsten Maehne: initialization changes to remove warnings. 505// 506// Revision 1.18 2011/08/07 19:08:04 acg 507// Andy Goodrich: moved logs to end of file so line number synching works 508// better between versions. 509// 510// Revision 1.17 2011/04/13 02:45:11 acg 511// Andy Goodrich: eliminated warning message that occurred if the DEBUG_MSG 512// macro was used. 513// 514// Revision 1.16 2011/04/10 22:18:23 acg 515// Andy Goodrich: debugging message clean up. 516// 517// Revision 1.15 2011/04/08 18:26:07 acg 518// Andy Goodrich: added execute_method_next() to handle method dispatch 519// for asynchronous notifications that occur outside the evaluation phase. 520// 521// Revision 1.14 2011/04/01 21:31:10 acg 522// Andy Goodrich: turn off diagnostic messages by default. 523// 524// Revision 1.13 2011/04/01 21:30:02 acg 525// Andy Goodrich: inserted conditional displays for queue manipulations. 526// 527// Revision 1.12 2011/03/30 00:01:34 acg 528// Philip A. Hartmann: change break to return in remove_method() to short 529// circuit the search the way remove_thread() works. 530// 531// Revision 1.11 2011/03/28 13:02:52 acg 532// Andy Goodrich: Changes for disable() interactions. 533// 534// Revision 1.10 2011/03/06 15:58:17 acg 535// Andy Goodrich: formatting changes. 536// 537// Revision 1.9 2011/02/18 20:27:14 acg 538// Andy Goodrich: Updated Copyrights. 539// 540// Revision 1.8 2011/02/13 21:47:38 acg 541// Andy Goodrich: update copyright notice. 542// 543// Revision 1.7 2011/02/02 06:37:03 acg 544// Andy Goodrich: removed toggle() method since it is no longer used. 545// 546// Revision 1.6 2011/02/01 21:09:13 acg 547// Andy Goodrich: addition of toggle_methods() and toggle_threads() calls. 548// 549// Revision 1.5 2011/01/25 20:50:37 acg 550// Andy Goodrich: changes for IEEE 1666 2011. 551// 552// Revision 1.4 2010/07/22 20:02:33 acg 553// Andy Goodrich: bug fixes. 554// 555// Revision 1.3 2009/02/28 00:26:58 acg 556// Andy Goodrich: changed boost name space to sc_boost to allow use with 557// full boost library applications. 558// 559// Revision 1.2 2008/05/22 17:06:26 acg 560// Andy Goodrich: updated copyright notice to include 2008. 561// 562// Revision 1.1.1.1 2006/12/15 20:20:05 acg 563// SystemC 2.3 564// 565// Revision 1.4 2006/04/20 17:08:17 acg 566// Andy Goodrich: 3.0 style process changes. 567// 568// Revision 1.3 2006/01/13 18:44:30 acg 569// Added $Log to record CVS changes into the source. 570// 571 572#endif // SC_RUNNABLE_INT_H 573 574// Taf! 575