SIMLIB/C++ 3.09
Loading...
Searching...
No Matches
process.cc
Go to the documentation of this file.
1/////////////////////////////////////////////////////////////////////////////
2//! \file process.cc Implementation of quasiparallel processes (coroutines)
3//!
4//! This module contains implementation of cooperative multitasking processes
5//! for discrete simulation
6
7//
8// Copyright (c) 1991-2022 Petr Peringer
9//
10// This library is licensed under GNU Library GPL. See the file COPYING.
11//
12
13//
14// Implementation of interruptable functions (non-preemptive, coroutine-like)
15//
16// We need code to save/restore process stack contents and working setjmp/longjmp
17// This approach has advantage in smaller memory requirements.
18//
19// LIMITATIONS:
20// - do not use (e.g. using pointers) any locals in Process::Behavior() if it
21// is not in running state (stack contents is moved to heap)
22// - do not use too big locals in Process::Behavior() for performance reasons
23//
24// WARNING: dirty hacks inside
25//
26
27// TODO: add implementation with stack switching (not copying)
28// as compile-time option
29// TODO: add implementation using C++20 coroutines?
30
31
32////////////////////////////////////////////////////////////////////////////
33// interface
34//
35
36#include "simlib.h"
37#include "internal.h"
38
39#include <csetjmp>
40#include <cstring>
41
42static_assert(sizeof(void*) >= 4, "not tested on <32bit systems");
43
44////////////////////////////////////////////////////////////////////////////
45// implementation
46//
47
48namespace simlib3 {
49
51
52////////////////////////////////////////////////////////////////////////////
53
54/**
55 * internal structure for storing of Process::Behavior() context
56 * @ingroup process
57 */
59 jmp_buf status; //!< stored SP, IP, and other registers
60 size_t size; //!< size of following array (allocated on heap)
61 char stack[1]; //!< saved stack contents
62};
63
64////////////////////////////////////////////////////////////////////////////
65// global variables (should be volatile)
66// (P_ means Process)
67// TODO: wrap to thread_local struct together with (almost) all globals
68static jmp_buf P_DispatcherStatusBuffer; //!< setjmp() state before dispatch
69static char *volatile P_StackBase = 0; //!< global start of stack area
70static char *volatile P_StackBase2 = 0; //!< used for checking only
71
72static P_Context_t *volatile P_Context = 0; //!< temporary global process state
73static volatile size_t P_StackSize = 0; //!< temporary global stack size
74
75////////////////////////////////////////////////////////////////////////////
76// Support for debugging:
77////////////////////////////////////////////////////////////////////////////
78
79#define EXTRA_DEBUG 0 // 0==off, 1==on
80
81#if EXTRA_DEBUG
82
83/// \def DEBUG_PROCESS
84/// Macro for detailed debugging of Process switching code
85#define DEBUG_PROCESS(n) DEBUG_PROCESS_f(n)
86
87/// \fn DEBUG_PROCESS_f
88/// We need? (FIXME) this non-inline function because optimization of volatile global
89/// variable access after longjmp -> setjmp transition in 32bit i686 mode of
90/// GCC 7 and newer versions
91// TODO: add string table? remove?
92[[gnu::noinline]] static void DEBUG_PROCESS_f(int n) {
93 switch(n) {
94 case 1:
95 DEBUG(DBG_PROCESS,("| PROCESS_INTERRUPT ***** begin *****"));
96 DEBUG(DBG_PROCESS,("| %d) - stack size = %p", n, P_StackSize));
97 break;
98 case 2:
99 break;
100 case 3:
101 break;
102 case 4:
103 DEBUG(DBG_PROCESS,("| %d) PROCESS_SAVE_STACK: before setjmp() - context=%p", n, P_Context));
104 break;
105 case 5:
106 DEBUG(DBG_PROCESS,("| %d) PROCESS_SAVE_STACK: after setjmp() - context=%p", n, P_Context));
107 break;
108 case 6:
109 DEBUG(DBG_PROCESS,("| %d) PROCESS_RESTORE: longjmp() back - context=%p", n, P_Context));
110 break;
111 case 7:
112 DEBUG(DBG_PROCESS,("| PROCESS_INTERRUPT ***** end *****"));
113 break;
114
115 case 0xB:
116 DEBUG(DBG_PROCESS,("| b) PROCESS Shift SP to %p (or more)", P_StackBase2));
117 break;
118 case 0xC:
119 DEBUG(DBG_PROCESS,("| c) PROCESS Before longjmp(%p,1)", P_Context->status));
120 break;
121
122 default:
123 DEBUG(DBG_PROCESS,("| %d) - context = %p", n, P_Context));
124 break;
125 }
126}
127#else
128#define DEBUG_PROCESS(n)
129#endif
130
131////////////////////////////////////////////////////////////////////////////
132// Specialized asymmetric stackfull coroutine implementation:
133////////////////////////////////////////////////////////////////////////////
134
135[[gnu::noinline]] static void PROCESS_INTERRUPT_f(); // special function
136
137/// interrupt process behavior execution, continue after return
138#define PROCESS_INTERRUPT() \
139{ /* This should be MACRO */ \
140 /* if(!isCurrent()) SIMLIB_error("Can't interrupt..."); */ \
141 this->_status = _INTERRUPTED; \
142 PROCESS_INTERRUPT_f(); \
143 this->_status = _RUNNING; \
144 this->_context = 0; \
145}
146
147/// does not save context
148#define PROCESS_EXIT() \
149 longjmp(P_DispatcherStatusBuffer, 2) // jump to dispatcher
150
151// FIXME: allocation/freeing memory is expensive, should be optimized
152
153/// \def ALLOC_CONTEXT
154/// allocate memory for process context, sz = size of stack area to save
155[[gnu::noinline]] static void ALLOC_CONTEXT(size_t sz) noexcept try
156{
157 P_Context = (P_Context_t *) new char[sizeof(P_Context_t) + sz];
158 P_Context->size = sz;
159} catch(std::bad_alloc&) {
160 SIMLIB_error("ALLOC_CONTEXT: no memory");
161}
162
163/// \fn FREE_CONTEXT
164/// deallocate saved process context
165[[gnu::noinline]] static void FREE_CONTEXT() noexcept {
166 delete[] (char *)(P_Context);
167 P_Context = 0;
168}
169
170////////////////////////////////////////////////////////////////////////////
171/// Process constructor
172/// sets state to PREPARED
174 Dprintf(("Process::Process(%d)", p));
175 _wait_until = false;
176 _context = 0; // pointer to process context
177 _status = _PREPARED; // prepared for running
178}
179
180////////////////////////////////////////////////////////////////////////////
181/// Process destructor
182/// Sets state to TERMINATED and
183/// removes process from queue/calendar/waituntil list.
184/// TODO: Warn if this==Current? (e.g. "delete this;" in Behavior())
186{
187 Dprintf(("Process::~Process()"));
188
189 //if(this==Current) SIMLIB_warning("Currently running process self-destructed");
190
191 // destroy context data
192 delete [] static_cast<char*>(_context);
193 _context = 0;
194
196
197 if (_wait_until) {
198 _WaitUntilRemove(); // remove from wait-until list
199 }
200
201 if (Where() != 0) { // if waiting in queue
202 Out(); // remove from queue, no warning
203 }
204
205 if (!Idle()) { // if process is scheduled
206 SQS::Get(this); // remove from calendar
207 }
208}
209
210#if 1
211////////////////////////////////////////////////////////////////////////////
212/// Name of the process
213/// Each process can be named, default is "Process#<number>"
214std::string Process::Name() const
215{
216 const std::string name = SimObject::Name();
217 if (!name.empty())
218 return name; // has explicit name
219 else
220 return SIMLIB_create_tmp_name("Process#%lu", _Ident);
221}
222#endif
223
224////////////////////////////////////////////////////////////////////////////
225/// Interrupt process behavior - this ensures WaitUntil tests
226/// WARNING: use with care - it can run higher (or equal) priority processes
227/// before continuing
228/// TODO: Works almost like Wait(0), used only with WaitUntil
230{
231 Dprintf(("Process#%lu.Interrupt()", _Ident));
232 if (!isCurrent())
233 return; // quasiparallel, TODO: Error?
234 // continue after other processes WaitUntil checks
235 // TODO: use >highest priority to eliminate problem
236 Entity::Activate(); // schedule now - can run higher priority
237 // processes before this one
239 // TODO: return to previous priority
240}
241
242////////////////////////////////////////////////////////////////////////////
243/// Activate process at time t
245{
246 Dprintf(("Process#%lu.Activate(%g)", _Ident, t));
247 Entity::Activate(t); // (re)scheduling
248 if (!isCurrent())
249 return;
251}
252
253////////////////////////////////////////////////////////////////////////////
254/// Wait for dtime
255/// The same as Activate(Time+dtime)
256void Process::Wait(double dtime)
257{
258 Dprintf(("Process#%lu.Wait(%g)", _Ident, dtime));
259 Entity::Activate(double (Time) + dtime); // (re)scheduling
260 if (!isCurrent())
261 return;
263}
264
265////////////////////////////////////////////////////////////////////////////
266/// Seize facility f with optional priority of service sp
267/// possibly waiting in input queue, if it is busy
269{
270 f.Seize(this, sp); // polymorphic interface
271}
272
273////////////////////////////////////////////////////////////////////////////
274/// Release facility f
275/// possibly activate first waiting entity in queue
277{
278 f.Release(this); // polymorphic interface
279}
280
281////////////////////////////////////////////////////////////////////////////
282/// Enter - use cap capacity of store s
283/// possibly waiting in input queue, if not enough free capacity
284void Process::Enter(Store & s, unsigned long cap)
285{
286 s.Enter(this, cap); // polymorphic interface
287}
288
289////////////////////////////////////////////////////////////////////////////
290/// Leave - return cap capacity of store s
291/// and enter first waiting entity from queue, which can use free capacity
292void Process::Leave(Store & s, unsigned long cap)
293{
294 s.Leave(cap); // polymorphic interface
295 //TODO: should be parametrized: use first-only, first-usable, all-usable
296}
297
298////////////////////////////////////////////////////////////////////////////
299/// Insert current process into queue
300/// The process can be at most in single queue. Moves if in other queue.
302{
303 if (Where() != 0) {
304 SIMLIB_warning("Process is already in (other) queue");
305 Out(); // if already in queue then remove
306 }
307 q.Insert(this); // polymorphic interface
308}
309
310////////////////////////////////////////////////////////////////////////////
311/// Process deactivation
312/// To continue the behavior it should be activated again
313/// Warning: memory leak if not activated/deleted explicitly (FIXME)
315{
316 Dprintf(("Process#%lu.Passivate()", id()));
318 if (!isCurrent())
319 return; // passivated by other process
321}
322
323////////////////////////////////////////////////////////////////////////////
324/// Terminate the process
325/// If called by current process, self-destruct.
326/// Remove from queue, unschedule from calendar.
327/// Automatically free the memory of the process.
329{
330 Dprintf(("Process#%lu.Terminate()", _Ident));
331
332 // remove from all queues TODO: write special method for this
333 if (Where() != 0) { // Entity linked in queue
334 Out(); // remove from queue, no warning
335 }
336 if (!Idle())
337 SQS::Get(this); // remove from calendar
338
339 // end of Process
340 if (isCurrent()) { // if currently running process
342 PROCESS_EXIT(); // jump back to dispatcher
343 }
344 else {
346 if (isAllocated())
347 delete this; // remove passive process
348 }
349}
350
351////////////////////////////////////////////////////////////////////////////
352#define CANARY1 (reinterpret_cast<long>(this)-1) // unaligned value is better
353
354
355/// This is theoretical max stack size for single SIMLIB Process at time of
356/// interruption (should never be too big, because of copying the stack contents)
357/// FIXME: should be checked at Process::Behavior interrupt for more precise error message
358#define MAX_PROCESS_STACK_SIZE 1000000UL
359
360[[noreturn,gnu::noinline]] static void restore_context2(volatile char *) noexcept;
361
362/// This elliminates the need for explicit stack pointer adjustment.
363/// The local array should not be optimized away.
364/// Parameters, return address and local variables will be overwritten.
365/// Never returns.
366[[noreturn,gnu::noinline]] static void restore_context(size_t data_size) noexcept
367{
368 volatile char skip[MAX_PROCESS_STACK_SIZE]; // should never be optimized
369 //skip[MAX_PROCESS_STACK_SIZE-1]='*';
370 if(data_size>MAX_PROCESS_STACK_SIZE)
371 SIMLIB_error("Process stack size limit exceeded");
372 DEBUG_PROCESS(0xB);
373 if(skip > P_StackBase2)
374 SIMLIB_error("Process stack error");
375 restore_context2(skip);
376}
377
378/// This function overwrites stack contents. It never returns, see longjmp.
379[[noreturn,gnu::noinline]] static void restore_context2(volatile char *) noexcept
380{
381 // c) Copy saved stack contents back to stack
382 memcpy((void *) (P_StackBase - P_StackSize), P_Context->stack, P_StackSize);
383 DEBUG_PROCESS(0xC);
384
385 // 4) Restore proces status (registers: SP,IP,...)
386 longjmp(P_Context->status, 1);
387 // ===========================================================
388 // never reach this point - longjmp never returns
389}
390
391/**
392 * \fn Process::_Run
393 * Process dispatch method
394 *
395 * The dispatcher starts/reactivates process Behavior() method
396 *
397 * IMPORTANT notes:
398 * - Function should be called from single place in simulation-control
399 * algorithm, because it is sensitive to stack-frame position
400 * (it saves/restores the stack contents).
401 *
402 * This function:
403 * 1) saves current context (position on stack and CPU registers)
404 * 2) calls Behavior() like any other function
405 * 3) interruption of Behavior() saves context+ and jumps back
406 * 4) to continue Behavior(), do 1) and move stack pointer away
407 * 5) copy saved stack content back to stack
408 * 6) do longjmp() to restore Behavior() execution
409 *
410 * @ingroup process
411 */
412void Process::_Run() noexcept // no exceptions
413{
414 // WARNING: all local variables should be volatile (see setjmp manual)
415 static const char * status_strings[] = {
416 "unknown", "PREPARED", "RUNNING", "INTERRUPTED", "TERMINATED"
417 };
418 Dprintf(("%016p===Process#%lu._Run() status=%s", this, _Ident, status_strings[_status]));
419
422
423 // Mark the stack base address
424 volatile long mylocal = CANARY1; // on stack variable
425 // Warning: DO NOT USE ANY OTHER LOCAL VARIABLES in this function!
426 P_StackBase = (char*)(&mylocal + 1);
427
428 //
429 // STACK layout (stack grows down):
430 //
431 // | ... |
432 // | |
433 // P_StackBase +-> +----------+
434 // | | mylocal |
435 // | +----------+
436 // | | |
437 // | | ... |
438 // _size | | Arguments, return addresses, locals, etc.
439 // | | ... |
440 // | | |
441 // | +----------+
442 // | | mylocal2 |
443 // +-> +----------+
444 // | | |
445# define STACK_RESERVED 0x080 // reserved area for "red zone" 128B ?
446 // | | |
447 // P_StackBase2 +-> +----------+
448 // ...
449 // locals and return address of restore_context2
450 // ...
451 // ...
452 // SIMLIB stack limit (defined by MAX_PROCESS_STACK_SIZE implementation defined constant)
453 // (limit holds only when Process::Behavior is interrupted and it's context saved)
454 // ...
455 // ...
456 // ...
457 // OS stack size limit (e.g. 8MiB on Linux: ulimit -s)
458
459
460#if EXTRA_DEBUG
461 DEBUG(DBG_PROCESS,("| PROCESS_STACK_BASE=%016p", P_StackBase));
462 // CHECK if the P_StackBase position is the same in each call
463 static char *P_StackBase0=0;
464 if(P_StackBase0==0)
465 P_StackBase0=P_StackBase;
466 else if (P_StackBase!=P_StackBase0)
467 SIMLIB_error("Internal error: P_StackBase not constant");
468#endif
469
470 // 2) mark current CPU context (part of context)
471 if (!setjmp(P_DispatcherStatusBuffer))
472 {
473 // setjmp returned after saving current status
475 if (_context == 0) { // process start
476 DEBUG(DBG_PROCESS, ("| --- Process::Behavior() START "));
477 Behavior(); // run behavior description
478 DEBUG(DBG_PROCESS, ("| --- Process::Behavior() END "));
480 if(mylocal != CANARY1)
481 SIMLIB_error("Process canary1 died after Behavior() return");
482 // Remove from any queue
483 if (Where() != 0) { // Entity linked in queue
484 Out(); // Remove from queue, no warning
485 }
486 if (!Idle())
487 SQS::Get(this); // Remove from calendar
488 //TODO: if(in any facility) error
489 } else { // process was interrupted and has saved context
490 DEBUG(DBG_PROCESS, ("| --- Process::Behavior() CONTINUE "));
491 mylocal = 0; // for checking only - previous value should be saved and later restored
492 // RESTORE_CONTEXT
493 // a) Save local variables to global
494 // This is important because of following stack manipulations.
495 P_Context = (P_Context_t*) this->_context;
496 P_StackSize = P_Context->size;
497
498 // b) Shift stack pointer under the currently restored stack area
499 // This is very important for next memcpy and longjmp
500 // (stack grows down), we reserve some more space
502
504 // never reach this point - longjmp (called from restore_context) never returns
505
506 }
507 }
508 else
509 { // setjmp: back from Behavior() - interrupted or terminated
510
511 if(mylocal != CANARY1)
512 SIMLIB_error("Process implementation canary1 died");
513
514 if(!isTerminated()) {
515 // Interrupted process
516 // Store content in global variables back to attributes
518 this->_context = P_Context;
519 DEBUG(DBG_PROCESS,("| --- Process::Behavior() INTERRUPT %p.context=%p, size=%d", \
520 this, P_Context, P_StackSize));
521 P_Context = 0; // cleaning
522 }
523 }
524
525 Dprintf(("%016p===Process#%lu._Run() RETURN status=%s", this, _Ident, status_strings[_status]));
526
527 //TODO: MOVE to simulation control loop
528 if (isTerminated() && isAllocated()) {
529 // terminated process on heap
530 DEBUG(DBG_PROCESS,("| Process %p ends and is deallocated now",this));
531 delete this; // destroy process
532 }
533 // return to simulation control
534}
535
536
537////////////////////////////////////////////////////////////////////////////
538#define CANARY2 0xDEADBEEFUL
539/**
540 * \fn PROCESS_INTERRUPT_f
541 * Special function called from Process::Behavior() directly or indirectly.
542 *
543 * This function:
544 * 1) computes stack data size,
545 * 2) allocates memory for stack data,
546 * 3) saves stack data to allocated memory,
547 * 4) saves CPU context using setjmp(), and
548 * 5) interrupts execution of current function using longjmp()
549 * to process dispatcher code,
550 * == (now runs dispatcher and other code)
551 * 6) continues execution after longjmp from dispatcher.
552 * 7) frees memory allocated at 2)
553 *
554 * Warning: This function is critical to process switching code and
555 * should not be inlined! It is never called directly by SIMLIB user.
556 *
557 * @ingroup process
558 */
559[[gnu::noinline]] static void PROCESS_INTERRUPT_f()
560{
561 // SAVE THE STACK STATE of the thread
562
563 // 1) compute stack context size (from P_StackBase to next variable)
564 volatile unsigned mylocal2 = CANARY2; // on-stack variable
565 // Warning: DO NOT USE ANY OTHER LOCAL VARIABLES in this function!
566 P_StackSize = (size_t) (P_StackBase - (char *) (&mylocal2));
567 DEBUG_PROCESS(1);
568
569 // 2) allocate memory for current context
571
572 // 3) save stack data (stack grows DOWN)
574
575 mylocal2 = 0; // previous value is saved (will be restored later)
576
577 // STACK CONTENTS SAVED
578
579 // 4) save CPU context (see man setjmp for details)
580 DEBUG_PROCESS(4);
581 if (!setjmp(P_Context->status)) {
582 ////////////////////////////////////////////////////////////////////
583 // 5) Interrupt the execution of Behavior()
584 DEBUG_PROCESS(5);
585 longjmp(P_DispatcherStatusBuffer, 1); // --> longjmp back to dispatcher
586 // longjmp never returns
587 }
588
589 // Check canary on stack after restore
590 if (mylocal2 != CANARY2)
591 SIMLIB_error("Process switching canary2 died.");
592
593 ////////////////////////////////////////////////////////////////////////
594 // 6) Continue execution after longjmp from dispatcher
595 // On stack data and CPU context were restored by dispatcher
596 DEBUG_PROCESS(6);
597
598 // 7) free memory of already restored context
599 FREE_CONTEXT();
600 DEBUG_PROCESS(7);
601 // return and continue Process::Behavior() execution
602}
603
604} // namespace
605
Test t(F)
abstract base class for active entities (Process, Event) instances of derived classes provide Behavio...
Definition: simlib.h:375
EntityPriority_t Priority_t
Definition: simlib.h:397
bool Idle()
entity activation is not scheduled in calendar
Definition: simlib.h:412
void Activate()
activate now
Definition: simlib.h:408
virtual void Out() override
remove entity from queue
Definition: entity.cc:90
virtual void Passivate()
deactivation
Definition: entity.cc:68
unsigned long _Ident
unique identification number of entity
Definition: simlib.h:378
(SOL-like) facility Facility with exclusive access and service priority
Definition: simlib.h:753
virtual void Seize(Entity *e, ServicePriority_t sp=DEFAULT_PRIORITY)
Definition: facility.cc:111
virtual void Release(Entity *e)
Definition: facility.cc:151
void Leave(Store &s, unsigned long ReqCap=1)
return some capacity
Definition: process.cc:292
virtual void Terminate() override
kill process
Definition: process.cc:328
virtual void Wait(double dtime)
wait for dtime interval
Definition: process.cc:256
void Release(Facility &f)
release facility
Definition: process.cc:276
void _WaitUntilRemove()
Definition: waitunti.cc:142
void Activate()
activate now
Definition: simlib.h:408
bool isCurrent() const
Definition: simlib.h:449
void Seize(Facility &f, ServicePriority_t sp=0)
seize facility
Definition: process.cc:268
bool isTerminated() const
Definition: simlib.h:451
virtual void Into(Queue &q)
insert process into queue
Definition: process.cc:301
virtual void Passivate() override
process deactivation (sleep)
Definition: process.cc:314
virtual void _Run() noexcept override
Process dispatch method.
Definition: process.cc:412
bool _wait_until
Definition: simlib.h:454
enum simlib3::Process::ProcessStatus_t _status
void Enter(Store &s, unsigned long ReqCap=1)
acquire some capacity
Definition: process.cc:284
void * _context
process context pointer
Definition: simlib.h:441
Process(Priority_t p=DEFAULT_PRIORITY)
Process constructor sets state to PREPARED.
Definition: process.cc:173
void Interrupt()
test of WaitUntil list, allow running others
Definition: process.cc:229
virtual void Behavior()=0
behavior description
virtual std::string Name() const override
name of object
Definition: process.cc:214
virtual ~Process()
Process destructor Sets state to TERMINATED and removes process from queue/calendar/waituntil list.
Definition: process.cc:185
priority queue
Definition: simlib.h:685
virtual void Insert(Entity *e)
Definition: queue.cc:50
bool isAllocated() const
Definition: simlib.h:318
virtual std::string Name() const
get object name
Definition: object.cc:134
(SOL-like) store store capacity can be changed dynamically
Definition: simlib.h:785
virtual void Leave(unsigned long rcap)
deallocate capacity
Definition: store.cc:152
virtual void Enter(Entity *e, unsigned long rcap)
allocate capacity
Definition: store.cc:128
@ ProcessNotInitialized
Definition: errors.h:31
Internal header file for SIMLIB/C++.
#define Dprintf(f)
Definition: internal.h:100
#define DBG_PROCESS
Definition: internal.h:126
#define DEBUG(c, f)
Definition: internal.h:105
void Get(Entity *e)
remove selected entity activation record from calendar
Definition: calendar.cc:1308
Implementation of class CalendarList interface is static - using global functions in SQS namespace.
Definition: algloop.cc:32
const double & Time
model time (is NOT the block)
Definition: run.cc:48
static char *volatile P_StackBase
global start of stack area
Definition: process.cc:69
void SIMLIB_error(const enum _ErrEnum N)
print error message and abort program
Definition: error.cc:38
static void restore_context2(volatile char *) noexcept
This function overwrites stack contents. It never returns, see longjmp.
Definition: process.cc:379
static jmp_buf P_DispatcherStatusBuffer
setjmp() state before dispatch
Definition: process.cc:68
static volatile size_t P_StackSize
temporary global stack size
Definition: process.cc:73
SIMLIB_IMPLEMENTATION
Definition: algloop.cc:34
std::string SIMLIB_create_tmp_name(const char *fmt,...)
printf-like function to create temporary name (the length of temporary names is limited) used only ...
Definition: name.cc:80
static P_Context_t *volatile P_Context
temporary global process state
Definition: process.cc:72
unsigned char ServicePriority_t
Service priority (see Facility::Seize)
Definition: simlib.h:365
static char *volatile P_StackBase2
used for checking only
Definition: process.cc:70
static void ALLOC_CONTEXT(size_t sz) noexcept
Definition: process.cc:155
static void FREE_CONTEXT() noexcept
deallocate saved process context
Definition: process.cc:165
void SIMLIB_warning(const enum _ErrEnum N)
print warning message and continue
Definition: error.cc:74
static void PROCESS_INTERRUPT_f()
Special function called from Process::Behavior() directly or indirectly.
Definition: process.cc:559
static void restore_context(size_t data_size) noexcept
This elliminates the need for explicit stack pointer adjustment.
Definition: process.cc:366
#define CANARY1
Definition: process.cc:352
#define DEBUG_PROCESS(n)
Definition: process.cc:128
#define PROCESS_EXIT()
does not save context
Definition: process.cc:148
#define CANARY2
Definition: process.cc:538
#define MAX_PROCESS_STACK_SIZE
This is theoretical max stack size for single SIMLIB Process at time of interruption (should never be...
Definition: process.cc:358
#define STACK_RESERVED
#define PROCESS_INTERRUPT()
interrupt process behavior execution, continue after return
Definition: process.cc:138
Main SIMLIB/C++ interface.
internal structure for storing of Process::Behavior() context
Definition: process.cc:58
size_t size
size of following array (allocated on heap)
Definition: process.cc:60
jmp_buf status
stored SP, IP, and other registers
Definition: process.cc:59
char stack[1]
saved stack contents
Definition: process.cc:61