Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752834Ab0KDT2j (ORCPT ); Thu, 4 Nov 2010 15:28:39 -0400 Received: from mail-bw0-f46.google.com ([209.85.214.46]:42120 "EHLO mail-bw0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751277Ab0KDT2i (ORCPT ); Thu, 4 Nov 2010 15:28:38 -0400 DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=date:from:to:cc:subject:message-id:references:mime-version :content-type:content-disposition:in-reply-to:user-agent; b=uQzO4qddoStwQYbFySUon0sTb5btwPTr9FHkpWOOoLRKPI/VukMMmvj3vkd/qTgX38 k1fn8FMzZQnpgbh8ZrfBMrR8QrNcPV+rIdH0hXYSXmq4lUEj6z7y058XWOS1BJjMFCGP HHuQy+JlgZbHkaE9l9plVK6R8Xg284NPIm7nU= Date: Thu, 4 Nov 2010 20:28:32 +0100 From: Richard Cochran To: linux-kernel@vger.kernel.org Cc: linux-api@vger.kernel.org, Alan Cox , Arnd Bergmann , Christoph Lameter , John Stultz , Peter Zijlstra , Thomas Gleixner Subject: [PATCH RFC 2/8] clock device: convert clock_gettime Message-ID: <81ccd2674ebf26332898761ba6b7b54f395a15bd.1288897199.git.richard.cochran@omicron.at> References: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.20 (2009-06-14) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 5710 Lines: 193 This patch lets the clock_gettime system call use dynamic clock devices. Signed-off-by: Richard Cochran --- include/linux/clockdevice.h | 9 ++++++ include/linux/posix-timers.h | 21 ++++++++++++++- include/linux/time.h | 2 + kernel/posix-timers.c | 4 +- kernel/time/clockdevice.c | 58 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 91 insertions(+), 3 deletions(-) diff --git a/include/linux/clockdevice.h b/include/linux/clockdevice.h index a8f9359..ae258ac 100644 --- a/include/linux/clockdevice.h +++ b/include/linux/clockdevice.h @@ -94,4 +94,13 @@ void destroy_clock_device(struct clock_device *clk); */ void *clock_device_private(struct file *fp); +/** + * clockid_to_clock_device() - obtain clock device pointer from a clock id + * @id: user space clock id + * + * Returns a pointer to the clock device, or NULL if the id is not a + * dynamic clock id. + */ +struct clock_device *clockid_to_clock_device(clockid_t id); + #endif diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h index 3e23844..70f40e6 100644 --- a/include/linux/posix-timers.h +++ b/include/linux/posix-timers.h @@ -17,10 +17,22 @@ struct cpu_timer_list { int firing; }; +/* Bit fields within a clockid: + * + * The most significant 29 bits hold either a pid or a file descriptor. + * + * Bit 2 indicates whether a cpu clock refers to a thread or a process. + * + * Bits 1 and 0 give the type: PROF=0, VIRT=1, SCHED=2, or FD=3. + * + * A clockid is invalid if bits 2, 1, and 0 all set (see also CLOCK_INVALID + * in include/linux/time.h) + */ + #define CPUCLOCK_PID(clock) ((pid_t) ~((clock) >> 3)) #define CPUCLOCK_PERTHREAD(clock) \ (((clock) & (clockid_t) CPUCLOCK_PERTHREAD_MASK) != 0) -#define CPUCLOCK_PID_MASK 7 + #define CPUCLOCK_PERTHREAD_MASK 4 #define CPUCLOCK_WHICH(clock) ((clock) & (clockid_t) CPUCLOCK_CLOCK_MASK) #define CPUCLOCK_CLOCK_MASK 3 @@ -28,12 +40,17 @@ struct cpu_timer_list { #define CPUCLOCK_VIRT 1 #define CPUCLOCK_SCHED 2 #define CPUCLOCK_MAX 3 +#define CLOCKFD CPUCLOCK_MAX +#define CLOCKFD_MASK (CPUCLOCK_PERTHREAD_MASK|CPUCLOCK_CLOCK_MASK) #define MAKE_PROCESS_CPUCLOCK(pid, clock) \ ((~(clockid_t) (pid) << 3) | (clockid_t) (clock)) #define MAKE_THREAD_CPUCLOCK(tid, clock) \ MAKE_PROCESS_CPUCLOCK((tid), (clock) | CPUCLOCK_PERTHREAD_MASK) +#define FD_TO_CLOCKID(fd) ((clockid_t) (fd << 3) | CLOCKFD) +#define CLOCKID_TO_FD(clk) (((unsigned int) clk) >> 3) + /* POSIX.1b interval timer structure. */ struct k_itimer { struct list_head list; /* free/ allocate list */ @@ -119,4 +136,6 @@ long clock_nanosleep_restart(struct restart_block *restart_block); void update_rlimit_cpu(struct task_struct *task, unsigned long rlim_new); +int posix_clock_gettime(const clockid_t clock, struct timespec __user *tp); + #endif diff --git a/include/linux/time.h b/include/linux/time.h index 9f15ac7..914c48d 100644 --- a/include/linux/time.h +++ b/include/linux/time.h @@ -299,6 +299,8 @@ struct itimerval { #define CLOCKS_MASK (CLOCK_REALTIME | CLOCK_MONOTONIC) #define CLOCKS_MONO CLOCK_MONOTONIC +#define CLOCK_INVALID -1 + /* * The various flags for setting POSIX.1b interval timers: */ diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c index 9ca4973..4aecbfa 100644 --- a/kernel/posix-timers.c +++ b/kernel/posix-timers.c @@ -952,8 +952,8 @@ SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock, return CLOCK_DISPATCH(which_clock, clock_set, (which_clock, &new_tp)); } -SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock, - struct timespec __user *,tp) +int posix_clock_gettime(const clockid_t which_clock, + struct timespec __user *tp) { struct timespec kernel_tp; int error; diff --git a/kernel/time/clockdevice.c b/kernel/time/clockdevice.c index 323b57b..e80117b 100644 --- a/kernel/time/clockdevice.c +++ b/kernel/time/clockdevice.c @@ -20,8 +20,11 @@ #include #include #include +#include #include #include +#include +#include #define MAX_CLKDEV BITS_PER_LONG static DECLARE_BITMAP(clocks_map, MAX_CLKDEV); @@ -153,3 +156,58 @@ void *clock_device_private(struct file *fp) return clk->priv; } EXPORT_SYMBOL_GPL(clock_device_private); + +static inline bool clock_is_static(clockid_t id) +{ + if (0 == (id & ~CLOCKFD_MASK)) + return true; + if (CLOCKFD == (id & CLOCKFD_MASK)) + return false; + return true; +} + +struct clock_device *clockid_to_clock_device(clockid_t id) +{ + struct clock_device *clk = NULL; + struct file *fp; + + if (clock_is_static(id)) + return NULL; + + fp = fget(CLOCKID_TO_FD(id)); + if (!fp) + return NULL; + + if (fp->f_op->open == clock_device_open) + clk = fp->private_data; + + fput(fp); + return clk; +} + +SYSCALL_DEFINE2(clock_gettime, + const clockid_t, id, struct timespec __user *, user_ts) +{ + struct timespec ts; + struct clock_device *clk; + int err; + + clk = clockid_to_clock_device(id); + if (!clk) + return posix_clock_gettime(id, user_ts); + + mutex_lock(&clk->mux); + + if (clk->zombie) + err = -ENODEV; + else if (!clk->ops->clock_gettime) + err = -EOPNOTSUPP; + else + err = clk->ops->clock_gettime(clk->priv, &ts); + + if (!err && copy_to_user(user_ts, &ts, sizeof(ts))) + err = -EFAULT; + + mutex_unlock(&clk->mux); + return err; +} -- 1.7.0.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/