Skip to content
This repository has been archived by the owner on Oct 31, 2024. It is now read-only.

Commit

Permalink
posix clocks: Introduce dynamic clocks
Browse files Browse the repository at this point in the history
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 <richard.cochran@omicron.at>
Acked-by: John Stultz <johnstul@us.ibm.com>
LKML-Reference: <20110201134420.164172635@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
  • Loading branch information
richardcochran authored and KAGA-KOKO committed Feb 2, 2011
1 parent 5270873 commit 0606f42
Show file tree
Hide file tree
Showing 5 changed files with 601 additions and 3 deletions.
150 changes: 150 additions & 0 deletions include/linux/posix-clock.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/*
* posix-clock.h - support for dynamic clock devices
*
* Copyright (C) 2010 OMICRON electronics GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef _LINUX_POSIX_CLOCK_H_
#define _LINUX_POSIX_CLOCK_H_

#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/poll.h>
#include <linux/posix-timers.h>

struct posix_clock;

/**
* struct posix_clock_operations - functional interface to the clock
*
* Every posix clock is represented by a character device. Drivers may
* optionally offer extended capabilities by implementing the
* character device methods. The character device file operations are
* first handled by the clock device layer, then passed on to the
* driver by calling these functions.
*
* @owner: The clock driver should set to THIS_MODULE
* @clock_adjtime: Adjust the clock
* @clock_gettime: Read the current time
* @clock_getres: Get the clock resolution
* @clock_settime: Set the current time value
* @timer_create: Create a new timer
* @timer_delete: Remove a previously created timer
* @timer_gettime: Get remaining time and interval of a timer
* @timer_setttime: Set a timer's initial expiration and interval
* @fasync: Optional character device fasync method
* @mmap: Optional character device mmap method
* @open: Optional character device open method
* @release: Optional character device release method
* @ioctl: Optional character device ioctl method
* @read: Optional character device read method
* @poll: Optional character device poll method
*/
struct posix_clock_operations {
struct module *owner;

int (*clock_adjtime)(struct posix_clock *pc, struct timex *tx);

int (*clock_gettime)(struct posix_clock *pc, struct timespec *ts);

int (*clock_getres) (struct posix_clock *pc, struct timespec *ts);

int (*clock_settime)(struct posix_clock *pc,
const struct timespec *ts);

int (*timer_create) (struct posix_clock *pc, struct k_itimer *kit);

int (*timer_delete) (struct posix_clock *pc, struct k_itimer *kit);

void (*timer_gettime)(struct posix_clock *pc,
struct k_itimer *kit, struct itimerspec *tsp);

int (*timer_settime)(struct posix_clock *pc,
struct k_itimer *kit, int flags,
struct itimerspec *tsp, struct itimerspec *old);
/*
* Optional character device methods:
*/
int (*fasync) (struct posix_clock *pc,
int fd, struct file *file, int on);

long (*ioctl) (struct posix_clock *pc,
unsigned int cmd, unsigned long arg);

int (*mmap) (struct posix_clock *pc,
struct vm_area_struct *vma);

int (*open) (struct posix_clock *pc, fmode_t f_mode);

uint (*poll) (struct posix_clock *pc,
struct file *file, poll_table *wait);

int (*release) (struct posix_clock *pc);

ssize_t (*read) (struct posix_clock *pc,
uint flags, char __user *buf, size_t cnt);
};

/**
* struct posix_clock - represents a dynamic posix clock
*
* @ops: Functional interface to the clock
* @cdev: Character device instance for this clock
* @kref: Reference count.
* @mutex: Protects the 'zombie' field from concurrent access.
* @zombie: If 'zombie' is true, then the hardware has disappeared.
* @release: A function to free the structure when the reference count reaches
* zero. May be NULL if structure is statically allocated.
*
* Drivers should embed their struct posix_clock within a private
* structure, obtaining a reference to it during callbacks using
* container_of().
*/
struct posix_clock {
struct posix_clock_operations ops;
struct cdev cdev;
struct kref kref;
struct mutex mutex;
bool zombie;
void (*release)(struct posix_clock *clk);
};

/**
* posix_clock_register() - register a new clock
* @clk: Pointer to the clock. Caller must provide 'ops' and 'release'
* @devid: Allocated device id
*
* A clock driver calls this function to register itself with the
* clock device subsystem. If 'clk' points to dynamically allocated
* memory, then the caller must provide a 'release' function to free
* that memory.
*
* Returns zero on success, non-zero otherwise.
*/
int posix_clock_register(struct posix_clock *clk, dev_t devid);

/**
* posix_clock_unregister() - unregister a clock
* @clk: Clock instance previously registered via posix_clock_register()
*
* A clock driver calls this function to remove itself from the clock
* device subsystem. The posix_clock itself will remain (in an
* inactive state) until its reference count drops to zero, at which
* point it will be deallocated with its 'release' method.
*/
void posix_clock_unregister(struct posix_clock *clk);

#endif
6 changes: 5 additions & 1 deletion include/linux/posix-timers.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ struct cpu_timer_list {
#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
Expand All @@ -48,6 +48,9 @@ struct cpu_timer_list {
#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 */
Expand Down Expand Up @@ -100,6 +103,7 @@ struct k_clock {
};

extern struct k_clock clock_posix_cpu;
extern struct k_clock clock_posix_dynamic;

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

Expand Down
4 changes: 3 additions & 1 deletion kernel/posix-timers.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
#include <linux/init.h>
#include <linux/compiler.h>
#include <linux/idr.h>
#include <linux/posix-clock.h>
#include <linux/posix-timers.h>
#include <linux/syscalls.h>
#include <linux/wait.h>
Expand Down Expand Up @@ -489,7 +490,8 @@ static void release_posix_timer(struct k_itimer *tmr, int it_id_set)
static struct k_clock *clockid_to_kclock(const clockid_t id)
{
if (id < 0)
return (id & CLOCKFD_MASK) == CLOCKFD ? NULL : &clock_posix_cpu;
return (id & CLOCKFD_MASK) == CLOCKFD ?
&clock_posix_dynamic : &clock_posix_cpu;

if (id >= MAX_CLOCKS || !posix_clocks[id].clock_getres)
return NULL;
Expand Down
3 changes: 2 additions & 1 deletion kernel/time/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o timecompare.o timeconv.o
obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o timecompare.o
obj-y += timeconv.o posix-clock.o

obj-$(CONFIG_GENERIC_CLOCKEVENTS_BUILD) += clockevents.o
obj-$(CONFIG_GENERIC_CLOCKEVENTS) += tick-common.o
Expand Down
Loading

0 comments on commit 0606f42

Please sign in to comment.