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