Skip to content

Commit

Permalink
posix clocks: Replace mutex with reader/writer semaphore
Browse files Browse the repository at this point in the history
A dynamic posix clock is protected from asynchronous removal by a mutex.
However, using a mutex has the unwanted effect that a long running clock
operation in one process will unnecessarily block other processes.

For example, one process might call read() to get an external time stamp
coming in at one pulse per second. A second process calling clock_gettime
would have to wait for almost a whole second.

This patch fixes the issue by using a reader/writer semaphore instead of
a mutex.

Signed-off-by: Richard Cochran <richard.cochran@omicron.at>
Cc: John Stultz <john.stultz@linaro.org>
Link: http://lkml.kernel.org/r/%3C20110330132421.GA31771%40riccoc20.at.omicron.at%3E
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
  • Loading branch information
Richard Cochran authored and Thomas Gleixner committed Apr 18, 2011
1 parent a1b49cb commit 1791f88
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 17 deletions.
5 changes: 3 additions & 2 deletions include/linux/posix-clock.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <linux/fs.h>
#include <linux/poll.h>
#include <linux/posix-timers.h>
#include <linux/rwsem.h>

struct posix_clock;

Expand Down Expand Up @@ -104,7 +105,7 @@ struct posix_clock_operations {
* @ops: Functional interface to the clock
* @cdev: Character device instance for this clock
* @kref: Reference count.
* @mutex: Protects the 'zombie' field from concurrent access.
* @rwsem: 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.
Expand All @@ -117,7 +118,7 @@ struct posix_clock {
struct posix_clock_operations ops;
struct cdev cdev;
struct kref kref;
struct mutex mutex;
struct rw_semaphore rwsem;
bool zombie;
void (*release)(struct posix_clock *clk);
};
Expand Down
24 changes: 9 additions & 15 deletions kernel/time/posix-clock.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
*/
#include <linux/device.h>
#include <linux/file.h>
#include <linux/mutex.h>
#include <linux/posix-clock.h>
#include <linux/slab.h>
#include <linux/syscalls.h>
Expand All @@ -34,19 +33,19 @@ static struct posix_clock *get_posix_clock(struct file *fp)
{
struct posix_clock *clk = fp->private_data;

mutex_lock(&clk->mutex);
down_read(&clk->rwsem);

if (!clk->zombie)
return clk;

mutex_unlock(&clk->mutex);
up_read(&clk->rwsem);

return NULL;
}

static void put_posix_clock(struct posix_clock *clk)
{
mutex_unlock(&clk->mutex);
up_read(&clk->rwsem);
}

static ssize_t posix_clock_read(struct file *fp, char __user *buf,
Expand Down Expand Up @@ -156,7 +155,7 @@ static int posix_clock_open(struct inode *inode, struct file *fp)
struct posix_clock *clk =
container_of(inode->i_cdev, struct posix_clock, cdev);

mutex_lock(&clk->mutex);
down_read(&clk->rwsem);

if (clk->zombie) {
err = -ENODEV;
Expand All @@ -172,7 +171,7 @@ static int posix_clock_open(struct inode *inode, struct file *fp)
fp->private_data = clk;
}
out:
mutex_unlock(&clk->mutex);
up_read(&clk->rwsem);
return err;
}

Expand Down Expand Up @@ -211,25 +210,20 @@ int posix_clock_register(struct posix_clock *clk, dev_t devid)
int err;

kref_init(&clk->kref);
mutex_init(&clk->mutex);
init_rwsem(&clk->rwsem);

cdev_init(&clk->cdev, &posix_clock_file_operations);
clk->cdev.owner = clk->ops.owner;
err = cdev_add(&clk->cdev, devid, 1);
if (err)
goto no_cdev;

return err;
no_cdev:
mutex_destroy(&clk->mutex);
return err;
}
EXPORT_SYMBOL_GPL(posix_clock_register);

static void delete_clock(struct kref *kref)
{
struct posix_clock *clk = container_of(kref, struct posix_clock, kref);
mutex_destroy(&clk->mutex);

if (clk->release)
clk->release(clk);
}
Expand All @@ -238,9 +232,9 @@ void posix_clock_unregister(struct posix_clock *clk)
{
cdev_del(&clk->cdev);

mutex_lock(&clk->mutex);
down_write(&clk->rwsem);
clk->zombie = true;
mutex_unlock(&clk->mutex);
up_write(&clk->rwsem);

kref_put(&clk->kref, delete_clock);
}
Expand Down

0 comments on commit 1791f88

Please sign in to comment.