Skip to content

Commit 0606f42

Browse files
richardcochranKAGA-KOKO
authored andcommitted
posix clocks: Introduce dynamic clocks
This patch adds support for adding and removing posix clocks. The clock lifetime cycle is patterned after usb devices. Each clock is represented by a standard character device. In addition, the driver may optionally implement custom character device operations. The posix clock and timer system calls listed below now work with dynamic posix clocks, as well as the traditional static clocks. The following system calls are affected: - clock_adjtime (brand new syscall) - clock_gettime - clock_getres - clock_settime - timer_create - timer_delete - timer_gettime - timer_settime [ tglx: Adapted to the posix-timer cleanup. Moved clock_posix_dynamic to posix-clock.c and made all referenced functions static ] Signed-off-by: Richard Cochran <[email protected]> Acked-by: John Stultz <[email protected]> LKML-Reference: <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]>
1 parent 5270873 commit 0606f42

File tree

5 files changed

+601
-3
lines changed

5 files changed

+601
-3
lines changed

include/linux/posix-clock.h

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/*
2+
* posix-clock.h - support for dynamic clock devices
3+
*
4+
* Copyright (C) 2010 OMICRON electronics GmbH
5+
*
6+
* This program is free software; you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation; either version 2 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program; if not, write to the Free Software
18+
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19+
*/
20+
#ifndef _LINUX_POSIX_CLOCK_H_
21+
#define _LINUX_POSIX_CLOCK_H_
22+
23+
#include <linux/cdev.h>
24+
#include <linux/fs.h>
25+
#include <linux/poll.h>
26+
#include <linux/posix-timers.h>
27+
28+
struct posix_clock;
29+
30+
/**
31+
* struct posix_clock_operations - functional interface to the clock
32+
*
33+
* Every posix clock is represented by a character device. Drivers may
34+
* optionally offer extended capabilities by implementing the
35+
* character device methods. The character device file operations are
36+
* first handled by the clock device layer, then passed on to the
37+
* driver by calling these functions.
38+
*
39+
* @owner: The clock driver should set to THIS_MODULE
40+
* @clock_adjtime: Adjust the clock
41+
* @clock_gettime: Read the current time
42+
* @clock_getres: Get the clock resolution
43+
* @clock_settime: Set the current time value
44+
* @timer_create: Create a new timer
45+
* @timer_delete: Remove a previously created timer
46+
* @timer_gettime: Get remaining time and interval of a timer
47+
* @timer_setttime: Set a timer's initial expiration and interval
48+
* @fasync: Optional character device fasync method
49+
* @mmap: Optional character device mmap method
50+
* @open: Optional character device open method
51+
* @release: Optional character device release method
52+
* @ioctl: Optional character device ioctl method
53+
* @read: Optional character device read method
54+
* @poll: Optional character device poll method
55+
*/
56+
struct posix_clock_operations {
57+
struct module *owner;
58+
59+
int (*clock_adjtime)(struct posix_clock *pc, struct timex *tx);
60+
61+
int (*clock_gettime)(struct posix_clock *pc, struct timespec *ts);
62+
63+
int (*clock_getres) (struct posix_clock *pc, struct timespec *ts);
64+
65+
int (*clock_settime)(struct posix_clock *pc,
66+
const struct timespec *ts);
67+
68+
int (*timer_create) (struct posix_clock *pc, struct k_itimer *kit);
69+
70+
int (*timer_delete) (struct posix_clock *pc, struct k_itimer *kit);
71+
72+
void (*timer_gettime)(struct posix_clock *pc,
73+
struct k_itimer *kit, struct itimerspec *tsp);
74+
75+
int (*timer_settime)(struct posix_clock *pc,
76+
struct k_itimer *kit, int flags,
77+
struct itimerspec *tsp, struct itimerspec *old);
78+
/*
79+
* Optional character device methods:
80+
*/
81+
int (*fasync) (struct posix_clock *pc,
82+
int fd, struct file *file, int on);
83+
84+
long (*ioctl) (struct posix_clock *pc,
85+
unsigned int cmd, unsigned long arg);
86+
87+
int (*mmap) (struct posix_clock *pc,
88+
struct vm_area_struct *vma);
89+
90+
int (*open) (struct posix_clock *pc, fmode_t f_mode);
91+
92+
uint (*poll) (struct posix_clock *pc,
93+
struct file *file, poll_table *wait);
94+
95+
int (*release) (struct posix_clock *pc);
96+
97+
ssize_t (*read) (struct posix_clock *pc,
98+
uint flags, char __user *buf, size_t cnt);
99+
};
100+
101+
/**
102+
* struct posix_clock - represents a dynamic posix clock
103+
*
104+
* @ops: Functional interface to the clock
105+
* @cdev: Character device instance for this clock
106+
* @kref: Reference count.
107+
* @mutex: Protects the 'zombie' field from concurrent access.
108+
* @zombie: If 'zombie' is true, then the hardware has disappeared.
109+
* @release: A function to free the structure when the reference count reaches
110+
* zero. May be NULL if structure is statically allocated.
111+
*
112+
* Drivers should embed their struct posix_clock within a private
113+
* structure, obtaining a reference to it during callbacks using
114+
* container_of().
115+
*/
116+
struct posix_clock {
117+
struct posix_clock_operations ops;
118+
struct cdev cdev;
119+
struct kref kref;
120+
struct mutex mutex;
121+
bool zombie;
122+
void (*release)(struct posix_clock *clk);
123+
};
124+
125+
/**
126+
* posix_clock_register() - register a new clock
127+
* @clk: Pointer to the clock. Caller must provide 'ops' and 'release'
128+
* @devid: Allocated device id
129+
*
130+
* A clock driver calls this function to register itself with the
131+
* clock device subsystem. If 'clk' points to dynamically allocated
132+
* memory, then the caller must provide a 'release' function to free
133+
* that memory.
134+
*
135+
* Returns zero on success, non-zero otherwise.
136+
*/
137+
int posix_clock_register(struct posix_clock *clk, dev_t devid);
138+
139+
/**
140+
* posix_clock_unregister() - unregister a clock
141+
* @clk: Clock instance previously registered via posix_clock_register()
142+
*
143+
* A clock driver calls this function to remove itself from the clock
144+
* device subsystem. The posix_clock itself will remain (in an
145+
* inactive state) until its reference count drops to zero, at which
146+
* point it will be deallocated with its 'release' method.
147+
*/
148+
void posix_clock_unregister(struct posix_clock *clk);
149+
150+
#endif

