SystemC 3.0.0
Accellera SystemC proof-of-concept library
sc_thread_process.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_thread_process.h -- Thread process declarations
23
24 Original Author: Andy Goodrich, Forte Design Systems, 4 August 2005
25
26
27 CHANGE LOG AT THE END OF THE FILE
28 *****************************************************************************/
29
30
31#if !defined(sc_thread_process_h_INCLUDED)
32#define sc_thread_process_h_INCLUDED
33
36#include "sysc/kernel/sc_cor.h"
40
41// DEBUGGING MACROS:
42//
43// DEBUG_MSG(NAME,P,MSG)
44// MSG = message to print
45// NAME = name that must match the process for the message to print, or
46// null if the message should be printed unconditionally.
47// P = pointer to process message is for, or NULL in which case the
48// message will not print.
49#if 0
50# include <cstring>
51# define DEBUG_NAME ""
52# define DEBUG_MSG(NAME,P,MSG) \
53 { \
54 if ( P && ( (std::strlen(NAME)==0) || !std::strcmp(NAME,P->name())) ) \
55 std::cout << "**** " << sc_time_stamp() << " (" \
56 << sc_get_current_process_name("** NONE **") << "): " << MSG \
57 << " - " << P->name() << std::endl; \
58 }
59#else
60# define DEBUG_MSG(NAME,P,MSG)
61#endif
62
63
64namespace sc_core {
65
66// forward references:
67class sc_event_and_list;
68class sc_event_or_list;
69class sc_reset;
70void sc_thread_cor_fn( void* );
71SC_API void sc_set_stack_size( sc_thread_handle, std::size_t );
72class sc_event;
73class sc_join;
74class sc_module;
75class sc_process_handle;
76class sc_process_table;
77class sc_simcontext;
78class sc_runnable;
79
80sc_cor* get_cor_pointer( sc_process_b* process_p );
81SC_API void sc_set_stack_size( sc_thread_handle thread_h, std::size_t size );
88SC_API void wait( const sc_time&, const sc_event&, sc_simcontext* );
91
92//==============================================================================
93// sc_thread_process -
94//
95//==============================================================================
97 friend void sc_thread_cor_fn( void* );
98 friend void sc_set_stack_size( sc_thread_handle, std::size_t );
99 friend class sc_event;
100 friend class sc_join;
101 friend class sc_module;
102 friend class sc_process_b;
103 friend class sc_process_handle;
104 friend class sc_process_table;
105 friend class sc_simcontext;
106 friend class sc_runnable;
107 friend sc_cor* get_cor_pointer( sc_process_b* process_p );
108
109 friend SC_API void wait( int, sc_simcontext* );
110 friend SC_API void wait( sc_simcontext* );
111 friend SC_API void wait( const sc_event&, sc_simcontext* );
112 friend SC_API void wait( const sc_event_or_list&, sc_simcontext* );
114 friend SC_API void wait( const sc_time&, sc_simcontext* );
115 friend SC_API void wait( const sc_time&, const sc_event&, sc_simcontext* );
116 friend SC_API void wait( const sc_time&, const sc_event_or_list&, sc_simcontext* );
117 friend SC_API void wait( const sc_time&, const sc_event_and_list&, sc_simcontext*);
118
119 public:
120 sc_thread_process( const char* name_p, bool free_host,
121 sc_entry_func method_p, sc_process_host* host_p,
122 const sc_spawn_options* opt_p );
123
124 virtual const char* kind() const
125 { return "sc_thread_process"; }
126
127 protected:
128 // may not be deleted manually (called from sc_process_b)
130
131 virtual void disable_process(
133 virtual void enable_process(
135 virtual void kill_process(
140 virtual void resume_process(
142 void set_next_exist( sc_thread_handle next_p );
143 void set_next_runnable( sc_thread_handle next_p );
144
145 void set_stack_size( std::size_t size );
146 inline void suspend_me();
147 virtual void suspend_process(
149 virtual void throw_reset( bool async );
150 virtual void throw_user( const sc_throw_it_helper& helper,
152
154 inline void trigger_static();
155
156 void wait( const sc_event& );
157 void wait( const sc_event_or_list& );
158 void wait( const sc_event_and_list& );
159 void wait( const sc_time& );
160 void wait( const sc_time&, const sc_event& );
161 void wait( const sc_time&, const sc_event_or_list& );
162 void wait( const sc_time&, const sc_event_and_list& );
163 void wait_cycles( int n=1 );
164
165 protected:
166 void add_monitor( sc_process_monitor* monitor_p );
167 void remove_monitor( sc_process_monitor* monitor_p);
168 void signal_monitors( int type = 0 );
169
170 protected:
171 sc_cor* m_cor_p; // Thread's coroutine.
172 std::vector<sc_process_monitor*> m_monitor_q; // Thread monitors.
173 std::size_t m_stack_size; // Thread stack size.
174 int m_wait_cycle_n; // # of waits to be done.
175
176 private: // disabled
178 const sc_thread_process& operator = ( const sc_thread_process& );
179
180};
181
182//------------------------------------------------------------------------------
183//"sc_thread_process::set_stack_size"
184//
185//------------------------------------------------------------------------------
186inline void sc_thread_process::set_stack_size( std::size_t size )
187{
188 sc_assert( size );
189 m_stack_size = size;
190}
191
192//------------------------------------------------------------------------------
193//"sc_thread_process::suspend_me"
194//
195// This method suspends this object instance in favor of the next runnable
196// process. Upon awakening we check to see if an exception should be thrown.
197// There are two types of exceptions that can be thrown, synchronous reset
198// and asynchronous reset. At a future time there may be more asynchronous
199// exceptions. If an asynchronous reset is seen and there is not static reset
200// specified, or the static reset is not active then clear the throw
201// type for the next time this method is called.
202//
203// Notes:
204// (1) For an explanation of how the reset mechanism works see the top of
205// the file sc_reset.cpp.
206// (2) The m_sticky_reset field is used to handle synchronous resets that
207// are enabled via the sc_process_handle::sync_reset_on() method. These
208// resets are not generated by a signal, but rather are modal by
209// method call: sync_reset_on() - sync_reset_off().
210//------------------------------------------------------------------------------
212{
213 // remember, if we're currently unwinding
214 bool unwinding_preempted = m_unwinding;
215
216 sc_simcontext* simc_p = simcontext();
217 sc_cor* cor_p = simc_p->next_cor();
218
219 // do not switch, if we're about to execute next (e.g. suicide)
220
221 if( m_cor_p != cor_p )
222 {
223 DEBUG_MSG( DEBUG_NAME , this, "suspending thread");
224 simc_p->cor_pkg()->yield( cor_p );
225 DEBUG_MSG( DEBUG_NAME , this, "resuming thread");
226 }
227
228 // IF THERE IS A THROW TO BE DONE FOR THIS PROCESS DO IT NOW:
229 //
230 // (1) Optimize THROW_NONE for speed as it is the normal case.
231 // (2) If this thread is already unwinding then suspend_me() was
232 // called from the catch clause to throw an exception on another
233 // process, so just go back to the catch clause.
234
235 if ( m_throw_status == THROW_NONE ) return;
236
237 if ( m_unwinding ) return;
238
239 switch( m_throw_status )
240 {
242 case THROW_SYNC_RESET:
243 DEBUG_MSG( DEBUG_NAME , this, "throwing reset for");
245 throw sc_unwind_exception( this, true );
246
247 case THROW_USER:
248 DEBUG_MSG( DEBUG_NAME, this, "invoking throw_it for");
251 THROW_NONE);
253 break;
254
255 case THROW_KILL:
256 DEBUG_MSG( DEBUG_NAME, this, "throwing kill for");
257 throw sc_unwind_exception( this, false );
258
259 default: // THROWING_NOW
260 if( !unwinding_preempted )
262 , "unexpected unwinding/throw status" );
263 // may continue, if suppressed
265 DEBUG_MSG( DEBUG_NAME, this, "restarting thread");
266 break;
267 }
268}
269
270
271//------------------------------------------------------------------------------
272//"sc_thread_process::wait"
273//
274//------------------------------------------------------------------------------
275inline
276void
278{
279 if( m_unwinding )
281
282 m_event_p = &e; // for cleanup.
283 e.add_dynamic( this );
285 suspend_me();
286}
287
288inline
289void
291{
292 if( m_unwinding )
294
295 el.add_dynamic( this );
296 m_event_list_p = &el;
298 suspend_me();
299}
300
301inline
302void
304{
305 if( m_unwinding )
307
308 el.add_dynamic( this );
309 m_event_list_p = &el;
310 m_event_count = el.size();
312 suspend_me();
313}
314
315inline
316void
318{
319 if( m_unwinding )
321
322 m_timeout_event_p->notify_internal( t );
323 m_timeout_event_p->add_dynamic( this );
325 suspend_me();
326}
327
328inline
329void
331{
332 if( m_unwinding )
334
335 m_timeout_event_p->notify_internal( t );
336 m_timeout_event_p->add_dynamic( this );
337 e.add_dynamic( this );
338 m_event_p = &e;
340 suspend_me();
341}
342
343inline
344void
346{
347 if( m_unwinding )
349
350 m_timeout_event_p->notify_internal( t );
351 m_timeout_event_p->add_dynamic( this );
352 el.add_dynamic( this );
353 m_event_list_p = &el;
355 suspend_me();
356}
357
358inline
359void
361{
362 if( m_unwinding )
364
365 m_timeout_event_p->notify_internal( t );
366 m_timeout_event_p->add_dynamic( this );
367 el.add_dynamic( this );
368 m_event_list_p = &el;
369 m_event_count = el.size();
371 suspend_me();
372}
373
374//------------------------------------------------------------------------------
375//"sc_thread_process::wait_cycles"
376//
377// This method suspends this object instance for the specified number of cycles.
378// A cycle is defined as the event the thread is set up to staticly wait on.
379// The field m_wait_cycle_n is set to one less than the number of cycles to
380// be waited for, since the value is tested before being decremented in
381// the simulation kernel.
382//------------------------------------------------------------------------------
383inline
384void
386{
387 if( m_unwinding )
389
390 if( n <= 0 )
392
393 m_wait_cycle_n = n-1;
394 suspend_me();
395}
396
397//------------------------------------------------------------------------------
398//"sc_thread_process::miscellaneous support"
399//
400//------------------------------------------------------------------------------
401inline
403{
404 m_monitor_q.push_back(monitor_p);
405}
406
407
408inline
410{
411 int mon_n = m_monitor_q.size();
412
413 for ( int mon_i = 0; mon_i < mon_n; mon_i++ )
414 {
415 if ( m_monitor_q[mon_i] == monitor_p )
416 {
417 m_monitor_q[mon_i] = m_monitor_q[mon_n-1];
418 m_monitor_q.resize(mon_n-1);
419 }
420 }
421}
422
423inline
425{
426 m_exist_p = next_p;
427}
428
429inline
431{
433}
434
435inline
437{
438 m_runnable_p = next_p;
439}
440
441inline
443{
445}
446
448{
449 sc_thread_handle thread_p = dynamic_cast<sc_thread_handle>(process_p);
450 return thread_p->m_cor_p;
451}
452
453//------------------------------------------------------------------------------
454//"sc_thread_process::trigger_static"
455//
456// This inline method adds the current thread to the queue of runnable
457// processes if required. This is the case if the following criteria
458// are met:
459// (1) The process is in a runnable state.
460// (2) The process is not already on the run queue.
461// (3) The process is expecting a static trigger,
462// dynamic event waits take priority.
463// (4) The process' static wait count is zero.
464//
465// Notes:
466// (1) See note 1 in the header for sc_simcontext::prepare_to_simulate (in
467// file sc_simcontext.cpp) for a diagram showing the state transitions
468// for processes.
469// (2) If the triggering process is the same process, the trigger is
470// ignored as well.
471//------------------------------------------------------------------------------
472inline
473void
475{
476 // No need to try queueing this thread if one of the following is true:
477 // (a) it is disabled
478 // (b) it is already queued for execution
479 // (c) it is waiting on a dynamic event
480 // (d) its wait count is not satisfied and it is not currently in reset
481
482 if ( (m_state & ps_bit_disabled) || is_runnable() ||
484 return;
485
486 if( SC_UNLIKELY_( sc_get_current_process_b() == this ) )
487 {
489 return;
490 }
491
493 {
495 return;
496 }
497
498 // If we get here, then the thread has satisfied its wait criteria. If it is
499 // suspended, then mark its state as ready to run. If it is not suspended,
500 // then push it onto the runnable queue.
501
503 {
505 return;
506 }
507
508 simcontext()->push_runnable_thread(this);
509}
510
511#undef DEBUG_MSG
512#undef DEBUG_NAME
513
514} // namespace sc_core
515
516// $Log: sc_thread_process.h,v $
517// Revision 1.30 2011/08/26 20:46:11 acg
518// Andy Goodrich: moved the modification log to the end of the file to
519// eliminate source line number skew when check-ins are done.
520//
521// Revision 1.29 2011/08/24 23:36:12 acg
522// Andy Goodrich: removed break statements that can never be reached and
523// which causes warnings in the Greenhills C++ compiler.
524//
525// Revision 1.28 2011/04/14 22:34:27 acg
526// Andy Goodrich: removed dead code.
527//
528// Revision 1.27 2011/04/13 05:02:18 acg
529// Andy Goodrich: added missing check to the wake up code in suspend_me()
530// so that we just return if the call to suspend_me() was issued from a
531// stack unwinding.
532//
533// Revision 1.26 2011/04/13 02:44:26 acg
534// Andy Goodrich: added m_unwinding flag in place of THROW_NOW because the
535// throw status will be set back to THROW_*_RESET if reset is active and
536// the check for an unwind being complete was expecting THROW_NONE as the
537// clearing of THROW_NOW.
538//
539// Revision 1.25 2011/04/11 22:05:14 acg
540// Andy Goodrich: use the DEBUG_NAME macro in DEBUG_MSG invocations.
541//
542// Revision 1.24 2011/04/10 22:12:32 acg
543// Andy Goodrich: adding debugging macros.
544//
545// Revision 1.23 2011/04/08 22:41:28 acg
546// Andy Goodrich: added comment pointing to the description of the reset
547// mechanism in sc_reset.cpp.
548//
549// Revision 1.22 2011/04/08 18:27:33 acg
550// Andy Goodrich: added check to make sure we don't schedule a running process
551// because of it issues a notify() it is sensitive to.
552//
553// Revision 1.21 2011/04/05 06:22:38 acg
554// Andy Goodrich: expanded comment for trigger_static() initial vetting.
555//
556// Revision 1.20 2011/04/01 21:24:57 acg
557// Andy Goodrich: removed unused code.
558//
559// Revision 1.19 2011/02/19 08:30:53 acg
560// Andy Goodrich: Moved process queueing into trigger_static from
561// sc_event::notify.
562//
563// Revision 1.18 2011/02/18 20:27:14 acg
564// Andy Goodrich: Updated Copyrights.
565//
566// Revision 1.17 2011/02/17 19:55:58 acg
567// Andy Goodrich:
568// (1) Changed signature of trigger_dynamic() back to a bool.
569// (2) Simplified process control usage.
570// (3) Changed trigger_static() to recognize process controls and to
571// do the down-count on wait(N), allowing the elimination of
572// ready_to_run().
573//
574// Revision 1.16 2011/02/16 22:37:31 acg
575// Andy Goodrich: clean up to remove need for ps_disable_pending.
576//
577// Revision 1.15 2011/02/13 21:47:38 acg
578// Andy Goodrich: update copyright notice.
579//
580// Revision 1.14 2011/02/13 21:35:54 acg
581// Andy Goodrich: added error for performing a wait() during unwinding.
582//
583// Revision 1.13 2011/02/11 13:25:24 acg
584// Andy Goodrich: Philipp A. Hartmann's changes:
585// (1) Removal of SC_CTHREAD method overloads.
586// (2) New exception processing code.
587//
588// Revision 1.12 2011/02/01 23:01:53 acg
589// Andy Goodrich: removed dead code.
590//
591// Revision 1.11 2011/02/01 21:18:01 acg
592// Andy Goodrich:
593// (1) Changes in throw processing for new process control rules.
594// (2) Support of new process_state enum values.
595//
596// Revision 1.10 2011/01/25 20:50:37 acg
597// Andy Goodrich: changes for IEEE 1666 2011.
598//
599// Revision 1.9 2011/01/19 23:21:50 acg
600// Andy Goodrich: changes for IEEE 1666 2011
601//
602// Revision 1.8 2011/01/18 20:10:45 acg
603// Andy Goodrich: changes for IEEE1666_2011 semantics.
604//
605// Revision 1.7 2011/01/06 17:59:58 acg
606// Andy Goodrich: removed debugging output.
607//
608// Revision 1.6 2010/07/22 20:02:33 acg
609// Andy Goodrich: bug fixes.
610//
611// Revision 1.5 2009/07/28 01:10:53 acg
612// Andy Goodrich: updates for 2.3 release candidate.
613//
614// Revision 1.4 2009/05/22 16:06:29 acg
615// Andy Goodrich: process control updates.
616//
617// Revision 1.3 2009/03/12 22:59:58 acg
618// Andy Goodrich: updates for 2.4 stuff.
619//
620// Revision 1.2 2008/05/22 17:06:06 acg
621// Andy Goodrich: formatting and comments.
622//
623// Revision 1.1.1.1 2006/12/15 20:20:05 acg
624// SystemC 2.3
625//
626// Revision 1.7 2006/05/08 17:57:13 acg
627// Andy Goodrich: Added David Long's forward declarations for friend functions
628// to keep the Microsoft C++ compiler happy.
629//
630// Revision 1.6 2006/04/20 17:08:17 acg
631// Andy Goodrich: 3.0 style process changes.
632//
633// Revision 1.5 2006/04/11 23:13:21 acg
634// Andy Goodrich: Changes for reduced reset support that only includes
635// sc_cthread, but has preliminary hooks for expanding to method and thread
636// processes also.
637//
638// Revision 1.4 2006/01/24 20:49:05 acg
639// Andy Goodrich: changes to remove the use of deprecated features within the
640// simulator, and to issue warning messages when deprecated features are used.
641//
642// Revision 1.3 2006/01/13 18:44:30 acg
643// Added $Log to record CVS changes into the source.
644
645#endif // !defined(sc_thread_process_h_INCLUDED)
#define SC_UNLIKELY_(x)
Definition: sc_cmnhdr.h:87
#define SC_API
Definition: sc_cmnhdr.h:148
#define DEBUG_MSG(NAME, P, MSG)
#define SC_REPORT_FATAL(msg_type, msg)
Definition: sc_report.h:221
#define sc_assert(expr)
Definition: sc_report.h:248
#define SC_REPORT_ERROR(msg_type, msg)
Definition: sc_report.h:217
const char SC_ID_WAIT_NEGATIVE_CYCLES_[]
class SC_API sc_simcontext
Definition: sc_object.h:50
SC_API void sc_set_stack_size(sc_method_handle, std::size_t)
class SC_API sc_reset
Definition: sc_signal.h:390
class SC_API sc_event
Definition: sc_interface.h:36
SC_API void wait(int, sc_simcontext *)
SC_API const char SC_ID_INTERNAL_ERROR_[]
const char SC_ID_WAIT_DURING_UNWINDING_[]
class sc_thread_process * sc_thread_handle
Definition: sc_process.h:62
sc_cor * get_cor_pointer(sc_process_b *process_p)
void sc_thread_cor_fn(void *arg)
void(sc_process_host::* sc_entry_func)()
Definition: sc_process.h:132
sc_process_b * sc_get_current_process_b()
class SC_API sc_module
Definition: sc_object.h:44
sc_descendant_inclusion_info
Definition: sc_process.h:77
@ SC_NO_DESCENDANTS
Definition: sc_process.h:78
virtual void yield(sc_cor *next_cor)=0
int size() const
Definition: sc_event.h:576
void add_dynamic(sc_method_handle) const
const char * name() const
Definition: sc_object.h:122
sc_simcontext * simcontext() const
Definition: sc_object.h:136
virtual void throw_it()=0
sc_event * m_reset_event_p
Definition: sc_process.h:382
void report_immediate_self_notification() const
trigger_t m_trigger_type
Definition: sc_process.h:395
sc_process_b * m_runnable_p
Definition: sc_process.h:384
process_throw_type m_throw_status
Definition: sc_process.h:392
const sc_event_list * m_event_list_p
Definition: sc_process.h:372
sc_throw_it_helper * m_throw_helper_p
Definition: sc_process.h:391
sc_event * m_timeout_event_p
Definition: sc_process.h:394
friend class sc_unwind_exception
Definition: sc_process.h:224
sc_process_b * m_exist_p
Definition: sc_process.h:373
friend class sc_thread_process
Definition: sc_process.h:211
const sc_event * m_event_p
Definition: sc_process.h:370
bool is_runnable() const
Definition: sc_process.h:481
sc_cor_pkg * cor_pkg()
void signal_monitors(int type=0)
virtual void kill_process(sc_descendant_inclusion_info descendants=SC_NO_DESCENDANTS)
sc_thread_handle next_runnable()
friend SC_API void wait(const sc_time &, const sc_event_or_list &, sc_simcontext *)
friend SC_API void wait(const sc_event &, sc_simcontext *)
friend SC_API void wait(const sc_time &, const sc_event &, sc_simcontext *)
friend void sc_thread_cor_fn(void *)
virtual void resume_process(sc_descendant_inclusion_info descendants=SC_NO_DESCENDANTS)
virtual const char * kind() const
void set_next_runnable(sc_thread_handle next_p)
friend void sc_set_stack_size(sc_thread_handle, std::size_t)
std::vector< sc_process_monitor * > m_monitor_q
sc_thread_handle next_exist()
void set_next_exist(sc_thread_handle next_p)
friend SC_API void wait(const sc_event_or_list &, sc_simcontext *)
virtual void throw_user(const sc_throw_it_helper &helper, sc_descendant_inclusion_info descendants=SC_NO_DESCENDANTS)
friend SC_API void wait(const sc_time &, sc_simcontext *)
virtual void enable_process(sc_descendant_inclusion_info descendants=SC_NO_DESCENDANTS)
void remove_monitor(sc_process_monitor *monitor_p)
virtual void prepare_for_simulation()
friend SC_API void wait(const sc_time &, const sc_event_and_list &, sc_simcontext *)
friend SC_API void wait(const sc_event_and_list &, sc_simcontext *)
bool trigger_dynamic(sc_event *)
void add_monitor(sc_process_monitor *monitor_p)
virtual void suspend_process(sc_descendant_inclusion_info descendants=SC_NO_DESCENDANTS)
friend SC_API void wait(sc_simcontext *)
virtual void throw_reset(bool async)
sc_thread_process(const char *name_p, bool free_host, sc_entry_func method_p, sc_process_host *host_p, const sc_spawn_options *opt_p)
void set_stack_size(std::size_t size)
virtual void disable_process(sc_descendant_inclusion_info descendants=SC_NO_DESCENDANTS)
friend sc_cor * get_cor_pointer(sc_process_b *process_p)
friend SC_API void wait(int, sc_simcontext *)