From 2c50b716fd2a6bfadd5118b0ea07d5278a01aa2b Mon Sep 17 00:00:00 2001 From: Tomoki Shirasawa Date: Fri, 19 Feb 2016 15:25:05 +0900 Subject: [PATCH] support setitimer/getitimer --- arch/x86/kernel/include/syscall_list.h | 2 + kernel/include/process.h | 8 ++ kernel/include/time.h | 45 ++++++ kernel/process.c | 36 +++-- kernel/syscall.c | 181 ++++++++++++++++++++++++- 5 files changed, 256 insertions(+), 16 deletions(-) diff --git a/arch/x86/kernel/include/syscall_list.h b/arch/x86/kernel/include/syscall_list.h index daf632b7..33212922 100644 --- a/arch/x86/kernel/include/syscall_list.h +++ b/arch/x86/kernel/include/syscall_list.h @@ -51,6 +51,8 @@ SYSCALL_HANDLED(30, shmat) SYSCALL_HANDLED(31, shmctl) SYSCALL_HANDLED(34, pause) SYSCALL_HANDLED(35, nanosleep) +SYSCALL_HANDLED(36, getitimer) +SYSCALL_HANDLED(38, setitimer) SYSCALL_HANDLED(39, getpid) SYSCALL_HANDLED(56, clone) SYSCALL_DELEGATED(57, fork) diff --git a/kernel/include/process.h b/kernel/include/process.h index a9fded27..e7e88e4d 100644 --- a/kernel/include/process.h +++ b/kernel/include/process.h @@ -533,6 +533,13 @@ struct thread { struct timespec btime; int times_update; int in_kernel; + + // interval timers + int itimer_enabled; + struct itimerval itimer_virtual; + struct itimerval itimer_prof; + struct timespec itimer_virtual_value; + struct timespec itimer_prof_value; }; struct process_vm { @@ -636,5 +643,6 @@ void process_unlock(struct process *proc, struct mcs_rwlock_node_irqsave *lock); void chain_process(struct process *); void chain_thread(struct thread *); void proc_init(); +void set_timer(); #endif diff --git a/kernel/include/time.h b/kernel/include/time.h index 5df0d8fb..b4c1bffd 100644 --- a/kernel/include/time.h +++ b/kernel/include/time.h @@ -53,6 +53,15 @@ struct timezone int tz_dsttime; /* Nonzero if DST is ever in effect. */ }; +#define ITIMER_REAL 0 +#define ITIMER_VIRTUAL 1 +#define ITIMER_PROF 2 + +struct itimerval { + struct timeval it_interval; + struct timeval it_value; +}; + static inline void ts_add(struct timespec *ats, const struct timespec *bts) { @@ -75,5 +84,41 @@ ts_sub(struct timespec *ats, const struct timespec *bts) } } +static inline void +tv_add(struct timeval *ats, const struct timeval *bts) +{ + ats->tv_sec += bts->tv_sec; + ats->tv_usec += bts->tv_usec; + while(ats->tv_usec >= 1000000){ + ats->tv_sec++; + ats->tv_usec -= 1000000; + } +} + +static inline void +tv_sub(struct timeval *ats, const struct timeval *bts) +{ + ats->tv_sec -= bts->tv_sec; + ats->tv_usec -= bts->tv_usec; + while(ats->tv_usec < 0){ + ats->tv_sec--; + ats->tv_usec += 1000000; + } +} + +static inline void +tv_to_ts(struct timespec *ats, const struct timeval *bts) +{ + ats->tv_sec = bts->tv_sec; + ats->tv_nsec = bts->tv_usec * 1000; +} + +static inline void +ts_to_tv(struct timeval *ats, const struct timespec *bts) +{ + ats->tv_sec = bts->tv_sec; + ats->tv_usec = bts->tv_nsec / 1000; +} + #endif // __TIME_H diff --git a/kernel/process.c b/kernel/process.c index c609cbbb..32d74a86 100644 --- a/kernel/process.c +++ b/kernel/process.c @@ -2478,6 +2478,26 @@ ack: ihk_mc_spinlock_unlock(&cur_v->migq_lock, irqstate); } +void +set_timer() +{ + struct cpu_local_var *v = get_this_cpu_local_var(); + + /* Toggle timesharing if CPU core is oversubscribed */ + if (v->runq_len > 1 || v->current->itimer_enabled) { + if (!cpu_local_var(timer_enabled)) { + lapic_timer_enable(10000000); + cpu_local_var(timer_enabled) = 1; + } + } + else { + if (cpu_local_var(timer_enabled)) { + lapic_timer_disable(); + cpu_local_var(timer_enabled) = 0; + } + } +} + void schedule(void) { struct cpu_local_var *v; @@ -2516,20 +2536,6 @@ redo: list_add_tail(&prev->sched_list, &(v->runq)); ++v->runq_len; } - - /* Toggle timesharing if CPU core is oversubscribed */ - if (v->runq_len > 1) { - if (!cpu_local_var(timer_enabled)) { - lapic_timer_enable(10000000); - cpu_local_var(timer_enabled) = 1; - } - } - else { - if (cpu_local_var(timer_enabled)) { - lapic_timer_disable(); - cpu_local_var(timer_enabled) = 0; - } - } } if (v->flags & CPU_FLAG_NEED_MIGRATE) { @@ -2556,6 +2562,8 @@ redo: reset_cputime(); } + set_timer(); + if (switch_ctx) { dkprintf("schedule: %d => %d \n", prev ? prev->tid : 0, next ? next->tid : 0); diff --git a/kernel/syscall.c b/kernel/syscall.c index 09daebed..a51cfeeb 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -5238,6 +5238,125 @@ static void calculate_time_from_tsc(struct timespec *ts) return; } +SYSCALL_DECLARE(setitimer) +{ + int which = (int)ihk_mc_syscall_arg0(ctx); + struct itimerval *new = (struct itimerval *)ihk_mc_syscall_arg1(ctx); + struct itimerval *old = (struct itimerval *)ihk_mc_syscall_arg2(ctx); + struct syscall_request request IHK_DMA_ALIGN; + struct thread *thread = cpu_local_var(current); + int timer_start = 1; + struct itimerval wkval; + struct timeval tv; + + if(which != ITIMER_REAL && + which != ITIMER_VIRTUAL && + which != ITIMER_PROF) + return -EINVAL; + + if(which == ITIMER_REAL){ + request.number = __NR_setitimer; + request.args[0] = ihk_mc_syscall_arg0(ctx); + request.args[1] = ihk_mc_syscall_arg1(ctx); + request.args[2] = ihk_mc_syscall_arg2(ctx); + + return do_syscall(&request, ihk_mc_get_processor_id(), 0); + } + else if(which == ITIMER_VIRTUAL){ + if(old){ + memcpy(&wkval, &thread->itimer_virtual, sizeof wkval); + if(wkval.it_value.tv_sec != 0 || + wkval.it_value.tv_usec != 0){ + ts_to_tv(&tv, &thread->itimer_virtual_value); + tv_sub(&wkval.it_value, &tv); + } + if(copy_to_user(old, &wkval, sizeof wkval)) + return -EFAULT; + } + if(!new){ + return 0; + } + if(copy_from_user(&thread->itimer_virtual, new, sizeof(struct itimerval))) + thread->itimer_virtual_value.tv_sec = 0; + thread->itimer_virtual_value.tv_nsec = 0; + if(thread->itimer_virtual.it_value.tv_sec == 0 && + thread->itimer_virtual.it_value.tv_usec == 0) + timer_start = 0; + } + else if(which == ITIMER_PROF){ + if(old){ + memcpy(&wkval, &thread->itimer_prof, sizeof wkval); + if(wkval.it_value.tv_sec != 0 || + wkval.it_value.tv_usec != 0){ + ts_to_tv(&tv, &thread->itimer_prof_value); + tv_sub(&wkval.it_value, &tv); + } + if(copy_to_user(old, &wkval, sizeof wkval)) + return -EFAULT; + } + if(!new){ + return 0; + } + if(copy_from_user(&thread->itimer_prof, new, sizeof(struct itimerval))) + thread->itimer_prof_value.tv_sec = 0; + thread->itimer_prof_value.tv_nsec = 0; + if(thread->itimer_prof.it_value.tv_sec == 0 && + thread->itimer_prof.it_value.tv_usec == 0) + timer_start = 0; + } + thread->itimer_enabled = timer_start; + set_timer(); + return 0; +} + +SYSCALL_DECLARE(getitimer) +{ + int which = (int)ihk_mc_syscall_arg0(ctx); + struct itimerval *old = (struct itimerval *)ihk_mc_syscall_arg1(ctx); + struct syscall_request request IHK_DMA_ALIGN; + struct thread *thread = cpu_local_var(current); + struct itimerval wkval; + struct timeval tv; + + if(which != ITIMER_REAL && + which != ITIMER_VIRTUAL && + which != ITIMER_PROF) + return -EINVAL; + + if(which == ITIMER_REAL){ + request.number = __NR_getitimer; + request.args[0] = ihk_mc_syscall_arg0(ctx); + request.args[1] = ihk_mc_syscall_arg1(ctx); + + return do_syscall(&request, ihk_mc_get_processor_id(), 0); + } + else if(which == ITIMER_VIRTUAL){ + if(old){ + memcpy(&wkval, &thread->itimer_virtual, sizeof wkval); + if(wkval.it_value.tv_sec != 0 || + wkval.it_value.tv_usec != 0){ + ts_to_tv(&tv, &thread->itimer_virtual_value); + tv_sub(&wkval.it_value, &tv); + } + if(copy_to_user(old, &wkval, sizeof wkval)) + return -EFAULT; + } + } + else if(which == ITIMER_PROF){ + if(old){ + memcpy(&wkval, &thread->itimer_prof, sizeof wkval); + if(wkval.it_value.tv_sec != 0 || + wkval.it_value.tv_usec != 0){ + ts_to_tv(&tv, &thread->itimer_prof_value); + tv_sub(&wkval.it_value, &tv); + } + if(copy_to_user(old, &wkval, sizeof wkval)) + return -EFAULT; + } + } + return 0; +} + SYSCALL_DECLARE(clock_gettime) { /* TODO: handle clock_id */ @@ -6735,11 +6854,17 @@ set_cputime(int mode) dts.tv_sec = ats.tv_sec; dts.tv_nsec = ats.tv_nsec; ts_sub(&dts, &thread->btime); - if(mode == 1) + if(mode == 1){ ts_add(&thread->utime, &dts); - else + ts_add(&thread->itimer_virtual_value, &dts); + ts_add(&thread->itimer_prof_value, &dts); + } + else{ ts_add(&thread->stime, &dts); + ts_add(&thread->itimer_prof_value, &dts); + } } + if(mode == 2){ thread->btime.tv_sec = 0; thread->btime.tv_nsec = 0; @@ -6750,6 +6875,58 @@ set_cputime(int mode) } thread->times_update = 1; thread->in_kernel = mode; + + if(thread->itimer_enabled){ + struct timeval tv; + int ev = 0; + + if(thread->itimer_virtual.it_value.tv_sec != 0 || + thread->itimer_virtual.it_value.tv_usec){ + ts_to_tv(&tv, &thread->itimer_virtual_value); + tv_sub(&tv, &thread->itimer_virtual.it_value); + if(tv.tv_sec > 0 || + (tv.tv_sec == 0 && + tv.tv_usec > 0)){ + thread->itimer_virtual_value.tv_sec = 0; + thread->itimer_virtual_value.tv_nsec = 0; + thread->itimer_virtual.it_value.tv_sec = + thread->itimer_virtual.it_interval.tv_sec; + thread->itimer_virtual.it_value.tv_usec = + thread->itimer_virtual.it_interval.tv_usec; + do_kill(thread, thread->proc->pid, thread->tid, + SIGVTALRM, NULL, 0); + ev = 1; + } + } + + if(thread->itimer_prof.it_value.tv_sec != 0 || + thread->itimer_prof.it_value.tv_usec){ + ts_to_tv(&tv, &thread->itimer_prof_value); + tv_sub(&tv, &thread->itimer_prof.it_value); + if(tv.tv_sec > 0 || + (tv.tv_sec == 0 && + tv.tv_usec > 0)){ + thread->itimer_prof_value.tv_sec = 0; + thread->itimer_prof_value.tv_nsec = 0; + thread->itimer_prof.it_value.tv_sec = + thread->itimer_prof.it_interval.tv_sec; + thread->itimer_prof.it_value.tv_usec = + thread->itimer_prof.it_interval.tv_usec; + do_kill(thread, thread->proc->pid, thread->tid, + SIGPROF, NULL, 0); + ev = 1; + } + } + if(ev){ + if(thread->itimer_virtual.it_value.tv_sec == 0 && + thread->itimer_virtual.it_value.tv_usec == 0 && + thread->itimer_prof.it_value.tv_sec == 0 && + thread->itimer_prof.it_value.tv_usec == 0){ + thread->itimer_enabled = 0; + set_timer(); + } + } + } } long syscall(int num, ihk_mc_user_context_t *ctx)