/* * 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); } }
static int posix_cpu_clock_get(const clockid_t which_clock, struct timespec *tp) { const pid_t pid = CPUCLOCK_PID(which_clock); int error = -EINVAL; unsigned long long rtn; if (pid == 0) { /* * Special case constant value for our own clocks. * We don't have to do any lookup to find ourselves. */ if (CPUCLOCK_PERTHREAD(which_clock)) { /* * Sampling just ourselves we can do with no locking. */ error = cpu_clock_sample(which_clock, current, &rtn); } else { read_lock(&tasklist_lock); error = cpu_clock_sample_group(which_clock, current, &rtn); read_unlock(&tasklist_lock); } } else { /* * Find the given PID, and validate that the caller * should be able to see it. */ struct task_struct *p; rcu_read_lock(); p = find_task_by_vpid(pid); if (p) { if (CPUCLOCK_PERTHREAD(which_clock)) { if (same_thread_group(p, current)) { error = cpu_clock_sample(which_clock, p, &rtn); } } else { read_lock(&tasklist_lock); if (thread_group_leader(p) && p->sighand) { error = cpu_clock_sample_group(which_clock, p, &rtn); } read_unlock(&tasklist_lock); } } rcu_read_unlock(); } if (error) return error; sample_to_timespec(which_clock, rtn, tp); return 0; }
static int posix_cpu_clock_get_task(struct task_struct *tsk, const clockid_t which_clock, struct timespec *tp) { int err = -EINVAL; unsigned long long rtn; if (CPUCLOCK_PERTHREAD(which_clock)) { if (same_thread_group(tsk, current)) err = cpu_clock_sample(which_clock, tsk, &rtn); } else { unsigned long flags; struct sighand_struct *sighand; /* * while_each_thread() is not yet entirely RCU safe, * keep locking the group while sampling process * clock for now. */ sighand = lock_task_sighand(tsk, &flags); if (!sighand) return err; if (tsk == current || thread_group_leader(tsk)) err = cpu_clock_sample_group(which_clock, tsk, &rtn); unlock_task_sighand(tsk, &flags); } if (!err) sample_to_timespec(which_clock, rtn, tp); return err; }
static int posix_cpu_clock_get_task(struct task_struct *tsk, const clockid_t which_clock, struct timespec *tp) { int err = -EINVAL; unsigned long long rtn; if (CPUCLOCK_PERTHREAD(which_clock)) { if (same_thread_group(tsk, current)) err = cpu_clock_sample(which_clock, tsk, &rtn); } else { if (tsk == current || thread_group_leader(tsk)) err = cpu_clock_sample_group(which_clock, tsk, &rtn); } if (!err) sample_to_timespec(which_clock, rtn, tp); return err; }
static void printclockname(int clockid) { #ifdef CLOCKID_TO_FD if (clockid < 0) { if ((clockid & CLOCKFD_MASK) == CLOCKFD) tprintf("FD_TO_CLOCKID(%d)", CLOCKID_TO_FD(clockid)); else { if(CPUCLOCK_PERTHREAD(clockid)) tprintf("MAKE_THREAD_CPUCLOCK(%d,", CPUCLOCK_PID(clockid)); else tprintf("MAKE_PROCESS_CPUCLOCK(%d,", CPUCLOCK_PID(clockid)); printxval(cpuclocknames, clockid & CLOCKFD_MASK, "CPUCLOCK_???"); tprints(")"); } } else #endif printxval(clocknames, clockid, "CLOCK_???"); }
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; }
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 void printclockname(int clockid) { #ifdef CLOCKID_TO_FD # include "xlat/cpuclocknames.h" if (clockid < 0) { if (xlat_verbose(xlat_verbosity) != XLAT_STYLE_ABBREV) tprintf("%d", clockid); if (xlat_verbose(xlat_verbosity) == XLAT_STYLE_RAW) return; if (xlat_verbose(xlat_verbosity) == XLAT_STYLE_VERBOSE) tprints(" /* "); if ((clockid & CLOCKFD_MASK) == CLOCKFD) tprintf("FD_TO_CLOCKID(%d)", CLOCKID_TO_FD(clockid)); else { tprintf("%s(%d,", CPUCLOCK_PERTHREAD(clockid) ? "MAKE_THREAD_CPUCLOCK" : "MAKE_PROCESS_CPUCLOCK", CPUCLOCK_PID(clockid)); printxval_index(cpuclocknames, (unsigned int) clockid & CLOCKFD_MASK, "CPUCLOCK_???"); tprints(")"); } if (xlat_verbose(xlat_verbosity) == XLAT_STYLE_VERBOSE) tprints(" */"); } else #endif printxval_index(clocknames, clockid, "CLOCK_???"); }