support setitimer/getitimer
This commit is contained in:
@ -51,6 +51,8 @@ SYSCALL_HANDLED(30, shmat)
|
|||||||
SYSCALL_HANDLED(31, shmctl)
|
SYSCALL_HANDLED(31, shmctl)
|
||||||
SYSCALL_HANDLED(34, pause)
|
SYSCALL_HANDLED(34, pause)
|
||||||
SYSCALL_HANDLED(35, nanosleep)
|
SYSCALL_HANDLED(35, nanosleep)
|
||||||
|
SYSCALL_HANDLED(36, getitimer)
|
||||||
|
SYSCALL_HANDLED(38, setitimer)
|
||||||
SYSCALL_HANDLED(39, getpid)
|
SYSCALL_HANDLED(39, getpid)
|
||||||
SYSCALL_HANDLED(56, clone)
|
SYSCALL_HANDLED(56, clone)
|
||||||
SYSCALL_DELEGATED(57, fork)
|
SYSCALL_DELEGATED(57, fork)
|
||||||
|
|||||||
@ -533,6 +533,13 @@ struct thread {
|
|||||||
struct timespec btime;
|
struct timespec btime;
|
||||||
int times_update;
|
int times_update;
|
||||||
int in_kernel;
|
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 {
|
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_process(struct process *);
|
||||||
void chain_thread(struct thread *);
|
void chain_thread(struct thread *);
|
||||||
void proc_init();
|
void proc_init();
|
||||||
|
void set_timer();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -53,6 +53,15 @@ struct timezone
|
|||||||
int tz_dsttime; /* Nonzero if DST is ever in effect. */
|
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
|
static inline void
|
||||||
ts_add(struct timespec *ats, const struct timespec *bts)
|
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
|
#endif // __TIME_H
|
||||||
|
|
||||||
|
|||||||
@ -2478,6 +2478,26 @@ ack:
|
|||||||
ihk_mc_spinlock_unlock(&cur_v->migq_lock, irqstate);
|
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)
|
void schedule(void)
|
||||||
{
|
{
|
||||||
struct cpu_local_var *v;
|
struct cpu_local_var *v;
|
||||||
@ -2516,20 +2536,6 @@ redo:
|
|||||||
list_add_tail(&prev->sched_list, &(v->runq));
|
list_add_tail(&prev->sched_list, &(v->runq));
|
||||||
++v->runq_len;
|
++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) {
|
if (v->flags & CPU_FLAG_NEED_MIGRATE) {
|
||||||
@ -2556,6 +2562,8 @@ redo:
|
|||||||
reset_cputime();
|
reset_cputime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set_timer();
|
||||||
|
|
||||||
if (switch_ctx) {
|
if (switch_ctx) {
|
||||||
dkprintf("schedule: %d => %d \n",
|
dkprintf("schedule: %d => %d \n",
|
||||||
prev ? prev->tid : 0, next ? next->tid : 0);
|
prev ? prev->tid : 0, next ? next->tid : 0);
|
||||||
|
|||||||
181
kernel/syscall.c
181
kernel/syscall.c
@ -5238,6 +5238,125 @@ static void calculate_time_from_tsc(struct timespec *ts)
|
|||||||
return;
|
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)
|
SYSCALL_DECLARE(clock_gettime)
|
||||||
{
|
{
|
||||||
/* TODO: handle clock_id */
|
/* TODO: handle clock_id */
|
||||||
@ -6735,11 +6854,17 @@ set_cputime(int mode)
|
|||||||
dts.tv_sec = ats.tv_sec;
|
dts.tv_sec = ats.tv_sec;
|
||||||
dts.tv_nsec = ats.tv_nsec;
|
dts.tv_nsec = ats.tv_nsec;
|
||||||
ts_sub(&dts, &thread->btime);
|
ts_sub(&dts, &thread->btime);
|
||||||
if(mode == 1)
|
if(mode == 1){
|
||||||
ts_add(&thread->utime, &dts);
|
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->stime, &dts);
|
||||||
|
ts_add(&thread->itimer_prof_value, &dts);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mode == 2){
|
if(mode == 2){
|
||||||
thread->btime.tv_sec = 0;
|
thread->btime.tv_sec = 0;
|
||||||
thread->btime.tv_nsec = 0;
|
thread->btime.tv_nsec = 0;
|
||||||
@ -6750,6 +6875,58 @@ set_cputime(int mode)
|
|||||||
}
|
}
|
||||||
thread->times_update = 1;
|
thread->times_update = 1;
|
||||||
thread->in_kernel = mode;
|
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)
|
long syscall(int num, ihk_mc_user_context_t *ctx)
|
||||||
|
|||||||
Reference in New Issue
Block a user