summaryrefslogtreecommitdiff
path: root/ext/systemc/src/sysc/kernel/sc_simcontext_int.h
blob: 039237f4adc52ab72e7f883a3d89334a90c1382d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
/*****************************************************************************

  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
  more contributor license agreements.  See the NOTICE file distributed
  with this work for additional information regarding copyright ownership.
  Accellera licenses this file to you under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with the
  License.  You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
  implied.  See the License for the specific language governing
  permissions and limitations under the License.

 *****************************************************************************/

/*****************************************************************************

  sc_simcontext_int.h -- For inline definitions of some utility functions.
                         DO NOT EXPORT THIS INCLUDE FILE. Include this file
                         after "sc_process_int.h" so that we can get the base
                         class right.

  Original Author: Stan Y. Liao, Synopsys, Inc.

  CHANGE LOG AT THE END OF THE FILE
 *****************************************************************************/

#ifndef SC_SIMCONTEXT_INT_H
#define SC_SIMCONTEXT_INT_H

#include "sysc/kernel/sc_simcontext.h"
#include "sysc/kernel/sc_runnable.h"
#include "sysc/kernel/sc_runnable_int.h"

// DEBUGGING MACROS:
//
// DEBUG_MSG(NAME,P,MSG)
//     MSG  = message to print
//     NAME = name that must match the process for the message to print, or
//            null if the message should be printed unconditionally.
//     P    = pointer to process message is for, or NULL in which case the
//            message will not print.
#if 0
#   define DEBUG_NAME ""
#   define DEBUG_MSG(NAME,P,MSG) \
    { \
        if ( P && ( (strlen(NAME)==0) || !strcmp(NAME,P->name())) ) \
          std::cout << "**** " << sc_time_stamp() << " ("  \
	            << sc_get_current_process_name() << "): " << MSG \
		    << " - " << P->name() << std::endl; \
    }
#else
#   define DEBUG_MSG(NAME,P,MSG) 
#endif


