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_simcontext_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: Stan Y. Liao, Synopsys, Inc.
28
29  CHANGE LOG AT THE END OF THE FILE
30 *****************************************************************************/
31
32#ifndef SC_SIMCONTEXT_INT_H
33#define SC_SIMCONTEXT_INT_H
34
35#include "sysc/kernel/sc_simcontext.h"
36#include "sysc/kernel/sc_runnable.h"
37#include "sysc/kernel/sc_runnable_int.h"
38
39// DEBUGGING MACROS:
40//
41// DEBUG_MSG(NAME,P,MSG)
42//     MSG  = message to print
43//     NAME = name that must match the process for the message to print, or
44//            null if the message should be printed unconditionally.
45//     P    = pointer to process message is for, or NULL in which case the
46//            message will not print.
47#if 0
48#   define DEBUG_NAME ""
49#   define DEBUG_MSG(NAME,P,MSG) \
50    { \
51        if ( P && ( (strlen(NAME)==0) || !strcmp(NAME,P->name())) ) \
52          std::cout << "**** " << sc_time_stamp() << " ("  \
53	            << sc_get_current_process_name() << "): " << MSG \
54		    << " - " << P->name() << std::endl; \
55    }
56#else
57#   define DEBUG_MSG(NAME,P,MSG)
58#endif
59
60
61namespace sc_core {
62
63inline
64const char*
65sc_get_current_process_name()
66{
67    sc_process_b* active_p; // active process to get name of.
68    const char*   result;   // name of active process.
69
70    active_p = sc_get_curr_simcontext()->get_curr_proc_info()->process_handle;
71    if ( active_p )
72        result = active_p->name();
73    else
74        result = "** NONE **";
75    return result;
76}
77
78// We use m_current_writer rather than m_curr_proc_info.process_handle to
79// return the active process for sc_signal<T>::check_write since that lets
80// us turn it off a library compile time, and only incur the overhead at
81// the time of process switches rather than having to interrogate an
82// additional switch every time a signal is written.
83
84inline
85void
86sc_simcontext::set_curr_proc( sc_process_b* process_h )
87{
88    m_curr_proc_info.process_handle = process_h;
89    m_curr_proc_info.kind           = process_h->proc_kind();
90    m_current_writer = m_write_check ? process_h : (sc_object*)0;
91}
92
93inline
94void
95sc_simcontext::reset_curr_proc()
96{
97    m_curr_proc_info.process_handle = 0;
98    m_curr_proc_info.kind           = SC_NO_PROC_;
99    m_current_writer                = 0;
100    sc_process_b::m_last_created_process_p = 0;
101}
102
103inline
104void
105sc_simcontext::execute_method_next( sc_method_handle method_h )
106{
107    m_runnable->execute_method_next( method_h );
108}
109
110inline
111void
112sc_simcontext::execute_thread_next( sc_thread_handle thread_h )
113{
114    m_runnable->execute_thread_next( thread_h );
115}
116
117// +----------------------------------------------------------------------------
118// |"sc_simcontext::preempt_with"
119// |
120// | This method executes the supplied thread immediately, suspending the
121// | caller. After executing the supplied thread the caller's execution will
122// | be restored. It is used to allow a thread to immediately throw an
123// | exception, e.g., when the thread's kill_process() method was called.
124// | There are three cases to consider:
125// |   (1) The caller is a method, e.g., murder by method.
126// |   (2) The caller is another thread instance, e.g., murder by thread.
127// |   (3) The caller is this thread instance, e.g., suicide.
128// |
129// | Arguments:
130// |     thread_h -> thread to be executed.
131// +----------------------------------------------------------------------------
132inline
133void
134sc_simcontext::preempt_with( sc_thread_handle thread_h )
135{
136    sc_thread_handle  active_p;    // active thread or null.
137    sc_curr_proc_info caller_info; // process info for caller.
138
139    // Determine the active process and take the thread to be run off the
140    // run queue, if its there, since we will be explicitly causing its
141    // execution.
142
143    active_p = DCAST<sc_thread_handle>(sc_get_current_process_b());
144    if ( thread_h->next_runnable() != NULL )
145	remove_runnable_thread( thread_h );
146
147    // THE CALLER IS A METHOD:
148    //
149    //   (a) Set the current process information to our thread.
150    //   (b) If the method was called by an invoker thread push that thread
151    //       onto the front of the run queue, this will cause the method
152    //       to be resumed after this thread waits.
153    //   (c) Invoke our thread directly by-passing the run queue.
154    //   (d) Restore the process info to the caller.
155    //   (e) Check to see if the calling method should throw an exception
156    //       because of activity that occurred during the preemption.
157
158    if ( active_p == NULL )
159    {
160	std::vector<sc_thread_handle>* invokers_p;  // active invokers stack.
161	sc_thread_handle           invoke_thread_p; // latest invocation thread.
162        sc_method_handle           method_p;        // active method.
163
164	method_p = DCAST<sc_method_handle>(sc_get_current_process_b());
165	invokers_p = &get_active_invokers();
166	caller_info = m_curr_proc_info;
167	if ( invokers_p->size() != 0 )
168	{
169	    invoke_thread_p = invokers_p->back();
170	    DEBUG_MSG( DEBUG_NAME, invoke_thread_p,
171	        "queueing invocation thread to execute next" );
172	    execute_thread_next(invoke_thread_p);
173	}
174        DEBUG_MSG( DEBUG_NAME, thread_h, "preempting method with thread" );
175	set_curr_proc( (sc_process_b*)thread_h );
176	m_cor_pkg->yield( thread_h->m_cor_p );
177	m_curr_proc_info = caller_info;
178        DEBUG_MSG(DEBUG_NAME, thread_h, "back from preempting method w/thread");
179	method_p->check_for_throws();
180    }
181
182    // CALLER IS A THREAD, BUT NOT THE THREAD TO BE RUN:
183    //
184    //   (a) Push the calling thread onto the front of the runnable queue
185    //       so it be the first thread to be run after this thread.
186    //   (b) Push the thread to be run onto the front of the runnable queue so
187    //       it will execute when we suspend the calling thread.
188    //   (c) Suspend the active thread.
189
190    else if ( active_p != thread_h )
191    {
192        DEBUG_MSG( DEBUG_NAME, thread_h,
193	           "preempting active thread with thread" );
194        execute_thread_next( active_p );
195	execute_thread_next( thread_h );
196	active_p->suspend_me();
197    }
198
199    // CALLER IS THE THREAD TO BE RUN:
200    //
201    //   (a) Push the thread to be run onto the front of the runnable queue so
202    //       it will execute when we suspend the calling thread.
203    //   (b) Suspend the active thread.
204
205    else
206    {
207        DEBUG_MSG(DEBUG_NAME,thread_h,"self preemption of active thread");
208	execute_thread_next( thread_h );
209	active_p->suspend_me();
210    }
211}
212
213
214inline
215void
216sc_simcontext::push_runnable_method( sc_method_handle method_h )
217{
218    m_runnable->push_back_method( method_h );
219}
220
221inline
222void
223sc_simcontext::push_runnable_method_front( sc_method_handle method_h )
224{
225    m_runnable->push_front_method( method_h );
226}
227
228inline
229void
230sc_simcontext::push_runnable_thread( sc_thread_handle thread_h )
231{
232    m_runnable->push_back_thread( thread_h );
233}
234
235inline
236void
237sc_simcontext::push_runnable_thread_front( sc_thread_handle thread_h )
238{
239    m_runnable->push_front_thread( thread_h );
240}
241
242
243inline
244sc_method_handle
245sc_simcontext::pop_runnable_method()
246{
247    sc_method_handle method_h = m_runnable->pop_method();
248    if( method_h == 0 ) {
249	reset_curr_proc();
250	return 0;
251    }
252    set_curr_proc( (sc_process_b*)method_h );
253    return method_h;
254}
255
256inline
257sc_thread_handle
258sc_simcontext::pop_runnable_thread()
259{
260    sc_thread_handle thread_h = m_runnable->pop_thread();
261    if( thread_h == 0 ) {
262	reset_curr_proc();
263	return 0;
264    }
265    set_curr_proc( (sc_process_b*)thread_h );
266    return thread_h;
267}
268
269inline
270void
271sc_simcontext::remove_runnable_method( sc_method_handle method_h )
272{
273    m_runnable->remove_method( method_h );
274}
275
276inline
277void
278sc_simcontext::remove_runnable_thread( sc_thread_handle thread_h )
279{
280    m_runnable->remove_thread( thread_h );
281}
282
283inline
284std::vector<sc_thread_handle>&
285sc_simcontext::get_active_invokers()
286{
287    return m_active_invokers;
288}
289
290// ----------------------------------------------------------------------------
291
292extern void sc_defunct_process_function( sc_module* );
293
294
295} // namespace sc_core
296
297#undef DEBUG_MSG
298#undef DEBUG_NAME
299
300// $Log: sc_simcontext_int.h,v $
301// Revision 1.14  2011/08/29 18:04:32  acg
302//  Philipp A. Hartmann: miscellaneous clean ups.
303//
304// Revision 1.13  2011/08/26 20:46:11  acg
305//  Andy Goodrich: moved the modification log to the end of the file to
306//  eliminate source line number skew when check-ins are done.
307//
308// Revision 1.12  2011/07/29 22:45:06  acg
309//  Andy Goodrich: added invocation of sc_method_process::check_for_throws()
310//  to the preempt_with() code to handle case where the preempting process
311//  causes a throw on the invoking method process.
312//
313// Revision 1.11  2011/04/13 02:45:11  acg
314//  Andy Goodrich: eliminated warning message that occurred if the DEBUG_MSG
315//  macro was used.
316//
317// Revision 1.10  2011/04/11 22:05:48  acg
318//  Andy Goodrich: use the DEBUG_NAME macro in DEBUG_MSG invocations.
319//
320// Revision 1.9  2011/04/10 22:12:32  acg
321//  Andy Goodrich: adding debugging macros.
322//
323// Revision 1.8  2011/04/08 18:26:07  acg
324//  Andy Goodrich: added execute_method_next() to handle method dispatch
325//   for asynchronous notifications that occur outside the evaluation phase.
326//
327// Revision 1.7  2011/02/18 20:27:14  acg
328//  Andy Goodrich: Updated Copyrights.
329//
330// Revision 1.6  2011/02/13 21:47:38  acg
331//  Andy Goodrich: update copyright notice.
332//
333// Revision 1.5  2011/02/08 08:17:50  acg
334//  Andy Goodrich: fixed bug in preempt_with() where I was resetting the
335//  process context rather than saving and restoring it.
336//
337// Revision 1.4  2011/02/01 21:12:56  acg
338//  Andy Goodrich: addition of preempt_with() method to allow immediate
339//  execution of threads for throws.
340//
341// Revision 1.3  2011/01/25 20:50:37  acg
342//  Andy Goodrich: changes for IEEE 1666 2011.
343//
344// Revision 1.2  2008/05/22 17:06:26  acg
345//  Andy Goodrich: updated copyright notice to include 2008.
346//
347// Revision 1.1.1.1  2006/12/15 20:20:05  acg
348// SystemC 2.3
349//
350// Revision 1.6  2006/05/26 20:33:16  acg
351//   Andy Goodrich: changes required by additional platform compilers (i.e.,
352//   Microsoft VC++, Sun Forte, HP aCC).
353//
354// Revision 1.5  2006/01/19 00:29:52  acg
355// Andy Goodrich: Yet another implementation for signal write checking. This
356// one uses an environment variable SC_SIGNAL_WRITE_CHECK, that when set to
357// DISABLE will disable write checking on signals.
358//
359// Revision 1.4  2006/01/18 21:42:37  acg
360// Andy Goodrich: Changes for check writer support.
361//
362// Revision 1.3  2006/01/13 18:44:30  acg
363// Added $Log to record CVS changes into the source.
364
365#endif
366