linux sleep implementation - Linux

This is a discussion on linux sleep implementation - Linux ; 1> sleeping in the kernel is like this (source taken from Robert Love Book, page 53) add_wait_queue(q, &wait); while (!condition) { set_current_state(TASK_INTERRUPTIBLE); if (signal_pending(current)) ............................... schedule(); } set_current_state(TASK_RUNNING); remove_wait_queue(q, &wait); Isn't it possible that just before the schedule is invoked, ...

+ Reply to Thread
Results 1 to 4 of 4

Thread: linux sleep implementation

  1. linux sleep implementation

    1> sleeping in the kernel is like this (source taken from Robert Love
    Book, page 53)

    add_wait_queue(q, &wait);
    while (!condition) {
    set_current_state(TASK_INTERRUPTIBLE);
    if (signal_pending(current))
    ...............................

    schedule();
    }
    set_current_state(TASK_RUNNING);
    remove_wait_queue(q, &wait);

    Isn't it possible that just before the schedule is invoked, the task is
    pre-empted. What if it is preempted because of the event that it
    intends to wait for occurs. Will it give weird result in that case ?

    2> What happens after the task in TASK_INTERRUPTIBLE state receives a
    signal and finshes with the associated handler. Does it go back to
    sleep again ?

    Thanks


  2. Re: linux sleep implementation

    Ask wrote:

    > 1> sleeping in the kernel is like this (source taken from Robert Love
    > Book, page 53)
    >
    > add_wait_queue(q, &wait);
    > while (!condition) {
    > set_current_state(TASK_INTERRUPTIBLE);
    > if (signal_pending(current))
    > ...............................
    >
    > schedule();
    > }
    > set_current_state(TASK_RUNNING);
    > remove_wait_queue(q, &wait);
    >
    > Isn't it possible that just before the schedule is invoked, the task is
    > pre-empted. What if it is preempted because of the event that it
    > intends to wait for occurs. Will it give weird result in that case ?


    It can be preempted. The effect is the same as if schedule was called.
    When the signal is delivered, the task changes back to TASK_RUNNING.

    I vaguely remember the above code to be a workaround to avoid a race
    condition when using a 2.4.x kernel. Newer kernels have a call which
    allows you to go to sleep and check your condition atomically.

    >
    > 2> What happens after the task in TASK_INTERRUPTIBLE state receives a
    > signal and finshes with the associated handler. Does it go back to
    > sleep again ?
    >


    No, it stays in TASK_RUNNING.

    Kind regards,

    Iwo


  3. Re: linux sleep implementation

    Iwo Mergler wrote:

    > I vaguely remember the above code to be a workaround to avoid a race
    > condition when using a 2.4.x kernel. Newer kernels have a call which
    > allows you to go to sleep and check your condition atomically.


    Well, from linux/wait.h :

    void wait_event(wait_queue_head_t waitqueue, condition);

    and

    int wait_event_interruptible (wait_queue_head_t wait_queue, condition);

    that's the state of the art...



    hth

    Marco

  4. Re: linux sleep implementation

    Ask wrote:
    > 1> sleeping in the kernel is like this (source taken from Robert Love
    > Book, page 53)
    >
    > add_wait_queue(q, &wait);
    > while (!condition) {
    > set_current_state(TASK_INTERRUPTIBLE);
    > if (signal_pending(current))
    > ...............................
    >
    > schedule();
    > }


    The above logic is outdated. It is correct only if the legacy "Big
    Kernel Lock" is being held, and if the event does not come from an
    interrupt source, only from another task.

    With other locks, you'd see an unlock around the schedule() call, but
    the BKL is handled automatically in the scheduler: that is, you can
    call schedule() with the BKL held and it will be released and
    re-acquired internally. The BKL kind of provides the appearance of
    cooperative multitasking, even though you may be on SMP and/or
    preemption.

    If the Big Kernel Lock is being held, then the exact order of the
    operations doesn't matter, thus it isn't an issue that the task is
    added to the queue first and then its state is changed. It's all atomic
    with respect to any other task holding the BKL.

    What does the book say about the exact assumptions?

    What kernel versions does it cover?

    > Isn't it possible that just before the schedule is invoked, the task is
    > pre-empted.


    Preemption is only possible in the kernel if CONFIG_PREEMPT is enabled.
    This might not have existed in the kernels covered by that book.

    Anyway, task doesn't have to be preempted to run something else,
    because another processor might be available to run it concurrently
    (CONFIG_SMP).

    What if the wake up is done by an interrupt? Under SMP, the interrupt
    could be handled on another CPU.

    > 2> What happens after the task in TASK_INTERRUPTIBLE state receives a
    > signal and finshes with the associated handler. Does it go back to
    > sleep again ?


    As you can see in the examples, bailing on a pending, non-blocked
    signal is done with an explicit check: if (signal_pending(current)) {
    /* bail with error code */ }. An error code is percolated all the way
    to the top and a return from the system call takes place. Control has
    to pass back to user space for the signal handler to be called. What
    happens then depends on whether the system call returned -EINTR or
    -ERESTARTSYS. A system call that returned -ERESTARTSYS is resumed by
    the kernel: actually just called again, basically. I think that
    userspace doesn't even see the ERESTARTSYS error result. So that would
    correspond with your "goes back to sleep" intuition. The other
    possibility is that user space sees the EINTR error, and causes the
    function to return -1, setting errno to EINTR.


+ Reply to Thread