include/linux/posix-timers.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ struct cpu_timer_list {
3232
#define CPUCLOCK_PID(clock) ((pid_t) ~((clock) >> 3))
3333
#define CPUCLOCK_PERTHREAD(clock) \
3434
(((clock) & (clockid_t) CPUCLOCK_PERTHREAD_MASK) != 0)
35-
#define CPUCLOCK_PID_MASK 7
35+
3636
#define CPUCLOCK_PERTHREAD_MASK 4
3737
#define CPUCLOCK_WHICH(clock) ((clock) & (clockid_t) CPUCLOCK_CLOCK_MASK)
3838
#define CPUCLOCK_CLOCK_MASK 3
@@ -48,6 +48,9 @@ struct cpu_timer_list {
4848
#define MAKE_THREAD_CPUCLOCK(tid, clock) \
4949
MAKE_PROCESS_CPUCLOCK((tid), (clock) | CPUCLOCK_PERTHREAD_MASK)
5050

51+
#define FD_TO_CLOCKID(fd) ((~(clockid_t) (fd) << 3) | CLOCKFD)
52+
#define CLOCKID_TO_FD(clk) ((unsigned int) ~((clk) >> 3))
53+
5154
/* POSIX.1b interval timer structure. */
5255
struct k_itimer {
5356
struct list_head list; /* free/ allocate list */
@@ -100,6 +103,7 @@ struct k_clock {
100103
};
101104

102105
extern struct k_clock clock_posix_cpu;
106+
extern struct k_clock clock_posix_dynamic;
103107

104108
void posix_timers_register_clock(const clockid_t clock_id, struct k_clock *new_clock);
105109

kernel/posix-timers.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include <linux/init.h>
4242
#include <linux/compiler.h>
4343
#include <linux/idr.h>
44+
#include <linux/posix-clock.h>
4445
#include <linux/posix-timers.h>
4546
#include <linux/syscalls.h>
4647
#include <linux/wait.h>
@@ -489,7 +490,8 @@ static void release_posix_timer(struct k_itimer *tmr, int it_id_set)
489490
static struct k_clock *clockid_to_kclock(const clockid_t id)
490491
{
491492
if (id < 0)
492-
return (id & CLOCKFD_MASK) == CLOCKFD ? NULL : &clock_posix_cpu;
493+
return (id & CLOCKFD_MASK) == CLOCKFD ?
494+
&clock_posix_dynamic : &clock_posix_cpu;
493495

494496
if (id >= MAX_CLOCKS || !posix_clocks[id].clock_getres)
495497
return NULL;

kernel/time/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o timecompare.o timeconv.o
1+
obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o timecompare.o
2+
obj-y += timeconv.o posix-clock.o
23

34
obj-$(CONFIG_GENERIC_CLOCKEVENTS_BUILD) += clockevents.o
45
obj-$(CONFIG_GENERIC_CLOCKEVENTS) += tick-common.o

0 commit comments

Comments
 (0)