diff --git a/kernel/arch/x86_64/apic.c b/kernel/arch/x86_64/apic.c index 725f8f4..2cce1c0 100644 --- a/kernel/arch/x86_64/apic.c +++ b/kernel/arch/x86_64/apic.c @@ -109,7 +109,7 @@ static void apic_timer_calibrate() } uint64_t avg = sum / (wait_ms * runs); - avg = (avg+100000) / 100000 * 100000; + avg = (avg + 100000) / 100000 * 100000; curcpu()->md.lapic_ticks_per_ms = avg; printk(LOG_DBG "apic timer: %ld ticks/ms\n", curcpu()->md.lapic_ticks_per_ms); @@ -130,6 +130,9 @@ static int apic_timer_handler(IrqObj *obj, Context *ctx, void *private) void apic_arm(uint64_t delta_us) { +#if 0 + printk("next timer in %ld ms\n", delta_us / 1000); +#endif if (delta_us == 0) { apic_write(APIC_REG_TIMER_INITIAL, 0); return; diff --git a/kernel/include/ivy-internal/sched.h b/kernel/include/ivy-internal/sched.h index 95c4ec8..12019c3 100644 --- a/kernel/include/ivy-internal/sched.h +++ b/kernel/include/ivy-internal/sched.h @@ -1,5 +1,6 @@ #pragma once +#include "ivy/status.h" #include #include "ivy/cpudata.h" #include "ivy/object.h" @@ -16,6 +17,7 @@ void sched_preempt(CpuData *data); void sched_yield(Thread *thread, CpuData *data); void sched_unwait_thread(Thread *thread, int status, int boost); -int sched_wait_thread(Thread *thread, int hastimeout); + +OsStatus sched_wait_thread(Thread *thread, int hastimeout); void sched_internal_ready(Thread *thread); diff --git a/kernel/include/ivy/sched.h b/kernel/include/ivy/sched.h index c98adc3..f656665 100644 --- a/kernel/include/ivy/sched.h +++ b/kernel/include/ivy/sched.h @@ -1,5 +1,6 @@ #pragma once +#include "ivy/status.h" #include #include "ivy/dpc.h" #include "ivy/timer.h" @@ -56,6 +57,9 @@ typedef struct thread { WaitBlock *wait_block_table; WaitBlock thread_wait_blocks[THREAD_WAIT_BLOCKS]; + Timer timeout; + WaitBlock timeout_wait_block; + TAILQ_ENTRY(thread) entry; } Thread; @@ -100,7 +104,9 @@ void sched_exit_self(); Thread *sched_satisfy_object(ObjHeader *object, int boost, int all, int status); -int sched_wait_multi(int waitmode, time_t timeout_ms, size_t objcount, - ObjHeader **objtable, WaitBlock *wbtable); +#define TIMEOUT_NONE 0 -int sched_wait(int waitmode, time_t timeout_ms, ObjHeader *obj); +OsStatus sched_wait_multi(int waitmode, time_t timeout_ms, size_t objcount, + ObjHeader **objtable, WaitBlock *wbtable); +OsStatus sched_wait(int waitmode, time_t timeout_ms, ObjHeader *obj); +OsStatus sleep(int waitmode, time_t ms); diff --git a/kernel/include/ivy/status.h b/kernel/include/ivy/status.h index ebf64a6..9dd9618 100644 --- a/kernel/include/ivy/status.h +++ b/kernel/include/ivy/status.h @@ -5,4 +5,7 @@ enum { IVY_NOSUPPORT, IVY_NOSPACE, IVY_INUSE, + IVY_WAIT_TIMEOUT, }; + +typedef int OsStatus; diff --git a/kernel/include/ivy/timer.h b/kernel/include/ivy/timer.h index 07b4982..d8828d1 100644 --- a/kernel/include/ivy/timer.h +++ b/kernel/include/ivy/timer.h @@ -41,3 +41,4 @@ void timer_init(Timer *timer, Dpc *dpc); void timer_reset(Timer *timer, Timespec deadline); void timer_reset_add(Timer *timer, time_t ms); void timer_install(Timer *timer, void *ctx); +void timer_uninstall(Timer *timer); diff --git a/kernel/src/init.c b/kernel/src/init.c index a76625c..535b1c3 100644 --- a/kernel/src/init.c +++ b/kernel/src/init.c @@ -6,6 +6,7 @@ #include "ivy/kmem.h" #include "ivy/log.h" #include "ivy/sched.h" +#include "ivy/status.h" #include "ivy/timer.h" #include "ivy/vm.h" #include "ivy/percpu.h" @@ -39,7 +40,7 @@ void print_loop(void *ctx) { int cnt = 0; for (;;) { - printk("%s", (const char *)ctx); + ///printk("%s", (const char *)ctx); if (++cnt == 5) sched_exit_self(); } @@ -62,10 +63,13 @@ void kmain_thread(void *) Timer timer; timer_init(&timer, NULL); - timer_reset_add(&timer, 500); + timer_reset_add(&timer, 2000); timer_install(&timer, NULL); - sched_wait(0, 0, &timer.hdr); + for (;;) { + sleep(0, 500); + } + timer_uninstall(&timer); printk(LOG_INFO "timer has fired, exit from wait\n"); diff --git a/kernel/src/irq/softint.c b/kernel/src/irq/softint.c index 3f4cffd..607bd02 100644 --- a/kernel/src/irq/softint.c +++ b/kernel/src/irq/softint.c @@ -3,6 +3,7 @@ #include "ivy/ipl.h" #include "ivy/softint.h" #include "ivy-internal/sched.h" +#include "ivy/log.h" #define PENDING(irql) ((1 << ((irql) - 1))) diff --git a/kernel/src/sched/sched.c b/kernel/src/sched/sched.c index 12df681..7bd2166 100644 --- a/kernel/src/sched/sched.c +++ b/kernel/src/sched/sched.c @@ -1,3 +1,4 @@ +#include "ivy/log.h" #include #include #include "ivy/dpc.h" @@ -161,9 +162,10 @@ void sched_ready(Thread *thread) void sched_yield(Thread *current, CpuData *data) { - Ipl ipl = spinlock_acquire(&data->sched.rq_lock); + assert(spinlock_held(¤t->lock)); + spinlock_acquire_elevated(&data->sched.rq_lock); Thread *next = next_thread(&data->sched, 0); - spinlock_release(&data->sched.rq_lock, ipl); + spinlock_release_elevated(&data->sched.rq_lock); if (next) { sched_switch(current, next); diff --git a/kernel/src/sched/thread.c b/kernel/src/sched/thread.c index 16e5526..d8c27ee 100644 --- a/kernel/src/sched/thread.c +++ b/kernel/src/sched/thread.c @@ -1,4 +1,6 @@ +#include "ivy/status.h" #include +#include "ivy/timer.h" #include "ivy/sched.h" #include "ivy-internal/sched.h" #include "ivy/vm.h" @@ -15,6 +17,12 @@ void thread_init(Thread *thread, ThreadEntryFn entry, int priority, thread->timeslice_ms = 15; SPINLOCK_INIT(&thread->lock); + timer_init(&thread->timeout, NULL); + + thread->timeout_wait_block.object = &thread->timeout.hdr; + thread->timeout_wait_block.wake_status = IVY_WAIT_TIMEOUT; + thread->timeout_wait_block.thread = thread; + context_init(thread, 0, entry, context); } diff --git a/kernel/src/sched/wait.c b/kernel/src/sched/wait.c index c7ff542..577bcae 100644 --- a/kernel/src/sched/wait.c +++ b/kernel/src/sched/wait.c @@ -36,6 +36,9 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include "ivy/log.h" +#include "ivy/status.h" +#include "ivy/timer.h" #include #include #include "ivy/cpudata.h" @@ -56,7 +59,7 @@ static void dequeue_waitblock(WaitBlock *waitblock) spinlock_release_elevated(&object->obj_lock); } -int sched_wait_thread(Thread *thread, int hastimeout) +OsStatus sched_wait_thread(Thread *thread, int hastimeout) { assert(spinlock_held(&thread->lock)); CpuData *data = curcpu(); @@ -75,7 +78,11 @@ int sched_wait_thread(Thread *thread, int hastimeout) wb++; } - assert(hastimeout == 0); + if (hastimeout) { + wb = &thread->timeout_wait_block; + dequeue_waitblock(wb); + timer_uninstall(&thread->timeout); + } // thread lock dropped, still IPL@DISPATCH @@ -104,9 +111,13 @@ void sched_unwait_thread(Thread *thread, int status, int boost) wb++; } + thread->timeout_wait_block.flags |= WB_UNWAITED; + // NOTE: could do quantum stuff - sched_internal_ready(thread); + if (thread->status == THREAD_WAITING) { + sched_internal_ready(thread); + } } Thread *sched_satisfy_object(ObjHeader *object, int boost, int all, int status) @@ -141,8 +152,8 @@ Thread *sched_satisfy_object(ObjHeader *object, int boost, int all, int status) return NULL; } -int sched_wait_multi(int waitmode, time_t timeout_ms, size_t objcount, - ObjHeader **objtable, WaitBlock *wbtable) +OsStatus sched_wait_multi(int waitmode, time_t timeout_ms, size_t objcount, + ObjHeader **objtable, WaitBlock *wbtable) { assert(objcount > 0 && objcount < 255); Thread *thread = curthread(); @@ -164,6 +175,9 @@ int sched_wait_multi(int waitmode, time_t timeout_ms, size_t objcount, assert(curipl() < IPL_DISPATCH); Ipl ipl = ripl(IPL_DISPATCH); + + thread->timeout_wait_block.flags = 0; + thread->wait_mode = waitmode; thread->wait_ipl = ipl; @@ -178,6 +192,7 @@ int sched_wait_multi(int waitmode, time_t timeout_ms, size_t objcount, size_t i; int status; ObjHeader *obj; + Timer *timer; for (i = 0; i < objcount; i++) { obj = objtable[i]; @@ -209,13 +224,26 @@ int sched_wait_multi(int waitmode, time_t timeout_ms, size_t objcount, spinlock_release_elevated(&obj->obj_lock); } - assert(!timeout_ms); + if (timeout_ms) { + WaitBlock *wb = &thread->timeout_wait_block; + timer = &thread->timeout; + + TAILQ_INSERT_TAIL(&timer->hdr.waiter_list, wb, entry); + timer->hdr.waiter_count = 1; + + timer_reset_add(timer, timeout_ms); + timer_install(timer, NULL); + } spinlock_acquire_elevated(&thread->lock); if (thread->wait_attempt == THREAD_WAIT_ABORTED) { spinlock_release_elevated(&thread->lock); if (timeout_ms) { + WaitBlock *wb = &thread->timeout_wait_block; + timer = &thread->timeout; + timer_uninstall(timer); + TAILQ_REMOVE(&timer->hdr.waiter_list, wb, entry); } status = thread->wait_status; @@ -231,7 +259,7 @@ int sched_wait_multi(int waitmode, time_t timeout_ms, size_t objcount, return status; } -int sched_wait(int waitmode, time_t timeout_ms, ObjHeader *obj) +OsStatus sched_wait(int waitmode, time_t timeout_ms, ObjHeader *obj) { Thread *thread = curthread(); WaitBlock singlewaitblock; @@ -245,6 +273,7 @@ int sched_wait(int waitmode, time_t timeout_ms, ObjHeader *obj) assert(curipl() < IPL_DISPATCH); Ipl ipl = ripl(IPL_DISPATCH); + thread->timeout_wait_block.flags = 0; thread->wait_mode = waitmode; thread->wait_ipl = ipl; thread->wait_block_table = NULL; @@ -272,11 +301,28 @@ int sched_wait(int waitmode, time_t timeout_ms, ObjHeader *obj) obj->waiter_count += 1; spinlock_release_elevated(&obj->obj_lock); + if (timeout_ms) { + WaitBlock *wb = &thread->timeout_wait_block; + Timer *timer = &thread->timeout; + TAILQ_INSERT_TAIL(&timer->hdr.waiter_list, wb, entry); + timer->hdr.waiter_count = 1; + + timer_reset_add(timer, timeout_ms); + timer_install(timer, NULL); + } + spinlock_acquire_elevated(&thread->lock); if (thread->wait_attempt == THREAD_WAIT_ABORTED) { spinlock_release_elevated(&thread->lock); + if (timeout_ms) { + WaitBlock *wb = &thread->timeout_wait_block; + Timer *timer = &thread->timeout; + timer_uninstall(timer); + TAILQ_REMOVE(&timer->hdr.waiter_list, wb, entry); + } + status = thread->wait_status; dequeue_waitblock(&singlewaitblock); thread->wait_attempt = THREAD_WAIT_NONE; @@ -294,3 +340,54 @@ int sched_wait(int waitmode, time_t timeout_ms, ObjHeader *obj) return status; } + +OsStatus sleep(int waitmode, time_t ms) +{ + Thread *thread = curthread(); + +retry: + + assert(curipl() < IPL_DISPATCH); + Ipl ipl = ripl(IPL_DISPATCH); + thread->timeout_wait_block.flags = 0; + thread->wait_mode = waitmode; + thread->wait_ipl = ipl; + thread->wait_block_table = NULL; + thread->wait_count = 0; + spinlock_acquire_elevated(&thread->lock); + // NOTE: check for all kinds of stuff here + thread->wait_attempt = THREAD_WAIT_TRY; + spinlock_release_elevated(&thread->lock); + + OsStatus status = 0; + + WaitBlock *wb = &thread->timeout_wait_block; + Timer *timer = &thread->timeout; + TAILQ_INSERT_TAIL(&timer->hdr.waiter_list, wb, entry); + timer->hdr.waiter_count = 1; + timer_reset_add(timer, ms); + timer_install(timer, NULL); + + spinlock_acquire_elevated(&thread->lock); + + if (thread->wait_attempt == THREAD_WAIT_ABORTED) { + spinlock_release_elevated(&thread->lock); + + timer_uninstall(timer); + TAILQ_REMOVE(&timer->hdr.waiter_list, wb, entry); + + status = thread->wait_status; + thread->wait_attempt = THREAD_WAIT_NONE; + + xipl(ipl); + return status; + } + + thread->wait_attempt = THREAD_WAIT_COMMITTED; + + status = sched_wait_thread(thread, 1); + + xipl(ipl); + + return status; +} diff --git a/kernel/src/time/timer.c b/kernel/src/time/timer.c index 2dbacf1..f6aa657 100644 --- a/kernel/src/time/timer.c +++ b/kernel/src/time/timer.c @@ -2,14 +2,13 @@ #include "ivy/cpudata.h" #include "ivy/dpc.h" #include "ivy/heap.h" -#include "ivy/log.h" #include "ivy/object.h" #include "ivy/time.h" #include "ivy/timespec.h" static int timer_cmp(Timer *a, Timer *b) { - return timespec_cmp(a->deadline, b->deadline) == 1; + return timespec_cmp(a->deadline, b->deadline) < 0; } HEAP_IMPL(timerlist, timer, entry, timer_cmp); @@ -36,7 +35,7 @@ void timer_init(Timer *timer, Dpc *dpc) HEAP_ENTRY_INIT(timer, entry); } -void timer_uninstall(Timer *timer, int flags) +void timer_uninstall(Timer *timer) { TimerEngine *engine = timer->engine; if (engine) { @@ -60,7 +59,7 @@ void timer_reset(Timer *timer, Timespec deadline) Ipl ipl = spinlock_acquire(&timer->hdr.obj_lock); if (timer->state == TIMER_QUEUED) { spinlock_release(&timer->hdr.obj_lock, ipl); - timer_uninstall(timer, 0); + timer_uninstall(timer); ipl = spinlock_acquire(&timer->hdr.obj_lock); } timer->deadline = deadline;