namespace sc_core {

inline
const char*
sc_get_current_process_name()
{
    sc_process_b* active_p; // active process to get name of.
    const char*   result;   // name of active process.

    active_p = sc_get_curr_simcontext()->get_curr_proc_info()->process_handle;
    if ( active_p )
        result = active_p->name();
    else
        result = "** NONE **";
    return result;
}

// We use m_current_writer rather than m_curr_proc_info.process_handle to
// return the active process for sc_signal<T>::check_write since that lets
// us turn it off a library compile time, and only incur the overhead at
// the time of process switches rather than having to interrogate an
// additional switch every time a signal is written.

inline
void
sc_simcontext::set_curr_proc( sc_process_b* process_h )
{
    m_curr_proc_info.process_handle = process_h;
    m_curr_proc_info.kind           = process_h->proc_kind();
    m_current_writer = m_write_check ? process_h : (sc_object*)0;
}

inline
void
sc_simcontext::reset_curr_proc()
{
    m_curr_proc_info.process_handle = 0;
    m_curr_proc_info.kind           = SC_NO_PROC_;
    m_current_writer                = 0;
    sc_process_b::m_last_created_process_p = 0; 
}

inline
void
sc_simcontext::execute_method_next( sc_method_handle method_h )
{
    m_runnable->execute_method_next( method_h );
}

inline
void
sc_simcontext::execute_thread_next( sc_thread_handle thread_h )
{
    m_runnable->execute_thread_next( thread_h );
}

// +----------------------------------------------------------------------------
// |"sc_simcontext::preempt_with"
// | 
// | This method executes the supplied thread immediately, suspending the
// | caller. After executing the supplied thread the caller's execution will
// | be restored. It is used to allow a thread to immediately throw an 
// | exception, e.g., when the thread's kill_process() method was called.
// | There are three cases to consider:
// |   (1) The caller is a method, e.g., murder by method.
// |   (2) The caller is another thread instance, e.g., murder by thread.
// |   (3) The caller is this thread instance, e.g., suicide.
// |
// | Arguments:
// |     thread_h -> thread to be executed.
// +----------------------------------------------------------------------------
inline
void
sc_simcontext::preempt_with( sc_thread_handle thread_h )
{
    sc_thread_handle  active_p;    // active thread or null.
    sc_curr_proc_info caller_info; // process info for caller.

    // Determine the active process and take the thread to be run off the
    // run queue, if its there, since we will be explicitly causing its 
    // execution.

    active_p = DCAST<sc_thread_handle>(sc_get_current_process_b());
    if ( thread_h->next_runnable() != NULL )
	remove_runnable_thread( thread_h );

    // THE CALLER IS A METHOD:
    //
    //   (a) Set the current process information to our thread.
    //   (b) If the method was called by an invoker thread push that thread
    //       onto the front of the run queue, this will cause the method
    //       to be resumed after this thread waits.
    //   (c) Invoke our thread directly by-passing the run queue.
    //   (d) Restore the process info to the caller.
    //   (e) Check to see if the calling method should throw an exception
    //       because of activity that occurred during the preemption.

    if ( active_p == NULL )
    {
	std::vector<sc_thread_handle>* invokers_p;  // active invokers stack.
	sc_thread_handle           invoke_thread_p; // latest invocation thread.
        sc_method_handle           method_p;        // active method.

	method_p = DCAST<sc_method_handle>(sc_get_current_process_b());
	invokers_p = &get_active_invokers();
	caller_info = m_curr_proc_info;
	if ( invokers_p->size() != 0 )
	{
	    invoke_thread_p = invokers_p->back();
	    DEBUG_MSG( DEBUG_NAME, invoke_thread_p, 
	        "queueing invocation thread to execute next" );
	    execute_thread_next(invoke_thread_p);
	}
        DEBUG_MSG( DEBUG_NAME, thread_h, "preempting method with thread" );
	set_curr_proc( (sc_process_b*)thread_h );
	m_cor_pkg->yield( thread_h->m_cor_p );
	m_curr_proc_info = caller_info; 
        DEBUG_MSG(DEBUG_NAME, thread_h, "back from preempting method w/thread");
	method_p->check_for_throws();
    }

    // CALLER IS A THREAD, BUT NOT THE THREAD TO BE RUN:
    //
    //   (a) Push the calling thread onto the front of the runnable queue
    //       so it be the first thread to be run after this thread.
    //   (b) Push the thread to be run onto the front of the runnable queue so 
    //       it will execute when we suspend the calling thread.
    //   (c) Suspend the active thread.

    else if ( active_p != thread_h )
    {
        DEBUG_MSG( DEBUG_NAME, thread_h,
	           "preempting active thread with thread" );
        execute_thread_next( active_p );
	execute_thread_next( thread_h );
	active_p->suspend_me();
    }

    // CALLER IS THE THREAD TO BE RUN:
    //
    //   (a) Push the thread to be run onto the front of the runnable queue so 
    //       it will execute when we suspend the calling thread.
    //   (b) Suspend the active thread.

    else
    {
        DEBUG_MSG(DEBUG_NAME,thread_h,"self preemption of active thread");
	execute_thread_next( thread_h );
	active_p->suspend_me();
    }
}


inline
void
sc_simcontext::push_runnable_method( sc_method_handle method_h )
{
    m_runnable->push_back_method( method_h );
}

inline
void
sc_simcontext::push_runnable_method_front( sc_method_handle method_h )
{
    m_runnable->push_front_method( method_h );
}

inline
void
sc_simcontext::push_runnable_thread( sc_thread_handle thread_h )
{
    m_runnable->push_back_thread( thread_h );
}

inline
void
sc_simcontext::push_runnable_thread_front( sc_thread_handle thread_h )
{
    m_runnable->push_front_thread( thread_h );
}


inline
sc_method_handle
sc_simcontext::pop_runnable_method()
{
    sc_method_handle method_h = m_runnable->pop_method();
    if( method_h == 0 ) {
	reset_curr_proc();
	return 0;
    }
    set_curr_proc( (sc_process_b*)method_h );
    return method_h;
}

inline
sc_thread_handle
sc_simcontext::pop_runnable_thread()
{
    sc_thread_handle thread_h = m_runnable->pop_thread();
    if( thread_h == 0 ) {
	reset_curr_proc();
	return 0;
    }
    set_curr_proc( (sc_process_b*)thread_h );
    return thread_h;
}

inline
void
sc_simcontext::remove_runnable_method( sc_method_handle method_h )
{
    m_runnable->remove_method( method_h );
}

inline
void
sc_simcontext::remove_runnable_thread( sc_thread_handle thread_h )
{
    m_runnable->remove_thread( thread_h );
}

inline
std::vector<sc_thread_handle>&
sc_simcontext::get_active_invokers()
{
    return m_active_invokers;
}

// ----------------------------------------------------------------------------

extern void sc_defunct_process_function( sc_module* );


} // namespace sc_core

