diff --git a/stix/kernel/Process.st b/stix/kernel/Process.st index de9dc32..a51e95f 100644 --- a/stix/kernel/Process.st +++ b/stix/kernel/Process.st @@ -53,6 +53,15 @@ { ^sp. } + + #method sleep: seconds + { + | s | + s := Semaphore new. + Processor signal: s after: seconds. + ## Processor activeProcess dump. + s wait. + } } #class Semaphore(Object) @@ -67,6 +76,8 @@ self.fireTimeNsec := 0. } + ## ================================================================== + #method signal { @@ -79,6 +90,20 @@ self primitiveFailed. } + #method waitWithTimeout: seconds + { + + self primitiveFailed + } + + #method waitWithTimeout: seconds and: nanoSeconds + { + + self primitiveFailed + } + + ## ================================================================== + #method heapIndex { ^heapIndex @@ -302,12 +327,6 @@ ^self.active. } - #method sleep: anInteger - { - - self primitiveFailed. - } - #method resume: aProcess { @@ -329,12 +348,6 @@ " } - #method remove: aProcess - { - "" -"TODO: " - } - " #method yield { @@ -354,4 +367,17 @@ self primitiveFailed. } + + #method unsignal: aSemaphore + { + + self primitiveFailed. + } + + "#method signal: aSemaphore onInput: file + { + }" + "#method signal: aSemaphore onOutput: file + { + }" } diff --git a/stix/lib/exec.c b/stix/lib/exec.c index 7486d0a..a2efc8b 100644 --- a/stix/lib/exec.c +++ b/stix/lib/exec.c @@ -157,6 +157,21 @@ #endif +static STIX_INLINE void vm_gettime (stix_ntime_t* now) +{ + struct timespec ts; + clock_gettime (CLOCK_MONOTONIC, &ts); + STIX_INITNTIME(now, ts.tv_sec, ts.tv_nsec); +} + +static STIX_INLINE void vm_sleep (const stix_ntime_t* dur) +{ + struct timespec ts; + ts.tv_sec = dur->sec; + ts.tv_nsec = dur->nsec; + nanosleep (&ts, STIX_NULL); +} + static stix_oop_process_t make_process (stix_t* stix, stix_oop_context_t c) { stix_oop_process_t proc; @@ -415,12 +430,11 @@ static void terminate_process (stix_t* stix, stix_oop_process_t proc) static void resume_process (stix_t* stix, stix_oop_process_t proc) { -printf ("TO RESUME PROCESS = %p %d\n", proc, (int)STIX_OOP_TO_SMOOI(proc->state)); if (proc->state == STIX_SMOOI_TO_OOP(PROC_STATE_SUSPENDED)) { /* SUSPENED ---> RUNNING */ -printf ("TO RESUME PROCESS = %p %d SUSPENED ----> RUNNING\n", proc, (int)STIX_OOP_TO_SMOOI(proc->state)); +//printf ("TO RESUME PROCESS = %p %d SUSPENED ----> RUNNING\n", proc, (int)STIX_OOP_TO_SMOOI(proc->state)); STIX_ASSERT ((stix_oop_t)proc->prev == stix->_nil); STIX_ASSERT ((stix_oop_t)proc->next == stix->_nil); @@ -429,7 +443,7 @@ printf ("TO RESUME PROCESS = %p %d SUSPENED ----> RUNNING\n", proc, (int)STIX_OO /*proc->current_context = proc->initial_context;*/ proc->state = STIX_SMOOI_TO_OOP(PROC_STATE_RUNNABLE); - /*switch_to_process (stix, proc);*/ + /* don't switch to this process. just set the state to RUNNING */ } #if 0 else if (proc->state == STIX_SMOOI_TO_OOP(PROC_STATE_RUNNABLE)) @@ -455,11 +469,11 @@ static void suspend_process (stix_t* stix, stix_oop_process_t proc) nrp = find_next_runnable_process (stix); -printf ("TO SUSPEND...%p %d\n", proc, (int)STIX_OOP_TO_SMOOI(proc->state)); +//printf ("TO SUSPEND...%p %d\n", proc, (int)STIX_OOP_TO_SMOOI(proc->state)); if (nrp == proc) { /* no runnable process after suspension */ -printf ("NO RUNNABLE PROCESS AFTER SUPSENDISION\n"); +//printf ("NO RUNNABLE PROCESS AFTER SUPSENDISION\n"); sleep_active_process (stix, PROC_STATE_RUNNABLE); unchain_from_processor (stix, proc, PROC_STATE_SUSPENDED); @@ -470,7 +484,7 @@ printf ("NO RUNNABLE PROCESS AFTER SUPSENDISION\n"); } else { -printf ("SWITCHING TO XXXXXXXXXXXXXXXXXXXXx\n"); +//printf ("SWITCHING TO XXXXXXXXXXXXXXXXXXXXx\n"); /* keep the unchained process at the runnable state for * the immediate call to switch_to_process() below */ unchain_from_processor (stix, proc, PROC_STATE_RUNNABLE); @@ -535,25 +549,34 @@ static int async_signal_semaphore (stix_t* stix, stix_oop_semaphore_t sem) return 0; } -static void signal_semaphore (stix_t* stix, stix_oop_semaphore_t sem) +static stix_oop_process_t 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) { -printf ("signal semaphore...1111\n"); +//printf ("signal semaphore...1111\n"); /* no process is waiting on this semaphore */ count = STIX_OOP_TO_SMOOI(sem->count); count++; sem->count = STIX_SMOOI_TO_OOP(count); + + /* no process has been resumed */ + return stix->_nil; } else { -printf ("signal semaphore...2222\n"); proc = sem->waiting_head; + + /* [NOTE] no GC must occur as 'proc' isn't protected with stix_pushtmp(). */ + unchain_from_semaphore (stix, proc); resume_process (stix, proc); /* TODO: error check */ +//printf ("signal semaphore...2222 DONE -> resumed process -> proc state %d\n", (int)STIX_OOP_TO_SMOOI(proc->state)); + + /* return the resumed process */ + return proc; } } @@ -568,20 +591,23 @@ static void await_semaphore (stix_t* stix, stix_oop_semaphore_t sem) /* it's already signalled */ count--; sem->count = STIX_SMOOI_TO_OOP(count); -printf (">>>>>>>>>>>>>> AWAIT SEMAPHORE - NO SUSPENDING ...................\n"); +//printf (">>>>>>>>>>>>>> AWAIT SEMAPHORE - NO SUSPENDING ...................\n"); } else { /* not signaled. need to wait */ proc = stix->processor->active; -printf (">>>>>>>>>>>>>> AWAIT SEMAPHORE - SUEPENDING ACTIVE PROCESS...............\n"); +//printf (">>>>>>>>>>>>>> AWAIT SEMAPHORE - SUEPENDING ACTIVE PROCESS..........state=>[%d].....PROC %p\n", (int)STIX_OOP_TO_SMOOI(proc->state), proc); /* suspend the active process */ suspend_process (stix, proc); - /* link the suspened process to the semaphore's process list */ + /* link the suspended process to the semaphore's process list */ chain_into_semaphore (stix, proc, sem); + STIX_ASSERT (sem->waiting_tail == proc); + +//printf (">>>>>>>>>>>>>> AWAIT SEMAPHORE - SUEPENDING ACTIVE PROCESS....XX......state=>[%d]..PROC %p\n", (int)STIX_OOP_TO_SMOOI(proc->state), proc); STIX_ASSERT (stix->processor->active != proc); } } @@ -709,6 +735,7 @@ static void delete_from_sem_heap (stix_t* stix, stix_ooi_t index) lastsem->heap_index = STIX_SMOOI_TO_OOP(index); stix->sem_heap[index] = lastsem; + if (SEM_HEAP_EARLIER_THAN(stix, lastsem, sem)) sift_up_sem_heap (stix, index); else @@ -1657,23 +1684,11 @@ static int prim_processor_schedule (stix_t* stix, stix_ooi_t nargs) return 1; } -static int prim_processor_remove (stix_t* stix, stix_ooi_t nargs) -{ -/* TODO: */ - return 0; -} - -static int prim_processor_sleep (stix_t* stix, stix_ooi_t nargs) -{ -/* TODO: */ - return 0; -} - static int prim_processor_add_timed_semaphore (stix_t* stix, stix_ooi_t nargs) { stix_oop_t rcv, sec, nsec; stix_oop_semaphore_t sem; - struct timespec ts, ft; + stix_ntime_t now, ft; STIX_ASSERT (nargs >= 2 || nargs <= 3); @@ -1710,30 +1725,17 @@ static int prim_processor_add_timed_semaphore (stix_t* stix, stix_ooi_t nargs) * * this code assumes that the monotonic clock returns a small value * that can fit into a small integer, even after some addtions... */ - if (clock_gettime (CLOCK_MONOTONIC, &ts) == -1) + vm_gettime (&now); + STIX_ADDNTIMESNS (&ft, &now, STIX_OOP_TO_SMOOI(sec), STIX_OOP_TO_SMOOI(nsec)); + if (ft.sec < 0 || ft.sec > STIX_SMOOI_MAX) { - /* TODO: soft error handling */ -printf ("clock_gettime() failure....\n"); - return 0; - } - - ft.tv_nsec = ts.tv_nsec + STIX_OOP_TO_SMOOI(nsec); - ft.tv_sec = ts.tv_sec + STIX_OOP_TO_SMOOI(sec); - while (ft.tv_nsec >= 1000000000) - { - ft.tv_sec++; - ft.tv_nsec -= 1000000000; - } - - if (ft.tv_sec < 0 || ft.tv_sec > STIX_SMOOI_MAX) - { - /* soft error - cannot represent the expiry time in + /* soft error - cannot represent the e:xpiry time in * a small integer. */ return 0; } - sem->heap_ftime_sec = STIX_SMOOI_TO_OOP(ft.tv_sec); - sem->heap_ftime_nsec = STIX_SMOOI_TO_OOP(ft.tv_nsec); + sem->heap_ftime_sec = STIX_SMOOI_TO_OOP(ft.sec); + sem->heap_ftime_nsec = STIX_SMOOI_TO_OOP(ft.nsec); if (add_to_sem_heap (stix, sem) <= -1) return -1; @@ -1741,15 +1743,20 @@ printf ("clock_gettime() failure....\n"); return 1; } -static int prim_processor_del_time_semaphore (stix_t* stix, stix_ooi_t nargs) +static int prim_processor_remove_semaphore (stix_t* stix, stix_ooi_t nargs) { + /* remove a semaphore from processor's signal scheduling */ + stix_oop_t rcv; stix_oop_semaphore_t sem; STIX_ASSERT (nargs == 1); - sem = (stix_oop_semaphore_t)ACTIVE_STACK_GET(stix, stix->sp - 1); - rcv = ACTIVE_STACK_GET(stix, stix->sp); + sem = (stix_oop_semaphore_t)ACTIVE_STACK_GET(stix, stix->sp); + rcv = ACTIVE_STACK_GET(stix, stix->sp - 1); + +/* TODO: remove a semaphore from IO handler if it's registered... + * remove a semaphore from XXXXXXXXXXXXXX */ if (rcv != (stix_oop_t)stix->processor) return 0; if (STIX_CLASSOF(stix,sem) != stix->_semaphore) return 0; @@ -1757,10 +1764,12 @@ static int prim_processor_del_time_semaphore (stix_t* stix, stix_ooi_t nargs) if (STIX_OOP_IS_SMOOI(sem->heap_index) && sem->heap_index != STIX_SMOOI_TO_OOP(-1)) { - delete_from_sem_heap (stix, STIX_OOP_TO_SMOOI(sem)); + /* the semaphore is in the timed semaphore heap */ + delete_from_sem_heap (stix, STIX_OOP_TO_SMOOI(sem->heap_index)); STIX_ASSERT(sem->heap_index == STIX_SMOOI_TO_OOP(-1)); } + ACTIVE_STACK_POPS (stix, nargs); return 1; } @@ -2448,10 +2457,9 @@ static prim_t primitives[] = { 0, 0, prim_semaphore_signal, "_semaphore_signal" }, { 0, 0, prim_semaphore_wait, "_semaphore_wait" }, - { 1, 1, prim_processor_schedule, "_processor_schedule" }, - { 1, 1, prim_processor_remove, "_processor_remove" }, - { 1, 1, prim_processor_sleep, "_processor_sleep" }, - { 2, 3, prim_processor_add_timed_semaphore, "_processor_add_timed_semaphore" }, + { 1, 1, prim_processor_schedule, "_processor_schedule" }, + { 2, 3, prim_processor_add_timed_semaphore, "_processor_add_timed_semaphore" }, + { 1, 1, prim_processor_remove_semaphore, "_processor_remove_semaphore" }, { 1, 1, prim_integer_add, "_integer_add" }, { 1, 1, prim_integer_sub, "_integer_sub" }, @@ -2852,42 +2860,45 @@ int stix_execute (stix_t* stix) while (1) { -#if 0 - if (stix->processor->active == stix->nil_process) - { - /* no more process in the system */ - STIX_ASSERT (stix->processor->tally = STIX_SMOOI_TO_OOP(0)); -printf ("NO MORE RUNNABLE PROCESS...\n"); - } -#endif - if (stix->sem_heap_count > 0) { - struct timespec now, ft; - - clock_gettime (CLOCK_MONOTONIC, &now); + stix_ntime_t ft, now; + vm_gettime (&now); do { STIX_ASSERT (STIX_OOP_IS_SMOOI(stix->sem_heap[0]->heap_ftime_sec)); STIX_ASSERT (STIX_OOP_IS_SMOOI(stix->sem_heap[0]->heap_ftime_nsec)); - ft.tv_sec = STIX_OOP_TO_SMOOI(stix->sem_heap[0]->heap_ftime_sec); - ft.tv_nsec = STIX_OOP_TO_SMOOI(stix->sem_heap[0]->heap_ftime_nsec); + STIX_INITNTIME (&ft, + STIX_OOP_TO_SMOOI(stix->sem_heap[0]->heap_ftime_sec), + STIX_OOP_TO_SMOOI(stix->sem_heap[0]->heap_ftime_nsec) + ); - if (ft.tv_sec < now.tv_sec || (ft.tv_sec == now.tv_sec && ft.tv_nsec <= now.tv_nsec)) + if (STIX_CMPNTIME(&ft, (stix_ntime_t*)&now) <= 0) { stix_oop_process_t proc; - proc = stix->sem_heap[0]->waiting_head; + /* waited long enough. signal the semaphore */ - signal_semaphore (stix, stix->sem_heap[0]); + proc = signal_semaphore (stix, stix->sem_heap[0]); + /* [NOTE] no stix_pushtmp() on proc. no GC must occur + * in the following line until it's used for + * wake_new_process() below. */ delete_from_sem_heap (stix, 0); - if (stix->processor->active == stix->nil_process) + /* if no process is waiting on the semaphore, + * signal_semaphore() returns stix->_nil. */ + + if (stix->processor->active == stix->nil_process && (stix_oop_t)proc != stix->_nil) { -STIX_ASSERT (proc->state == STIX_SMOOI_TO_OOP(PROC_STATE_RUNNABLE)); -STIX_ASSERT (proc == stix->processor->runnable_head); + /* this is the only runnable process. + * switch the process to the running state. + * it uses wake_new_process() instead of + * switch_to_process() as there is no running + * process at this moment */ + STIX_ASSERT (proc->state == STIX_SMOOI_TO_OOP(PROC_STATE_RUNNABLE)); + STIX_ASSERT (proc == stix->processor->runnable_head); wake_new_process (stix, proc); stix->proc_switched = 1; @@ -2895,16 +2906,9 @@ STIX_ASSERT (proc == stix->processor->runnable_head); } else if (stix->processor->active == stix->nil_process) { -/* THIS PART IS JUST EXPERIMENTAL... PROPER WAITING WITH IO MULTIPLEXER IS NEEDED ... */ - ft.tv_sec -= now.tv_sec; - ft.tv_nsec -= now.tv_nsec; - while (ft.tv_nsec < 0) - { - ft.tv_sec--; - ft.tv_nsec += 1000000000; - } - nanosleep (&ft, STIX_NULL); - clock_gettime (CLOCK_MONOTONIC, &now); + STIX_SUBNTIME (&ft, &ft, (stix_ntime_t*)&now); + vm_sleep (&ft); /* TODO: change this to i/o multiplexer??? */ + vm_gettime (&now); } else { @@ -2921,13 +2925,6 @@ printf ("REALLY NO MORE RUNNABLE PROCESS...\n"); break; } -/* - else if (stix->processor->active == stix->idle_process) - { -IDLEING WAITING FOR PROCESS WAKE-UP... - } -*/ - while (stix->sem_list_count > 0) { /* handle async signals */ @@ -3704,7 +3701,6 @@ printf ("TERMINATE A PROCESS RETURNING FROM BLOCK\n"); #endif terminate_process (stix, stix->processor->active); #if defined(STIX_DEBUG_EXEC_002) - printf ("TERMINATED A PROCESS RETURNING FROM BLOCK %lld new active_context %p\n", (long long int)stix->ip, stix->active_context); #endif } diff --git a/stix/lib/stix-cmn.h b/stix/lib/stix-cmn.h index 2b2728e..1932ab6 100644 --- a/stix/lib/stix-cmn.h +++ b/stix/lib/stix-cmn.h @@ -316,6 +316,83 @@ typedef stix_ucs_t stix_oocs_t; #define STIX_OOCH_IS_UCH + +/* ========================================================================= + * TIME-RELATED TYPES + * =========================================================================*/ +#define STIX_MSECS_PER_SEC (1000) +#define STIX_MSECS_PER_MIN (STIX_MSECS_PER_SEC * STIX_SECS_PER_MIN) +#define STIX_MSECS_PER_HOUR (STIX_MSECS_PER_SEC * STIX_SECS_PER_HOUR) +#define STIX_MSECS_PER_DAY (STIX_MSECS_PER_SEC * STIX_SECS_PER_DAY) + +#define STIX_USECS_PER_MSEC (1000) +#define STIX_NSECS_PER_USEC (1000) +#define STIX_NSECS_PER_MSEC (STIX_NSECS_PER_USEC * STIX_USECS_PER_MSEC) +#define STIX_USECS_PER_SEC (STIX_USECS_PER_MSEC * STIX_MSECS_PER_SEC) +#define STIX_NSECS_PER_SEC (STIX_NSECS_PER_USEC * STIX_USECS_PER_MSEC * STIX_MSECS_PER_SEC) + +#define STIX_SECNSEC_TO_MSEC(sec,nsec) \ + (((qse_long_t)(sec) * STIX_MSECS_PER_SEC) + ((qse_long_t)(nsec) / STIX_NSECS_PER_MSEC)) + +#define STIX_SECNSEC_TO_USEC(sec,nsec) \ + (((qse_long_t)(sec) * STIX_USECS_PER_SEC) + ((qse_long_t)(nsec) / STIX_NSECS_PER_USEC)) + +#define STIX_SEC_TO_MSEC(sec) ((sec) * STIX_MSECS_PER_SEC) +#define STIX_MSEC_TO_SEC(sec) ((sec) / STIX_MSECS_PER_SEC) + +#define STIX_USEC_TO_NSEC(usec) ((usec) * STIX_NSECS_PER_USEC) +#define STIX_NSEC_TO_USEC(nsec) ((nsec) / STIX_NSECS_PER_USEC) + +#define STIX_MSEC_TO_NSEC(msec) ((msec) * STIX_NSECS_PER_MSEC) +#define STIX_NSEC_TO_MSEC(nsec) ((nsec) / STIX_NSECS_PER_MSEC) + +#define STIX_SEC_TO_NSEC(sec) ((sec) * STIX_NSECS_PER_SEC) +#define STIX_NSEC_TO_SEC(nsec) ((nsec) / STIX_NSECS_PER_SEC) + +#define STIX_SEC_TO_USEC(sec) ((sec) * STIX_USECS_PER_SEC) +#define STIX_USEC_TO_SEC(usec) ((usec) / STIX_USECS_PER_SEC) + +typedef struct stix_ntime_t stix_ntime_t; +struct stix_ntime_t +{ + stix_intptr_t sec; + stix_int32_t nsec; /* nanoseconds */ +}; + +#define STIX_INITNTIME(c,s,ns) (((c)->sec = (s)), ((c)->nsec = (ns))) +#define STIX_CLEARNTIME(c) STIX_INITNTIME(c, 0, 0) + +#define STIX_ADDNTIME(c,a,b) \ + do { \ + (c)->sec = (a)->sec + (b)->sec; \ + (c)->nsec = (a)->nsec + (b)->nsec; \ + while ((c)->nsec >= STIX_NSECS_PER_SEC) { (c)->sec++; (c)->nsec -= STIX_NSECS_PER_SEC; } \ + } while(0) + +#define STIX_ADDNTIMESNS(c,a,s,ns) \ + do { \ + (c)->sec = (a)->sec + (s); \ + (c)->nsec = (a)->nsec + (ns); \ + while ((c)->nsec >= STIX_NSECS_PER_SEC) { (c)->sec++; (c)->nsec -= STIX_NSECS_PER_SEC; } \ + } while(0) + +#define STIX_SUBNTIME(c,a,b) \ + do { \ + (c)->sec = (a)->sec - (b)->sec; \ + (c)->nsec = (a)->nsec - (b)->nsec; \ + while ((c)->nsec < 0) { (c)->sec--; (c)->nsec += STIX_NSECS_PER_SEC; } \ + } while(0) + +#define STIX_SUBNTIMESNS(c,a,s,ns) \ + do { \ + (c)->sec = (a)->sec - s; \ + (c)->nsec = (a)->nsec - ns; \ + while ((c)->nsec < 0) { (c)->sec--; (c)->nsec += STIX_NSECS_PER_SEC; } \ + } while(0) + + +#define STIX_CMPNTIME(a,b) (((a)->sec == (b)->sec)? ((a)->nsec - (b)->nsec): ((a)->sec - (b)->sec)) + /* ========================================================================= * PRIMITIVE MACROS * ========================================================================= */