lkml.org 
[lkml]   [2008]   [Jul]   [21]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Subject[RFC] schedule_timeout_range()
    From
    Date
    Along the same lines as the previous patch, this provides
    schedule_timeout_range() for when the precise moment of wakeup doesn't
    matter (and isn't worth wasting power on), but any time the CPU happens
    to be awake within a given range of time is fine.

    Implement schedule_timeout() using it, and likewise for the _killable,
    _interruptible and _uninterruptible variants.

    Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
    ---
    include/linux/sched.h | 16 +++++--
    kernel/timer.c | 127 +++++++++++++++++++++++++++++++------------------
    2 files changed, 93 insertions(+), 50 deletions(-)

    diff --git a/include/linux/sched.h b/include/linux/sched.h
    index 1941d8b..5e9f5a9 100644
    --- a/include/linux/sched.h
    +++ b/include/linux/sched.h
    @@ -325,12 +325,20 @@ extern char __sched_text_start[], __sched_text_end[];
    extern int in_sched_functions(unsigned long addr);

    #define MAX_SCHEDULE_TIMEOUT LONG_MAX
    -extern signed long schedule_timeout(signed long timeout);
    -extern signed long schedule_timeout_interruptible(signed long timeout);
    -extern signed long schedule_timeout_killable(signed long timeout);
    -extern signed long schedule_timeout_uninterruptible(signed long timeout);
    +extern long schedule_timeout_range(long timeout, long deadline);
    +extern long schedule_timeout_range_interruptible(long timeout, long deadline);
    +extern long schedule_timeout_range_killable(long timeout, long deadline);
    +extern long schedule_timeout_range_uninterruptible(long timeout, long deadline);
    asmlinkage void schedule(void);

    +#define schedule_timeout(_t) schedule_timeout_range((_t), (_t))
    +#define schedule_timeout_interruptible(_t) \
    + schedule_timeout_range_interruptible((_t), (_t))
    +#define schedule_timeout_killable(_t) \
    + schedule_timeout_range_killable((_t), (_t))
    +#define schedule_timeout_uninterruptible(_t) \
    + schedule_timeout_range_uninterruptible((_t), (_t))
    +
    struct nsproxy;
    struct user_namespace;

    diff --git a/kernel/timer.c b/kernel/timer.c
    index e114f08..dd43c34 100644
    --- a/kernel/timer.c
    +++ b/kernel/timer.c
    @@ -1144,11 +1144,12 @@ static void process_timeout(unsigned long __data)
    }

    /**
    - * schedule_timeout - sleep until timeout
    - * @timeout: timeout value in jiffies
    + * schedule_timeout_range - sleep until timeout
    + * @timeout: timeout value in jiffies, deferrable
    + * @deadline: hard deadline for timeout
    *
    - * Make the current task sleep until @timeout jiffies have
    - * elapsed. The routine will return immediately unless
    + * Make the current task sleep for a length of time between @timeout
    + * and @deadline jiffies. The routine will return immediately unless
    * the current task state has been set (see set_current_state()).
    *
    * You can set the task state as follows -
    @@ -1169,81 +1170,115 @@ static void process_timeout(unsigned long __data)
    *
    * In all cases the return value is guaranteed to be non-negative.
    */
    -signed long __sched schedule_timeout(signed long timeout)
    +signed long __sched schedule_timeout_range(signed long timeout,
    + signed long deadline)
    {
    struct timer_list timer;
    + struct timer_list timer2;
    unsigned long expire;
    + unsigned long expire2;

    - switch (timeout)
    - {
    - case MAX_SCHEDULE_TIMEOUT:
    - /*
    - * These two special cases are useful to be comfortable
    - * in the caller. Nothing more. We could take
    - * MAX_SCHEDULE_TIMEOUT from one of the negative value
    - * but I' d like to return a valid offset (>=0) to allow
    - * the caller to do everything it want with the retval.
    - */
    + /*
    + * This special case is useful to be comfortable
    + * in the caller. Nothing more. We could take
    + * MAX_SCHEDULE_TIMEOUT from one of the negative value
    + * but I'd like to return a valid offset (>=0) to allow
    + * the caller to do everything it want with the retval.
    + */
    + if (timeout == MAX_SCHEDULE_TIMEOUT &&
    + deadline == MAX_SCHEDULE_TIMEOUT) {
    schedule();
    goto out;
    - default:
    - /*
    - * Another bit of PARANOID. Note that the retval will be
    - * 0 since no piece of kernel is supposed to do a check
    - * for a negative retval of schedule_timeout() (since it
    - * should never happens anyway). You just have the printk()
    - * that will tell you if something is gone wrong and where.
    - */
    - if (timeout < 0) {
    - printk(KERN_ERR "schedule_timeout: wrong timeout "
    - "value %lx\n", timeout);
    - dump_stack();
    - current->state = TASK_RUNNING;
    - goto out;
    - }
    + }
    + /*
    + * Another bit of PARANOIA. Note that the retval will be
    + * 0 since no piece of kernel is supposed to do a check
    + * for a negative retval of schedule_timeout() (since it
    + * should never happens anyway). You just have the printk()
    + * that will tell you if something is gone wrong and where.
    + */
    + if (unlikely(timeout < 0)) {
    + printk(KERN_ERR "schedule_timeout: wrong timeout "
    + "value %lx\n", timeout);
    + dump_stack();
    + current->state = TASK_RUNNING;
    + goto out;
    + }
    + if (unlikely(deadline < 0)) {
    + printk(KERN_ERR "schedule_timeout: wrong deadline "
    + "value %lx\n", deadline);
    + dump_stack();
    + current->state = TASK_RUNNING;
    + goto out;
    + }
    + if (unlikely(timeout > deadline)) {
    + printk(KERN_ERR "schedule_timeout: deadline %lx earlier "
    + "than initial timeout %lx\n", deadline, timeout);
    + timeout = deadline;
    }

    expire = timeout + jiffies;
    + expire2 = expire + deadline - timeout;
    +
    + /* Don't bother to set up the deferrable timer if the deadline
    + is at the same time */
    + if (timeout != deadline) {
    + setup_timer_on_stack(&timer, process_timeout,
    + (unsigned long)current);
    + timer_set_deferrable(&timer);
    + __mod_timer(&timer, expire);
    + }
    + /* And don't bother with the deadline if it's infinite */
    + if (deadline != MAX_SCHEDULE_TIMEOUT) {
    + setup_timer_on_stack(&timer2, process_timeout,
    + (unsigned long)current);
    + __mod_timer(&timer, expire2);
    + }

    - setup_timer_on_stack(&timer, process_timeout, (unsigned long)current);
    - __mod_timer(&timer, expire);
    schedule();
    - del_singleshot_timer_sync(&timer);
    -
    - /* Remove the timer from the object tracker */
    - destroy_timer_on_stack(&timer);
    + if (timeout != deadline) {
    + del_singleshot_timer_sync(&timer);
    + destroy_timer_on_stack(&timer);
    + }
    + if (deadline != MAX_SCHEDULE_TIMEOUT) {
    + del_singleshot_timer_sync(&timer2);
    + destroy_timer_on_stack(&timer2);
    + }

    timeout = expire - jiffies;

    out:
    return timeout < 0 ? 0 : timeout;
    }
    -EXPORT_SYMBOL(schedule_timeout);
    +EXPORT_SYMBOL(schedule_timeout_range);

    /*
    * We can use __set_current_state() here because schedule_timeout() calls
    * schedule() unconditionally.
    */
    -signed long __sched schedule_timeout_interruptible(signed long timeout)
    +signed long __sched schedule_timeout_range_interruptible(signed long timeout,
    + signed long deadline)
    {
    __set_current_state(TASK_INTERRUPTIBLE);
    - return schedule_timeout(timeout);
    + return schedule_timeout_range(timeout, deadline);
    }
    -EXPORT_SYMBOL(schedule_timeout_interruptible);
    +EXPORT_SYMBOL(schedule_timeout_range_interruptible);

    -signed long __sched schedule_timeout_killable(signed long timeout)
    +signed long __sched schedule_timeout_range_killable(signed long timeout,
    + signed long deadline)
    {
    __set_current_state(TASK_KILLABLE);
    - return schedule_timeout(timeout);
    + return schedule_timeout_range(timeout, deadline);
    }
    -EXPORT_SYMBOL(schedule_timeout_killable);
    +EXPORT_SYMBOL(schedule_timeout_range_killable);

    -signed long __sched schedule_timeout_uninterruptible(signed long timeout)
    +signed long __sched schedule_timeout_range_uninterruptible(signed long timeout,
    + signed long deadline)
    {
    __set_current_state(TASK_UNINTERRUPTIBLE);
    - return schedule_timeout(timeout);
    + return schedule_timeout_range(timeout, deadline);
    }
    -EXPORT_SYMBOL(schedule_timeout_uninterruptible);
    +EXPORT_SYMBOL(schedule_timeout_range_uninterruptible);

    /* Thread ID - the internal kernel "pid" */
    asmlinkage long sys_gettid(void)
    --
    1.5.5.1


    --
    David Woodhouse Open Source Technology Centre
    David.Woodhouse@intel.com Intel Corporation




    \
     
     \ /
      Last update: 2008-07-22 05:09    [W:0.046 / U:31.696 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site