diff --git a/src/arch/x86_64/syscall.asm b/src/arch/x86_64/syscall.asm index 7b276bf3..13970fbf 100644 --- a/src/arch/x86_64/syscall.asm +++ b/src/arch/x86_64/syscall.asm @@ -40,7 +40,8 @@ extern syscall_bind extern syscall_listen extern syscall_connect extern syscall_accept -func_count equ 39 +extern syscall_nanosleep +func_count equ 40 func_table: @@ -83,6 +84,7 @@ func_table: dq syscall_listen dq syscall_connect dq syscall_accept + dq syscall_nanosleep section .text global asm_syscall_entry diff --git a/src/sys/syscalls/sleep.c b/src/sys/syscalls/sleep.c new file mode 100644 index 00000000..95fcaee8 --- /dev/null +++ b/src/sys/syscalls/sleep.c @@ -0,0 +1,63 @@ +#include +#include +#include +#include +#include + +// XXX proper implementation and not a hacky stub + +syscallret syscall_nanosleep(struct timespec *time, struct timespec *remaining){ + + syscallret retv; + retv.ret = -1; + + if(time > USER_SPACE_END || remaining > USER_SPACE_END){ + retv.errno = EFAULT; + return retv; + } + + struct timespec t = *time; + + if(t.tv_nsec > 999999999 || t.tv_nsec < 0){ + retv.errno = EINVAL; + return retv; + } + + struct timespec start = arch_timekeeper_gettime(); + struct timespec end = start; + end.tv_sec += t.tv_sec; + end.tv_nsec += t.tv_nsec; + + if(end.tv_nsec / 999999999){ + ++end.tv_sec; + end.tv_nsec %= 999999999; + } + + for(;;){ + + struct timespec current = arch_timekeeper_gettime(); + + if(current.tv_sec > end.tv_sec) + break; + + if(current.tv_sec == end.tv_sec && current.tv_nsec > end.tv_nsec) + break; + + arch_interrupt_disable(); + + sched_yield(); + + arch_interrupt_enable(); + + } + + remaining->tv_nsec = 0; + remaining->tv_sec = 0; + + retv.errno = 0; + retv.ret = 0; + + return retv; + + +}