/* * Insert the timer on the appropriate list before any timers that * expire later. This must be called with the sighand lock held. */ static void arm_timer(struct k_itimer *timer) { struct task_struct *p = timer->it.cpu.task; struct list_head *head, *listpos; struct task_cputime *cputime_expires; struct cpu_timer_list *const nt = &timer->it.cpu; struct cpu_timer_list *next; if (CPUCLOCK_PERTHREAD(timer->it_clock)) { head = p->cpu_timers; cputime_expires = &p->cputime_expires; } else { head = p->signal->cpu_timers; cputime_expires = &p->signal->cputime_expires; } head += CPUCLOCK_WHICH(timer->it_clock); listpos = head; list_for_each_entry(next, head, entry) { if (nt->expires < next->expires) break; listpos = &next->entry; } list_add(&nt->entry, listpos); if (listpos == head) { unsigned long long exp = nt->expires; /* * We are the new earliest-expiring POSIX 1.b timer, hence * need to update expiration cache. Take into account that * for process timers we share expiration cache with itimers * and RLIMIT_CPU and for thread timers with RLIMIT_RTTIME. */ switch (CPUCLOCK_WHICH(timer->it_clock)) { case CPUCLOCK_PROF: if (expires_gt(cputime_expires->prof_exp, expires_to_cputime(exp))) cputime_expires->prof_exp = expires_to_cputime(exp); break; case CPUCLOCK_VIRT: if (expires_gt(cputime_expires->virt_exp, expires_to_cputime(exp))) cputime_expires->virt_exp = expires_to_cputime(exp); break; case CPUCLOCK_SCHED: if (cputime_expires->sched_exp == 0 || cputime_expires->sched_exp > exp) cputime_expires->sched_exp = exp; break; } if (CPUCLOCK_PERTHREAD(timer->it_clock)) tick_dep_set_task(p, TICK_DEP_BIT_POSIX_TIMER); else tick_dep_set_signal(p->signal, TICK_DEP_BIT_POSIX_TIMER); } }
/* Set CLOCK to value TP. */ int __clock_settime (clockid_t clock_id, const struct timespec *tp) { int retval; /* Make sure the time cvalue is OK. */ if (tp->tv_nsec < 0 || tp->tv_nsec >= 1000000000) { __set_errno (EINVAL); return -1; } switch (clock_id) { #define HANDLE_REALTIME \ do { \ struct timeval tv; \ TIMESPEC_TO_TIMEVAL (&tv, tp); \ \ retval = settimeofday (&tv, NULL); \ } while (0) #ifdef SYSDEP_SETTIME SYSDEP_SETTIME; #endif #ifndef HANDLED_REALTIME case CLOCK_REALTIME: HANDLE_REALTIME; break; #endif default: #ifdef SYSDEP_SETTIME_CPU SYSDEP_SETTIME_CPU; #endif #ifndef HANDLED_CPUTIME # if HP_TIMING_AVAIL if (CPUCLOCK_WHICH (clock_id) == CLOCK_PROCESS_CPUTIME_ID || CPUCLOCK_WHICH (clock_id) == CLOCK_THREAD_CPUTIME_ID) retval = hp_timing_settime (clock_id, tp); else # endif { __set_errno (EINVAL); retval = -1; } #endif break; } return retval; }
/* * Update expiry time from increment, and increase overrun count, * given the current clock sample. */ static void bump_cpu_timer(struct k_itimer *timer, union cpu_time_count now) { int i; if (timer->it.cpu.incr.sched == 0) return; if (CPUCLOCK_WHICH(timer->it_clock) == CPUCLOCK_SCHED) { unsigned long long delta, incr; if (now.sched < timer->it.cpu.expires.sched) return; incr = timer->it.cpu.incr.sched; delta = now.sched + incr - timer->it.cpu.expires.sched; /* Don't use (incr*2 < delta), incr*2 might overflow. */ for (i = 0; incr < delta - incr; i++) incr = incr << 1; for (; i >= 0; incr >>= 1, i--) { if (delta < incr) continue; timer->it.cpu.expires.sched += incr; timer->it_overrun += 1 << i; delta -= incr; } } else {
static void sample_to_timespec(const clockid_t which_clock, unsigned long long expires, struct timespec *tp) { if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED) *tp = ns_to_timespec(expires); else cputime_to_timespec((__force cputime_t)expires, tp); }
static void sample_to_timespec(const clockid_t which_clock, union cpu_time_count cpu, struct timespec *tp) { if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED) *tp = ns_to_timespec(cpu.sched); else cputime_to_timespec(cpu.cpu, tp); }
static inline int cpu_time_before(const clockid_t which_clock, union cpu_time_count now, union cpu_time_count then) { if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED) { return now.sched < then.sched; } else { return cputime_lt(now.cpu, then.cpu); } }
static inline void cpu_time_add(const clockid_t which_clock, union cpu_time_count *acc, union cpu_time_count val) { if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED) { acc->sched += val.sched; } else { acc->cpu = cputime_add(acc->cpu, val.cpu); } }
static void sample_to_timespec(const clockid_t which_clock, union cpu_time_count cpu, struct timespec *tp) { if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED) { tp->tv_sec = div_long_long_rem(cpu.sched, NSEC_PER_SEC, &tp->tv_nsec); } else { cputime_to_timespec(cpu.cpu, tp); } }
static inline union cpu_time_count cpu_time_sub(const clockid_t which_clock, union cpu_time_count a, union cpu_time_count b) { if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED) { a.sched -= b.sched; } else { a.cpu = cputime_sub(a.cpu, b.cpu); } return a; }
static inline union cpu_time_count timespec_to_sample(const clockid_t which_clock, const struct timespec *tp) { union cpu_time_count ret; ret.sched = 0; /* high half always zero when .cpu used */ if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED) { ret.sched = (unsigned long long)tp->tv_sec * NSEC_PER_SEC + tp->tv_nsec; } else { ret.cpu = timespec_to_cputime(tp); } return ret; }
static int posix_cpu_clock_getres(const clockid_t which_clock, struct timespec *tp) { int error = check_clock(which_clock); if (!error) { tp->tv_sec = 0; tp->tv_nsec = ((NSEC_PER_SEC + HZ - 1) / HZ); if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED) { /* * If sched_clock is using a cycle counter, we * don't have any idea of its true resolution * exported, but it is much more than 1s/HZ. */ tp->tv_nsec = 1; } } return error; }
/* * Sample a per-thread clock for the given task. */ static int cpu_clock_sample(const clockid_t which_clock, struct task_struct *p, unsigned long long *sample) { switch (CPUCLOCK_WHICH(which_clock)) { default: return -EINVAL; case CPUCLOCK_PROF: *sample = prof_ticks(p); break; case CPUCLOCK_VIRT: *sample = virt_ticks(p); break; case CPUCLOCK_SCHED: *sample = task_sched_runtime(p); break; } return 0; }
/* * Sample a process (thread group) timer for the given group_leader task. * Must be called with task sighand lock held for safe while_each_thread() * traversal. */ static int cpu_timer_sample_group(const clockid_t which_clock, struct task_struct *p, u64 *sample) { struct task_cputime cputime; thread_group_cputimer(p, &cputime); switch (CPUCLOCK_WHICH(which_clock)) { default: return -EINVAL; case CPUCLOCK_PROF: *sample = cputime.utime + cputime.stime; break; case CPUCLOCK_VIRT: *sample = cputime.utime; break; case CPUCLOCK_SCHED: *sample = cputime.sum_exec_runtime; break; } return 0; }
static int check_clock(const clockid_t which_clock) { int error = 0; struct task_struct *p; const pid_t pid = CPUCLOCK_PID(which_clock); if (CPUCLOCK_WHICH(which_clock) >= CPUCLOCK_MAX) return -EINVAL; if (pid == 0) return 0; read_lock(&tasklist_lock); p = find_task_by_pid(pid); if (!p || (CPUCLOCK_PERTHREAD(which_clock) ? p->tgid != current->tgid : p->tgid != pid)) { error = -EINVAL; } read_unlock(&tasklist_lock); return error; }
static int check_clock(const clockid_t which_clock) { int error = 0; struct task_struct *p; const pid_t pid = CPUCLOCK_PID(which_clock); if (CPUCLOCK_WHICH(which_clock) >= CPUCLOCK_MAX) return -EINVAL; if (pid == 0) return 0; read_lock(&tasklist_lock); p = find_task_by_vpid(pid); if (!p || !(CPUCLOCK_PERTHREAD(which_clock) ? same_thread_group(p, current) : thread_group_leader(p))) { error = -EINVAL; } read_unlock(&tasklist_lock); return error; }
/* * Validate the clockid_t for a new CPU-clock timer, and initialize the timer. * This is called from sys_timer_create() and do_cpu_nanosleep() with the * new timer already all-zeros initialized. */ static int posix_cpu_timer_create(struct k_itimer *new_timer) { int ret = 0; const pid_t pid = CPUCLOCK_PID(new_timer->it_clock); struct task_struct *p; if (CPUCLOCK_WHICH(new_timer->it_clock) >= CPUCLOCK_MAX) return -EINVAL; INIT_LIST_HEAD(&new_timer->it.cpu.entry); rcu_read_lock(); if (CPUCLOCK_PERTHREAD(new_timer->it_clock)) { if (pid == 0) { p = current; } else { p = find_task_by_vpid(pid); if (p && !same_thread_group(p, current)) p = NULL; } } else { if (pid == 0) { p = current->group_leader; } else { p = find_task_by_vpid(pid); if (p && !has_group_leader_pid(p)) p = NULL; } } new_timer->it.cpu.task = p; if (p) { get_task_struct(p); } else { ret = -EINVAL; } rcu_read_unlock(); return ret; }
/* * Sample a process (thread group) clock for the given group_leader task. * Must be called with task sighand lock held for safe while_each_thread() * traversal. */ static int cpu_clock_sample_group(const clockid_t which_clock, struct task_struct *p, unsigned long long *sample) { struct task_cputime cputime; switch (CPUCLOCK_WHICH(which_clock)) { default: return -EINVAL; case CPUCLOCK_PROF: thread_group_cputime(p, &cputime); *sample = cputime_to_expires(cputime.utime + cputime.stime); break; case CPUCLOCK_VIRT: thread_group_cputime(p, &cputime); *sample = cputime_to_expires(cputime.utime); break; case CPUCLOCK_SCHED: thread_group_cputime(p, &cputime); *sample = cputime.sum_exec_runtime; break; } return 0; }