added some code to implement semaphores

This commit is contained in:
hyunghwan.chung 2016-02-18 17:49:56 +00:00
parent fc7a44ba7d
commit 734082db91
6 changed files with 233 additions and 52 deletions

View File

@ -1,3 +1,5 @@
#class Delay(Object)
{
## TODO: support milliseconds or nanoseconds
@ -26,7 +28,7 @@
#class(#pointer) Process(Object)
{
#dcl initial active state prev next sp.
#dcl initial_context runnable_context state prev next sp sem_next.
#method new
{
@ -71,6 +73,27 @@
}
}
#class Semaphore(Object)
{
#dcl count waiting_head waiting_tail.
#method initialize
{
}
#method signal
{
<primitive: #_semaphore_signal>
self primitiveFailed.
}
#method wait
{
<primitive: #_semaphore_wait>
self primitiveFailed.
}
}
#class ProcessScheduler(Object)
{
#dcl tally head tail active.

View File

@ -26,10 +26,11 @@
#include "stix-prv.h"
#define PROCESS_STATE_RUNNING 3
#define PROCESS_STATE_BLOCKED 2
#define PROCESS_STATE_SUSPENDED 1
#define PROCESS_STATE_CREATED 0
#define PROCESS_STATE_WAITING 2
#define PROCESS_STATE_RUNNABLE 1
#define PROCESS_STATE_SUSPENDED 0
#define PROCESS_STATE_TERMINATED -1
#if defined(USE_DYNCALL)
@ -138,6 +139,8 @@
# define DBGOUT_EXEC_3(fmt,a1,a2,a3)
#endif
static stix_oop_process_t make_process (stix_t* stix, stix_oop_context_t c)
{
stix_oop_process_t proc;
@ -147,7 +150,7 @@ static stix_oop_process_t make_process (stix_t* stix, stix_oop_context_t c)
stix_poptmp (stix);
if (!proc) return STIX_NULL;
proc->state = STIX_SMOOI_TO_OOP(PROCESS_STATE_CREATED);
proc->state = STIX_SMOOI_TO_OOP(PROCESS_STATE_SUSPENDED);
proc->initial_context = c;
proc->sp = STIX_SMOOI_TO_OOP(-1);
@ -161,8 +164,8 @@ static void switch_process (stix_t* stix, stix_oop_process_t proc)
{
if (stix->processor->active != proc)
{
STIX_ASSERT (proc->state == STIX_SMOOI_TO_OOP(PROCESS_STATE_SUSPENDED) ||
proc->state == STIX_SMOOI_TO_OOP(PROCESS_STATE_BLOCKED));
STIX_ASSERT (proc->state == STIX_SMOOI_TO_OOP(PROCESS_STATE_RUNNABLE) ||
proc->state == STIX_SMOOI_TO_OOP(PROCESS_STATE_WAITING));
#if defined(STIX_DEBUG_PROCESSOR)
printf ("ACTUAL PROCESS SWITCHING BF...%d %p\n", (int)stix->ip, stix->active_context);
@ -177,8 +180,8 @@ printf ("ACTUAL PROCESS SWITCHING BF...%d %p\n", (int)stix->ip, stix->active_con
/* store the current active context to the current process.
* it is the suspended context of the process to be suspended */
STIX_ASSERT ((stix_oop_t)stix->processor->active != stix->_nil);
stix->processor->active->suspended_context = stix->active_context;
stix->processor->active->state = STIX_SMOOI_TO_OOP(PROCESS_STATE_SUSPENDED);
stix->processor->active->runnable_context = stix->active_context;
stix->processor->active->state = STIX_SMOOI_TO_OOP(PROCESS_STATE_RUNNABLE);
/* activate the given process */
proc->state = STIX_SMOOI_TO_OOP(PROCESS_STATE_RUNNING);
@ -191,7 +194,7 @@ printf ("ACTUAL PROCESS SWITCHING BF...%d %p\n", (int)stix->ip, stix->active_con
#endif
/* activate the suspended context of the new process */
SWITCH_ACTIVE_CONTEXT (stix, proc->suspended_context);
SWITCH_ACTIVE_CONTEXT (stix, proc->runnable_context);
#if defined(STIX_DEBUG_PROCESSOR)
printf ("ACTUAL PROCESS SWITCHING AF...%d %p\n", (int)stix->ip, stix->active_context);
@ -218,7 +221,7 @@ printf ("SWITCHING TO THE NEXT PROCESS\n");
}
}
static STIX_INLINE int register_new_process (stix_t* stix, stix_oop_process_t proc)
static STIX_INLINE int insert_into_processor (stix_t* stix, stix_oop_process_t proc)
{
/* the process is not scheduled at all.
* link it to the processor's process list. */
@ -227,11 +230,11 @@ static STIX_INLINE int register_new_process (stix_t* stix, stix_oop_process_t pr
STIX_ASSERT ((stix_oop_t)proc->prev == stix->_nil);
STIX_ASSERT ((stix_oop_t)proc->next == stix->_nil);
STIX_ASSERT (proc->state == STIX_SMOOI_TO_OOP(PROCESS_STATE_CREATED));
STIX_ASSERT ((stix_oop_t)proc->suspended_context == stix->_nil);
STIX_ASSERT (proc->state == STIX_SMOOI_TO_OOP(PROCESS_STATE_SUSPENDED));
STIX_ASSERT ((stix_oop_t)proc->runnable_context == stix->_nil);
tally = STIX_OOP_TO_SMOOI(stix->processor->tally);
if (tally <= 0)
if (tally == 0)
{
/* the process schedule has no process.
* it is the first process */
@ -239,36 +242,59 @@ static STIX_INLINE int register_new_process (stix_t* stix, stix_oop_process_t pr
stix->processor->head = proc;
stix->processor->tail = proc;
stix->processor->tally = STIX_SMOOI_TO_OOP(1);
#if defined(STIX_DEBUG_PROCESSOR)
printf ("ADDED FIRST NEW PROCESS - %d\n", (int)1);
#endif
}
else if (tally >= STIX_SMOOI_MAX)
{
#if defined(STIX_DEBUG_PROCESSOR)
printf ("TOO MANY PROCESS\n");
#endif
stix->errnum = STIX_EPFULL;
return -1;
}
else
else if (tally < STIX_SMOOI_MAX)
{
proc->next = stix->processor->head;
stix->processor->head->prev = proc;
stix->processor->head = proc;
stix->processor->tally = STIX_SMOOI_TO_OOP(tally + 1);
}
else if (tally < 0)
{
stix->errnum = STIX_EINTERN;
return -1;
}
else
{
#if defined(STIX_DEBUG_PROCESSOR)
printf ("ADDED NEW PROCESS - %d\n", (int)tally + 1);
printf ("TOO MANY PROCESS\n");
#endif
stix->errnum = STIX_EPFULL;
return -1;
}
proc->state = STIX_SMOOI_TO_OOP(PROCESS_STATE_SUSPENDED);
proc->suspended_context = proc->initial_context;
tally++;
stix->processor->tally = STIX_SMOOI_TO_OOP(tally);
#if defined(STIX_DEBUG_PROCESSOR)
printf ("INSERTED PROCESS %d TO PROCESSOR\n", (int)tally);
#endif
return 0;
}
static STIX_INLINE void delete_from_processor (stix_t* stix, stix_oop_process_t proc)
{
stix_ooi_t tally;
STIX_ASSERT (proc->state == STIX_SMOOI_TO_OOP(PROCESS_STATE_RUNNING) ||
proc->state == STIX_SMOOI_TO_OOP(PROCESS_STATE_RUNNABLE));
tally = STIX_OOP_TO_SMOOI(stix->processor->tally);
STIX_ASSERT (tally > 0);
if ((stix_oop_t)proc->prev != stix->_nil) proc->prev->next = proc->next;
else stix->processor->head = proc->next;
if ((stix_oop_t)proc->next != stix->_nil) proc->next->prev = proc->prev;
else stix->processor->tail = proc->prev;
proc->prev = (stix_oop_process_t)stix->_nil;
proc->next = (stix_oop_process_t)stix->_nil;
tally--;
stix->processor->tally = STIX_SMOOI_TO_OOP(tally);
}
static void terminate_process (stix_t* stix, stix_oop_process_t proc)
{
/* TODO:
@ -276,21 +302,20 @@ static void terminate_process (stix_t* stix, stix_oop_process_t proc)
* can the only process be killed? if so, terminate VM??? */
if (proc->state == STIX_SMOOI_TO_OOP(PROCESS_STATE_RUNNING) ||
proc->state == STIX_SMOOI_TO_OOP(PROCESS_STATE_SUSPENDED) ||
proc->state == STIX_SMOOI_TO_OOP(PROCESS_STATE_BLOCKED))
proc->state == STIX_SMOOI_TO_OOP(PROCESS_STATE_RUNNABLE) ||
proc->state == STIX_SMOOI_TO_OOP(PROCESS_STATE_WAITING)) /* TODO: is it safe to terminate a waiting process? */
{
stix_ooi_t tally;
tally = STIX_OOP_TO_SMOOI(stix->processor->tally);
/* the state must be alive */
if ((stix_oop_t)proc->prev != stix->_nil) proc->prev->next = proc->next;
else stix->processor->head = proc->next;
if ((stix_oop_t)proc->next != stix->_nil) proc->next->prev = proc->prev;
else stix->processor->tail = proc->prev;
proc->state = STIX_SMOOI_TO_OOP(PROCESS_STATE_TERMINATED);
if (proc == stix->processor->active) proc->suspended_context = stix->active_context; /* not needed but just in case */
if (proc == stix->processor->active) proc->runnable_context = stix->active_context; /* not needed but just in case */
proc->sp = STIX_SMOOI_TO_OOP(-1); /* invalidate the process stack */
tally--;
@ -316,7 +341,7 @@ static void terminate_process (stix_t* stix, stix_oop_process_t proc)
}
}
static int schedule_process (stix_t* stix, stix_oop_process_t proc)
static int resume_process (stix_t* stix, stix_oop_process_t proc)
{
if (proc->state == STIX_SMOOI_TO_OOP(PROCESS_STATE_TERMINATED))
{
@ -324,11 +349,15 @@ static int schedule_process (stix_t* stix, stix_oop_process_t proc)
stix->errnum = STIX_EINVAL; /* TODO: more specialized error code? */
return -1;
}
else if (proc->state == STIX_SMOOI_TO_OOP(PROCESS_STATE_CREATED))
else if (proc->state == STIX_SMOOI_TO_OOP(PROCESS_STATE_SUSPENDED))
{
/* the process is not scheduled at all. it must not exist in the
* process list of the process scheduler. */
if (register_new_process (stix, proc) <= -1) return -1;
if (insert_into_processor (stix, proc) <= -1) return -1;
/* SUSPENED -> RUNNING */
proc->runnable_context = proc->initial_context;
proc->state = STIX_SMOOI_TO_OOP(PROCESS_STATE_RUNNABLE);
switch_process (stix, proc);
}
else if (stix->processor->active != proc)
@ -339,6 +368,85 @@ static int schedule_process (stix_t* stix, stix_oop_process_t proc)
return 0;
}
static void suspend_process (stix_t* stix, stix_oop_process_t proc)
{
if (proc->state == STIX_SMOOI_TO_OOP(PROCESS_STATE_RUNNING) ||
proc->state == STIX_SMOOI_TO_OOP(PROCESS_STATE_RUNNABLE))
{
/* RUNNING/RUNNABLE -> SUSPENDED */
delete_from_processor (stix, proc);
proc->state = STIX_SMOOI_TO_OOP(PROCESS_STATE_SUSPENDED);
}
#if 0
else
{
stix->errnum = STIX_EINVAL; /* TODO: more specialized error code? */
return -1;
}
#endif
}
static void schedule_process (stix_t* stix, stix_oop_process_t proc)
{
/* RUNNABLE -> RUNNING */
}
static void signal_semaphore (stix_t* stix, stix_oop_semaphore_t sem)
{
stix_oop_process_t proc;
stix_ooi_t count;
if ((stix_oop_t)sem->waiting_head == stix->_nil)
{
count = STIX_OOP_TO_SMOOI(sem->count);
count++;
sem->count = STIX_SMOOI_TO_OOP(count);
}
else
{
proc = sem->waiting_head;
sem->waiting_head = proc->sem_next;
if ((stix_oop_t)sem->waiting_head == stix->_nil)
sem->waiting_tail = (stix_oop_process_t)stix->_nil;
proc->sem_next = (stix_oop_process_t)stix->_nil;
resume_process (stix, proc);
}
}
static void await_semaphore (stix_t* stix, stix_oop_semaphore_t sem)
{
stix_oop_process_t proc;
stix_ooi_t count;
count = STIX_OOP_TO_SMOOI(sem->count);
if (count > 0)
{
count--;
sem->count = STIX_SMOOI_TO_OOP(count);
}
else
{
proc = stix->processor->active;
STIX_ASSERT ((stix_oop_t)proc->sem_next == stix->_nil);
if ((stix_oop_t)sem->waiting_tail == stix->_nil)
{
STIX_ASSERT ((stix_oop_t)sem->waiting_head == stix->_nil);
sem->waiting_head = proc;
}
else
{
STIX_ASSERT ((stix_oop_t)sem->waiting_head != stix->_nil);
sem->waiting_tail->sem_next = proc;
}
sem->waiting_tail = proc;
suspend_process (stix, proc);
STIX_ASSERT (stix->processor->active != proc);
}
}
static stix_oop_process_t start_initial_process (stix_t* stix, stix_oop_context_t c)
{
stix_oop_process_t proc;
@ -350,14 +458,14 @@ static stix_oop_process_t start_initial_process (stix_t* stix, stix_oop_context_
proc = make_process (stix, c);
if (!proc) return STIX_NULL;
if (register_new_process (stix, proc) <= -1) return STIX_NULL;
/*TODO: set the state to RUNNING */
if (insert_into_processor (stix, proc) <= -1) return STIX_NULL;
proc->runnable_context = proc->initial_context;
proc->state = STIX_SMOOI_TO_OOP(PROCESS_STATE_RUNNING); /* skip RUNNABLE and go to RUNNING */
stix->processor->active = proc;
/* do somthing that schedule_process() would do with less overhead */
STIX_ASSERT ((stix_oop_t)proc->suspended_context != stix->_nil);
STIX_ASSERT (proc->suspended_context == proc->initial_context);
/* do somthing that resume_process() would do with less overhead */
STIX_ASSERT ((stix_oop_t)proc->runnable_context != stix->_nil);
STIX_ASSERT (proc->runnable_context == proc->initial_context);
SWITCH_ACTIVE_CONTEXT (stix, proc->initial_context);
return proc;
@ -642,7 +750,7 @@ TODO: overcome this problem
STIX_ASSERT (stix->processor->active == proc);
STIX_ASSERT (stix->processor->active->initial_context == ctx);
STIX_ASSERT (stix->processor->active->suspended_context == ctx);
STIX_ASSERT (stix->processor->active->runnable_context == ctx);
STIX_ASSERT (stix->active_context == ctx);
/* emulate the message sending */
@ -1196,6 +1304,34 @@ static int prim_process_terminate (stix_t* stix, stix_ooi_t nargs)
return 1;
}
static int prim_semaphore_signal (stix_t* stix, stix_ooi_t nargs)
{
stix_oop_t rcv;
STIX_ASSERT (nargs == 0);
rcv = ACTIVE_STACK_GET(stix, stix->sp);
if (STIX_CLASSOF(stix,rcv) != stix->_semaphore) return 0;
signal_semaphore (stix, (stix_oop_semaphore_t)rcv);
/* keep the receiver in the stack top */
return 1;
}
static int prim_semaphore_wait (stix_t* stix, stix_ooi_t nargs)
{
stix_oop_t rcv;
STIX_ASSERT (nargs == 0);
rcv = ACTIVE_STACK_GET(stix, stix->sp);
if (STIX_CLASSOF(stix,rcv) != stix->_semaphore) return 0;
await_semaphore (stix, (stix_oop_semaphore_t)rcv);
/* keep the receiver in the stack top */
return 1;
}
static int prim_processor_schedule (stix_t* stix, stix_ooi_t nargs)
{
stix_oop_t rcv, arg;
@ -1210,7 +1346,7 @@ static int prim_processor_schedule (stix_t* stix, stix_ooi_t nargs)
return 0;
}
if (schedule_process (stix, (stix_oop_process_t)arg) <= -1)
if (resume_process (stix, (stix_oop_process_t)arg) <= -1)
{
printf ("PROCESS SCHEDULE FAILURE...\n");
/* TODO: Can this be a soft failure? */
@ -1909,6 +2045,8 @@ static prim_t primitives[] =
{ -1, prim_block_new_process, "_block_new_process" },
{ 0, prim_process_terminate, "_process_terminate" },
{ 0, prim_semaphore_signal, "_semaphore_signal" },
{ 0, prim_semaphore_wait, "_semaphore_wait" },
{ 1, prim_processor_schedule, "_processor_schedule" },
{ 1, prim_processor_remove, "_processor_remove" },

View File

@ -324,6 +324,7 @@ printf ("STARTING GC curheap base %p ptr %p newheap base %p ptr %p\n",
stix->_association = stix_moveoop (stix, stix->_association);
stix->_method_context = stix_moveoop (stix, stix->_method_context);
stix->_block_context = stix_moveoop (stix, stix->_block_context);
stix->_semaphore = stix_moveoop (stix, stix->_semaphore);
stix->_process = stix_moveoop (stix, stix->_process);
stix->_process_scheduler = stix_moveoop (stix, stix->_process_scheduler);
stix->_true_class = stix_moveoop (stix, stix->_true_class);

View File

@ -137,6 +137,7 @@ static int ignite_1 (stix_t* stix)
stix->_method_context = alloc_kernel_class (stix, 0, STIX_CLASS_SPEC_MAKE(STIX_CONTEXT_NAMED_INSTVARS, 1, STIX_OBJ_TYPE_OOP));
stix->_block_context = alloc_kernel_class (stix, 0, STIX_CLASS_SPEC_MAKE(STIX_CONTEXT_NAMED_INSTVARS, 1, STIX_OBJ_TYPE_OOP));
stix->_process = alloc_kernel_class (stix, 0, STIX_CLASS_SPEC_MAKE(STIX_PROCESS_NAMED_INSTVARS, 1, STIX_OBJ_TYPE_OOP));
stix->_semaphore = alloc_kernel_class (stix, 0, STIX_CLASS_SPEC_MAKE(STIX_SEMAPHORE_NAMED_INSTVARS, 0, STIX_OBJ_TYPE_OOP));
stix->_process_scheduler = alloc_kernel_class (stix, 0, STIX_CLASS_SPEC_MAKE(STIX_PROCESS_SCHEDULER_NAMED_INSTVARS, 0, STIX_OBJ_TYPE_OOP));
stix->_true_class = alloc_kernel_class (stix, 0, STIX_CLASS_SPEC_MAKE(0, 0, STIX_OBJ_TYPE_OOP));
stix->_false_class = alloc_kernel_class (stix, 0, STIX_CLASS_SPEC_MAKE(0, 0, STIX_OBJ_TYPE_OOP));
@ -158,7 +159,7 @@ static int ignite_1 (stix_t* stix)
!stix->_method_dictionary || !stix->_method || !stix->_association ||
!stix->_method_context || !stix->_block_context ||
!stix->_process || !stix->_process_scheduler ||
!stix->_process || !stix->_semaphore || !stix->_process_scheduler ||
!stix->_true_class || !stix->_false_class ||
!stix->_character || !stix->_small_integer ||
@ -249,6 +250,7 @@ static int ignite_3 (stix_t* stix)
{ 13, { 'M','e','t','h','o','d','C','o','n','t','e','x','t' } },
{ 12, { 'B','l','o','c','k','C','o','n','t','e','x','t' } },
{ 7, { 'P','r','o','c','e','s','s' } },
{ 9, { 'S','e','m','a','p','h','o','r','e' } },
{ 16, { 'P','r','o','c','e','s','s','S','c','h','e','d','u','l','e','r' } },
{ 4, { 'T','r','u','e' } },
{ 5, { 'F','a','l','s','e' } },

View File

@ -586,6 +586,9 @@ printf ("%p\n", a);
printf ("ERROR: cannot compile code - %d\n", stix_geterrnum(stix));
}
stix_close (stix);
#if defined(USE_LTDL)
lt_dlexit ();
#endif
return -1;
}
}

View File

@ -539,23 +539,36 @@ struct stix_context_t
stix_oop_t slot[1]; /* stack */
};
#define STIX_PROCESS_NAMED_INSTVARS 6
#define STIX_PROCESS_NAMED_INSTVARS 7
typedef struct stix_process_t stix_process_t;
typedef struct stix_process_t* stix_oop_process_t;
struct stix_process_t
{
STIX_OBJ_HEADER;
stix_oop_context_t initial_context;
stix_oop_context_t suspended_context;
stix_oop_context_t runnable_context;
stix_oop_t state; /* SmallInteger */
stix_oop_process_t prev;
stix_oop_process_t next;
stix_oop_t sp; /* stack pointer. SmallInteger */
stix_oop_process_t sem_next;
/* == variable indexed part == */
stix_oop_t slot[1]; /* process stack */
};
#define STIX_SEMAPHORE_NAMED_INSTVARS 3
typedef struct stix_semaphore_t stix_semaphore_t;
typedef struct stix_semaphore_t* stix_oop_semaphore_t;
struct stix_semaphore_t
{
STIX_OBJ_HEADER;
stix_oop_t count; /* SmallInteger */
stix_oop_process_t waiting_head; /* nil or Process */
stix_oop_process_t waiting_tail; /* nil or Process */
};
#define STIX_PROCESS_SCHEDULER_NAMED_INSTVARS 4
typedef struct stix_process_scheduler_t stix_process_scheduler_t;
typedef struct stix_process_scheduler_t* stix_oop_process_scheduler_t;
@ -739,6 +752,7 @@ struct stix_t
stix_oop_t _method_context; /* MethodContext */
stix_oop_t _block_context; /* BlockContext */
stix_oop_t _process; /* Process */
stix_oop_t _semaphore; /* Semaphore */
stix_oop_t _process_scheduler; /* ProcessScheduler */
stix_oop_t _true_class; /* True */
stix_oop_t _false_class; /* False */
@ -785,8 +799,8 @@ extern "C" {
STIX_EXPORT stix_t* stix_open (
stix_mmgr_t* mmgr,
stix_oow_t xtnsize,
stix_oow_t heapsize,
stix_oow_t xtnsize,
stix_oow_t heapsize,
const stix_vmprim_t* vmprim,
stix_errnum_t* errnum
);
@ -798,7 +812,7 @@ STIX_EXPORT void stix_close (
STIX_EXPORT int stix_init (
stix_t* vm,
stix_mmgr_t* mmgr,
stix_oow_t heapsize,
stix_oow_t heapsize,
const stix_vmprim_t* vmprim
);