This patch lets the clock_gettime system call use dynamic clock devices.

Signed-off-by: Richard Cochran <[email protected]>
---
 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 <linux/cdev.h>
 #include <linux/clockdevice.h>
 #include <linux/device.h>
+#include <linux/file.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
+#include <linux/syscalls.h>
+#include <linux/uaccess.h>
 
 #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-api" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to