From 734082db9128aefcab5676f034f4489117db5a27 Mon Sep 17 00:00:00 2001 From: "hyunghwan.chung" Date: Thu, 18 Feb 2016 17:49:56 +0000 Subject: [PATCH] added some code to implement semaphores --- stix/kernel/Process.st | 25 ++++- stix/lib/exec.c | 228 +++++++++++++++++++++++++++++++++-------- stix/lib/gc.c | 1 + stix/lib/ignite.c | 4 +- stix/lib/main.c | 3 + stix/lib/stix.h | 24 ++++- 6 files changed, 233 insertions(+), 52 deletions(-) diff --git a/stix/kernel/Process.st b/stix/kernel/Process.st index f4091a4..b68dcfc 100644 --- a/stix/kernel/Process.st +++ b/stix/kernel/Process.st @@ -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 + { + + self primitiveFailed. + } + + #method wait + { + + self primitiveFailed. + } +} + #class ProcessScheduler(Object) { #dcl tally head tail active. diff --git a/stix/lib/exec.c b/stix/lib/exec.c index d8963f3..bb57f37 100644 --- a/stix/lib/exec.c +++ b/stix/lib/exec.c @@ -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" }, diff --git a/stix/lib/gc.c b/stix/lib/gc.c index 547fea7..e0070d0 100644 --- a/stix/lib/gc.c +++ b/stix/lib/gc.c @@ -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); diff --git a/stix/lib/ignite.c b/stix/lib/ignite.c index cc4e9f9..30b927e 100644 --- a/stix/lib/ignite.c +++ b/stix/lib/ignite.c @@ -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' } }, diff --git a/stix/lib/main.c b/stix/lib/main.c index 73cd83d..fa08d01 100644 --- a/stix/lib/main.c +++ b/stix/lib/main.c @@ -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; } } diff --git a/stix/lib/stix.h b/stix/lib/stix.h index 3b2a30a..2563cee 100644 --- a/stix/lib/stix.h +++ b/stix/lib/stix.h @@ -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 );