From: Randy Dunlap <randy.dunlap@oracle.com>
To: Hillf Danton <dhillf@gmail.com>
Cc: linux-kernel@vger.kernel.org
Subject: Re: [PATCH v0] add nano semaphore in kernel
Date: Mon, 27 Dec 2010 12:08:21 -0800 [thread overview]
Message-ID: <20101227120821.51f8a554.randy.dunlap@oracle.com> (raw)
In-Reply-To: <AANLkTim0Xmsnzz5yMLAx_+w-c7sSSReu0SKMAmjpbS+1@mail.gmail.com>
On Sun, 26 Dec 2010 13:13:42 +0800 Hillf Danton wrote:
> Based upon high resolution timer and idea borrowed from semaphore,
> nano semaphore is created.
>
> Nano semaphore provides finer time resolution depending on system
> configuration and capabilities.
>
> Nano semaphore is not to replace semaphore, but used in application
> environments where nano seconds are required.
>
> Three methods, nano_semaphore_try_down, nano_semaphore_down and
> nano_semaphore_up are implemented in a header file, and there is no
> corresponding C file since nano semaphore is not complex.
>
> Signed-off-by: Hillf Danton <dhillf@gmail.com>
> ---
>
> --- a/include/linux/nano_semaphore.h 1970-01-01 08:00:00.000000000 +0800
> +++ b/include/linux/nano_semaphore.h 2010-12-26 12:38:36.000000000 +0800
> @@ -0,0 +1,263 @@
> +/*
> + * linux/nano_semaphore.h
> + *
> + * Definition and implementation of nano semaphore
> + *
> + * Nano semaphore provides finer time resolution depending on system
> + * configuration and capabilities.
> + *
> + * Nano semaphore could be used in parallel with semaphore.
> + *
> + * Started-by: Hillf Danton
> + *
> + * Credits:
> + * ideas are borrowed from semaphore and high resolution timer
> + *
> + * Distributed under the terms of GPL v2
> + */
> +
> +#ifndef __NANO_SEMAPHORE_H_
> +#define __NANO_SEMAPHORE_H_
> +
> +#include <linux/list.h>
> +#include <linux/spinlock.h>
> +#include <linux/ktime.h>
> +#include <linux/sched.h>
> +#include <linux/hrtimer.h>
> +
> +/* must be initialized before use */
> +struct nano_semaphore {
> + struct list_head chair;
> + struct task_struct *holder;
> + spinlock_t lock;
> +};
> +
> +#define NANO_SEMAPHORE_INITIALIZER(name) \
> +{ \
> + .chair = LIST_HEAD_INIT((name).chair), \
> + .holder = NULL, \
> + .lock = __SPIN_LOCK_UNLOCKED((name).lock), \
> +}
> +
> +
> +#define DEFINE_NANO_SEMAPHORE(name) \
> + struct nano_semaphore name = NANO_SEMAPHORE_INITIALIZER(name)
> +
> +
> +static inline void nano_semaphore_init(struct nano_semaphore *s)
> +{
> + INIT_LIST_HEAD(&s->chair);
> + s->holder = NULL;
> + spin_lock_init(&s->lock);
> +}
> +
> +/*
> + * Helper functions about nano semaphore
> + */
> +
> +/*
> + * Helper function to check, whether anyone is waiting the nano semaphore
> + *
> + * Called with lock hold
with lock held
(change this in many places)
> + */
> +static inline int nano_semaphore_waiter_pending(struct nano_semaphore *s)
> +{
> + return !list_empty(&s->chair);
> +}
> +
> +/*
> + * Helper function to check, whether the nano semaphore is not hold by anyone
> + *
> + * Called with lock hold
> + */
> +static inline int nano_semaphore_holder_empty(struct nano_semaphore *s)
> +{
> + return !s->holder;
> +}
> +
> +/*
> + * Helper function to check, whether `task' is the holder of nano semaphore
> + *
> + * Called with lock hold
> + */
> +static inline int
> +nano_semaphore_holder_match(struct nano_semaphore *s, struct task_struct *task)
> +{
> + return s->holder == task;
> +}
> +
> +/*
> + * Helper function to set `task' to be the holder of nano semaphore
> + *
> + * Called with lock hold
> + */
> +static inline void
> +nano_semaphore_set_holder(struct nano_semaphore *s, struct task_struct *task)
> +{
> + s->holder = task;
> +}
> +
> +/*
> + * Helper function try to acquire the nano semaphore
> + *
> + * Returns 1 if acquired successfully, 0 otherwise.
> + *
> + * Called with lock hold
> + */
> +static inline int __nano_semaphore_try_down(struct nano_semaphore *s)
> +{
> + int ret;
> +
> + ret = !nano_semaphore_waiter_pending(s) &&
> + nano_semaphore_holder_empty(s);
> + if (ret)
> + nano_semaphore_set_holder(s, current);
> +
> + return ret;
> +}
Several of the functions above could easily be modified to use kernel-doc
notation for their documentation comments... please.
> +
> +/*
Please use
/**
here so that the kernel-doc can be used/expanded.
> + * nano_semaphore_try_down - try to acquire the nano semaphore without waiting
> + * @s: the nano semaphore to be acquired
> + *
> + * Returns 1 if acquired successfully, 0 otherwise.
> + */
> +static inline int nano_semaphore_try_down(struct nano_semaphore *s)
> +{
> + unsigned long flags;
> + int ret;
> +
> + spin_lock_irqsave(&s->lock, flags);
> + ret = __nano_semaphore_try_down(s);
> + spin_unlock_irqrestore(&s->lock, flags);
> +
> + return ret;
> +}
> +
> +
> +/* only for internal use by nano semaphore */
> +struct nano_semaphore_waiter {
> + struct list_head node;
> + struct task_struct *task;
> +};
> +
> +/*
> + * Helper function to init a waiter with `task'
> + */
> +static inline void nano_semaphore_waiter_init(struct nano_semaphore_waiter *w,
> + struct task_struct *task)
> +{
> + INIT_LIST_HEAD(&w->node);
> + w->task = task;
> +}
> +
> +/*
> + * Helper function to get the first pending waiter of nano semaphore
> + *
> + * Called with lock hold
> + */
> +struct inline struct nano_semaphore_waiter *
> +nano_semaphore_get_waiter(struct nano_semaphore *s)
> +{
> + if (nano_semaphore_waiter_pending(s))
> + return list_first_entry(&s->chair,
> + struct nano_semaphore_waiter, node);
> + return NULL;
> +}
> +
> +/*
> + * Helper function to sleep a while
> + *
> + * Called with lock not hold
> + */
> +static inline int nano_semaphore_sleep(unsigned long nano_secs)
> +{
> + int ret;
> +
> + if (nano_secs) {
> + ktime_t ktime = ktime_set(0, nano_secs);
> +
> + ret = schedule_hrtimeout(&ktime, HRTIMER_MODE_REL);
> + } else
> + ret = schedule_hrtimeout(NULL, HRTIMER_MODE_REL);
> +
> + return ret;
> +}
> +
> +/*
/**
> + * nano_semaphore_down - acquire the nano semaphore
> + * @s: the nano semaphore to be acquired
> + * @nano_secs: the nano seconds to wait if necessary,
> + * could be zero if want to wait as long as possible.
> + *
> + * Returns >0 if acquired successfully, <=0 otherwise.
> + *
> + * Note unlike down() in semaphore, nano_semaphore_down is not looping until
> + * the nano semaphore is hold, but simply reports the result. And the callers
is held,
> + * could, if they like, loop in simple manner, for instance,
> + * while (1 != nano_semaphore_down(s, 800));
> + * do_home_work();
> + * nano_semaphore_up(s);
> + *
> + */
> +static inline int
> +nano_semaphore_down(struct nano_semaphore *s, unsigned long nano_secs)
> +{
> + unsigned long flags;
> + int ret;
> + struct nano_semaphore_waiter w;
> +
> + spin_lock_irqsave(&s->lock, flags);
> +
> + ret = __nano_semaphore_try_down(s);
> + if (ret)
> + goto out;
> +
> + nano_semaphore_waiter_init(&w, current);
> +
> + __set_task_state(current, TASK_INTERRUPTIBLE);
> +
> + list_add_tail(&w.node, &s->chair);
> +
> + spin_unlock_irqrestore(&s->lock, flags);
> + ret = nano_semaphore_sleep(nano_secs);
> + spin_lock_irqsave(&s->lock, flags);
> +
> + list_del(&w.node);
> +
> + if (nano_semaphore_holder_match(s, current))
> + ret = 1;
> + out:
> + spin_unlock_irqrestore(&s->lock, flags);
> +
> + return ret;
> +}
> +
> +/**
> + * nano_semaphore_up - release the nano semaphore
> + * @s: the nano semaphore to release
> + *
> + * Note nano_semaphore_up() could be called even by tasks which have never
> + * called nano_semaphore_down(), but the tricky is not recommended.
s/tricky/trick/
> + */
> +static inline void nano_semaphore_up(struct nano_semaphore *s)
> +{
> + struct nano_semaphore_waiter *w;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&s->lock, flags);
> +
> + if (! nano_semaphore_holder_match(s, current))
> + goto out;
> +
> + w = nano_semaphore_get_waiter(s);
> + if (w) {
> + nano_semaphore_set_holder(s, w->task);
> + wake_up_process(w->task);
> + } else
> + nano_semaphore_set_holder(s, NULL);
> + out:
> + spin_unlock_irqrestore(&s->lock, flags);
> +}
> +
> +#endif /* __NANO_SEMAPHORE_H_ */
> --
---
~Randy
*** Remember to use Documentation/SubmitChecklist when testing your code ***
desserts: http://www.xenotime.net/linux/recipes/
next prev parent reply other threads:[~2010-12-27 20:09 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-12-26 5:13 Hillf Danton
2010-12-26 6:46 ` Rakib Mullick
2010-12-26 7:04 ` Hillf Danton
2010-12-26 9:08 ` Rakib Mullick
2010-12-26 12:05 ` Hillf Danton
2010-12-26 12:56 ` Rakib Mullick
2010-12-27 14:04 ` Hillf Danton
2010-12-27 20:08 ` Randy Dunlap [this message]
2010-12-29 14:57 ` Hillf Danton
2010-12-27 21:15 ` Arnd Bergmann
2010-12-28 13:13 ` Hillf Danton
2010-12-28 15:51 ` Daniel Walker
2010-12-29 11:47 ` Arnd Bergmann
2010-12-29 14:42 ` Hillf Danton
2010-12-29 14:58 ` Daniel Walker
2010-12-29 15:03 ` Hillf Danton
2010-12-29 19:16 ` Arnd Bergmann
2010-12-30 14:21 ` Hillf Danton
2010-12-30 15:56 ` Arnd Bergmann
2011-01-04 14:03 ` Pavel Machek
2011-01-04 14:18 ` Hillf Danton
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20101227120821.51f8a554.randy.dunlap@oracle.com \
--to=randy.dunlap@oracle.com \
--cc=dhillf@gmail.com \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Powered by JetHome