45 #if !(defined(__MSDOS__)||defined(__linux__)|| \ 46 defined(__WIN32__)||defined(__FreeBSD__)) 47 # error "module process.cc is not implemented on this operating system" 51 #if !(defined(__i386__)||defined(__x86_64__)) 52 # error "module process.cc is not ported to this processor architecture" 71 #if defined(__BCPLUSPLUS__) || defined(__TURBOC__) // Borland compilers 74 # if defined(__WIN32__) // 32 bit WINDOWS 75 # define GET_STACK_PTR(v) { v = (char*)_ESP; } 76 # define SET_STACK_PTR(v) { _ESP = v; } 77 # else // 16 bit MSDOS (obsolete, not supported) 78 # if defined(__LARGE__) || defined(__COMPACT__) || defined(__HUGE__) 79 # define GET_STACK_PTR(v) { v = (char far *)MK_FP(_SS,_SP); } 81 # define GET_STACK_PTR(v) { v = (char*)_SP; } 83 # define SET_STACK_PTR(v) { _SP = v; } 86 #elif defined(__GNUC__) // GNU C++ compiler 88 # if defined(__i386__) // 32bit: i386+ expected... 90 # define GET_STACK_PTR(v) { asm("movl %%esp,%0":"=r" (v)); } 91 # define SET_STACK_PTR(v) { asm("movl %0,%%eax": : "m" (v)); \ 92 asm("movl %eax,%esp"); \ 95 # elif defined(__x86_64__) // 64bit: Athlon64, ... 97 # define GET_STACK_PTR(gvar) { asm("movq %%rsp,%0": "=r" (gvar)); } 98 # define SET_STACK_PTR(gvar) { asm("movq %0,%%rsp": : "m" (gvar)); } 100 # else // Other CPU ... 101 # error "process.cc: Unsupported CPU architecture" 104 #else // Other compilers not supported 106 # error "process.cc: Unsupported compiler" 139 #define EXTRA_DEBUG 0 // 0==off, 1==on 145 #define THREAD_DEBUG(n) THREAD_DEBUG_f(n) 151 # define P_DEBUG(c,f) \ 152 do{ if( SIMLIB_debug_flag & (c) ) { \ 153 _Print("EXTRA_PROCESS_DEBUG:"); \ 154 _Print f; _Print("\n"); \ 162 static void THREAD_DEBUG_f(
int n) __attribute__ ((noinline));
163 static void THREAD_DEBUG_f(
int n) {
166 P_DEBUG(
DBG_THREAD,(
"| THREAD_INTERRUPT ***** begin *****"));
167 P_DEBUG(
DBG_THREAD,(
"| %d) - stack size = %p", n, P_StackSize));
174 P_DEBUG(
DBG_THREAD,(
"| %d) THREAD_SAVE_STACK: before setjmp() - context=%p", n, P_Context));
177 P_DEBUG(
DBG_THREAD,(
"| %d) THREAD_SAVE_STACK: after setjmp() - context=%p", n, P_Context));
180 P_DEBUG(
DBG_THREAD,(
"| %d) THREAD_RESTORE: longjmp() back - context=%p", n, P_Context));
183 P_DEBUG(
DBG_THREAD,(
"| THREAD_INTERRUPT ***** end *****"));
187 P_DEBUG(
DBG_THREAD,(
"| b) THREAD Shift SP to %p ", P_StackBase2));
190 P_DEBUG(
DBG_THREAD,(
"| c) THREAD Before longjmp(%p,1)", P_Context->
status));
194 P_DEBUG(
DBG_THREAD,(
"| %d) - context = %p", n, P_Context));
199 #define THREAD_DEBUG(n) 209 #define THREAD_INTERRUPT() \ 212 this->_status = _INTERRUPTED; \ 213 THREAD_INTERRUPT_f(); \ 214 this->_status = _RUNNING; \ 215 this->_context = 0; \ 219 #define THREAD_EXIT() \ 220 longjmp(P_DispatcherStatusBuffer, 2) // jump to dispatcher 226 #define ALLOC_CONTEXT(sz) \ 227 P_Context = (P_Context_t *) new char[sizeof(P_Context_t) + sz]; \ 228 P_Context->size = sz; 232 #if BUG_IN_32BIT_CODE_USING_GCC_7_plus 234 #define FREE_CONTEXT() \ 235 delete[] (char *) P_Context; \ 242 delete[] (
char *) P_Context;
251 Dprintf((
"Process::Process(%d)", p));
264 Dprintf((
"Process::~Process()"));
395 Dprintf((
"Process#%lu.Passivate()",
id()));
430 #define CANARY1 (reinterpret_cast<long>(this)+1) // unaligned value is better 458 static const char * status_strings[] = {
459 "unknown",
"PREPARED",
"RUNNING",
"INTERRUPTED",
"TERMINATED" 467 volatile long mylocal =
CANARY1;
469 P_StackBase = (
char*)(&mylocal + 1);
488 # define STACK_RESERVED 0x080 // reserved for "red zone" 128B ? 496 static char *P_StackBase0=0;
499 else if (P_StackBase!=P_StackBase0)
500 SIMLIB_error(
"Internal error: P_StackBase not constant");
504 if (!setjmp(P_DispatcherStatusBuffer))
514 SIMLIB_error(
"Process canary1 died after Behavior() return");
529 P_StackSize = P_Context->
size;
538 SET_STACK_PTR(P_StackBase2);
542 memcpy((
void *) (P_StackBase - P_StackSize), P_Context->
stack, P_StackSize);
546 longjmp(P_Context->
status, 1);
563 DEBUG(
DBG_THREAD,(
"| --- Process::Behavior() INTERRUPT %p.context=%p, size=%d", \
564 this, P_Context, P_StackSize));
569 Dprintf((
"%016p===Process#%lu._Run() RETURN status=%s",
this,
_Ident, status_strings[_status]));
582 #define CANARY2 0xDEADBEEFUL 608 volatile unsigned mylocal2 =
CANARY2;
609 P_StackSize = (size_t) (P_StackBase - (
char *) (&mylocal2));
616 memcpy(P_Context->
stack, (P_StackBase - P_StackSize), P_StackSize);
624 if (!setjmp(P_Context->
status)) {
628 longjmp(P_DispatcherStatusBuffer, 1);
void Leave(Store &s, unsigned long ReqCap=1)
return some capacity
(SOL-like) facility Facility with exclusive access and service priority
void Interrupt()
test of WaitUntil list, allow running others
virtual void Out() override
remove entity from queue
virtual void Into(Queue &q)
insert process into queue
virtual ~Process()
Process destructor Sets status to TERMINATED and removes process from queue/calendar/waituntil list...
void SIMLIB_error(const enum _ErrEnum N)
print error message and abort program
unsigned char ServicePriority_t
Service priority (see Facility::Seize)
static volatile size_t P_StackSize
temporary global stack size
(SOL-like) store store capacity can be changed dynamically
void * _context
process context pointer
#define THREAD_INTERRUPT()
interrupt process behavior execution, continue after return
void Release(Facility &f)
release facility
jmp_buf status
stored SP, IP, and other registers
virtual void Passivate()
deactivation
void Get(Entity *e)
remove selected entity activation record from calendar
virtual void Seize(Entity *e, ServicePriority_t sp=DEFAULT_PRIORITY)
bool isTerminated() const
size_t size
size of following array (allocated on heap)
Implementation of class CalendarList interface is static - using global functions in SQS namespace...
virtual void Behavior()=0
behavior description
unsigned long _Ident
unique identification number of entity
void SIMLIB_warning(const enum _ErrEnum N)
print warning message and continue
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 ...
abstract base class for active entities (Process, Event) instances of derived classes provide Behavio...
static char *volatile P_StackBase
global start of stack area
const double & Time
model time (is NOT the block)
#define ALLOC_CONTEXT(sz)
allocate memory for process context, sz = size of stack area to save
static char *volatile P_StackBase2
for checking start of stack
virtual void Release(Entity *e)
void Seize(Facility &f, ServicePriority_t sp=0)
seize facility
#define THREAD_EXIT()
does not save context
enum simlib3::Process::ProcessStatus_t _status
virtual void Terminate() override
kill process
virtual void Wait(double dtime)
wait for dtime interval
virtual void Enter(Entity *e, unsigned long rcap)
allocate capacity
virtual void Leave(unsigned long rcap)
deallocate capacity
Internal header file for SIMLIB/C++.
internal structure for storing of process context
virtual void Passivate() override
process deactivation (sleep)
Main SIMLIB/C++ interface.
virtual std::string Name() const
get object name
static jmp_buf P_DispatcherStatusBuffer
setjmp() state before dispatch
static P_Context_t *volatile P_Context
temporary global process state
bool Idle()
entity activation is not scheduled in calendar
List * Where()
where is linked
void Enter(Store &s, unsigned long ReqCap=1)
acquire some capacity
static void FREE_CONTEXT() __attribute__((noinline))
non-inline function for deallocating saved process context
void Activate()
activate now
EntityPriority_t Priority_t
virtual std::string Name() const override
name of object
Process(Priority_t p=DEFAULT_PRIORITY)
Process constructor sets state to PREPARED.
static void THREAD_INTERRUPT_f() __attribute__((noinline))
Special function called from Process::Behavior() directly or indirectly.
char stack[1]
stack contents saved
virtual void Insert(Entity *e)
virtual void _Run() noexcept override
Process dispatch method.