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