#undef DEBUG_MSG
#undef DEBUG_NAME

// $Log: sc_simcontext_int.h,v $
// Revision 1.14  2011/08/29 18:04:32  acg
//  Philipp A. Hartmann: miscellaneous clean ups.
//
// Revision 1.13  2011/08/26 20:46:11  acg
//  Andy Goodrich: moved the modification log to the end of the file to
//  eliminate source line number skew when check-ins are done.
//
// Revision 1.12  2011/07/29 22:45:06  acg
//  Andy Goodrich: added invocation of sc_method_process::check_for_throws()
//  to the preempt_with() code to handle case where the preempting process
//  causes a throw on the invoking method process.
//
// Revision 1.11  2011/04/13 02:45:11  acg
//  Andy Goodrich: eliminated warning message that occurred if the DEBUG_MSG
//  macro was used.
//
// Revision 1.10  2011/04/11 22:05:48  acg
//  Andy Goodrich: use the DEBUG_NAME macro in DEBUG_MSG invocations.
//
// Revision 1.9  2011/04/10 22:12:32  acg
//  Andy Goodrich: adding debugging macros.
//
// Revision 1.8  2011/04/08 18:26:07  acg
//  Andy Goodrich: added execute_method_next() to handle method dispatch
//   for asynchronous notifications that occur outside the evaluation phase.
//
// Revision 1.7  2011/02/18 20:27:14  acg
//  Andy Goodrich: Updated Copyrights.
//
// Revision 1.6  2011/02/13 21:47:38  acg
//  Andy Goodrich: update copyright notice.
//
// Revision 1.5  2011/02/08 08:17:50  acg
//  Andy Goodrich: fixed bug in preempt_with() where I was resetting the
//  process context rather than saving and restoring it.
//
// Revision 1.4  2011/02/01 21:12:56  acg
//  Andy Goodrich: addition of preempt_with() method to allow immediate
//  execution of threads for throws.
//
// Revision 1.3  2011/01/25 20:50:37  acg
//  Andy Goodrich: changes for IEEE 1666 2011.
//
// Revision 1.2  2008/05/22 17:06:26  acg
//  Andy Goodrich: updated copyright notice to include 2008.
//
// Revision 1.1.1.1  2006/12/15 20:20:05  acg
// SystemC 2.3
//
// Revision 1.6  2006/05/26 20:33:16  acg
//   Andy Goodrich: changes required by additional platform compilers (i.e.,
//   Microsoft VC++, Sun Forte, HP aCC).
//
// Revision 1.5  2006/01/19 00:29:52  acg
// Andy Goodrich: Yet another implementation for signal write checking. This
// one uses an environment variable SC_SIGNAL_WRITE_CHECK, that when set to
// DISABLE will disable write checking on signals.
//
// Revision 1.4  2006/01/18 21:42:37  acg
// Andy Goodrich: Changes for check writer support.
//
// Revision 1.3  2006/01/13 18:44:30  acg
// Added $Log to record CVS changes into the source.

#endif