Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 17 Jan 2001 11:58:57 -0800 (PST)
From:      Matt Dillon <dillon@earth.backplane.com>
To:        Alfred Perlstein <bright@wintelcom.net>
Cc:        arch@FreeBSD.ORG
Subject:   Re: HEADS-UP: await/asleep removal imminent
Message-ID:  <200101171958.f0HJwv649221@earth.backplane.com>
References:  <200101171138.MAA11834@freebsd.dk> <ybug0iixiee.fsf@jesup.eng.tvol.net.jesup.eng.tvol.net> <20010117092109.O7240@fw.wintelcom.net> <20010117100516.Q7240@fw.wintelcom.net> <200101171907.f0HJ7Qe48680@earth.backplane.com> <20010117112850.X7240@fw.wintelcom.net>

next in thread | previous in thread | raw e-mail | index | archive | help

:This is confusing:
:
:> 
:>     Revamp asleep/await to be based on state variables rather then 
:>     tsleep's traditionaln 'fake' addresses.  Rather then
:>     have a traditional sleep/wakeup we instead have a state variable that
:>     asleep/await operate on.  For example lets say we have a memory allocator.
:>     When the memory allocator finds it would block, it utilizes a global
:>     state structure representing the blockage and clears the state
:>     (blah.state = 0;).  Then it calls asleep(&blah).  asleep simply stores 
:>     the pointer to &blah in the process structure, it does not try to queue
:>     it or do anything else.  Thus no locking or mutexes or interrupt
:>     disablement is required *at all*.  The routine is entirely passive and
:>     safe to call from anywhere.
:
:It's not queued _anywhere_?

    Right.  Not queued anywhere... the await() (or tsleep or whatever)
    code would check for the existance of the pointer in the proc
    structure at the time the process tries to go to sleep.

    This is why you need a condition variable... because there is no
    way for an asynchronous event to 'wakeup' the process before it has
    tried to go to sleep for real the process needs some way to detect
    that the event has occured, hence the necessity of a condition
    variable.  

    The traditional tsleep/wakeup code has *NO* persistent state associated
    with it, which means the process is required to place itself on the
    sleep queue atomically in order to avoid the event occuring between the
    resource allocation failure (or whatever) and the tsleep() call.

:>     to go to sleep for real.  await() checks p_state->state and if it
:>     is zero await() places the process on the sleep queue for real and actually
:>     goes to sleep.  If p_state->state is non-zero, await() simply clears
:>     the pointer (proc->p_state = NULL;) and returns (without sleeping).
:
:This is a bit weird, basically await doesn't enqueue the process, so
:there's a weird race going on such that all "freeing" need to signal
:rather than just when the pool is exhausted, in fact the pool may not be
:exhausted but you still block because no one signal's after you await.

    await() in its current form doesn't enqueue the process because asleep()
    has already done it (in order for async events to be able to dequeue
    the process which turns the later await() into a NOP).  That's the
    current state of the code... but the problem here is that in order
    for await() to enqueue the process await() needs to grab a mutex,
    which is expensive and nasty.

    So my proposal is to use a condition variable that holds the state of
    whether something will block or not persistently and have asleep() just
    store a reference to the condition variable.  asleep() would NOT
    enqueue anything.  await() would be responsible for checking the
    status of the condition variable and queueing the process to the 
    appropriate sleep queue if the condition variable is zero.  The exact
    reverse of the original implementation resulting in huge benefits
    in efficiency.

    If you think about it, it makes sense... you don't have to enqueue 
    anything until you actually try to go to sleep for real (await()).
    The condition variable itself does not need to know that a process
    has asleep()'d on it until that process actually tries to await().

    (though for safety you might want to have a simple ref count to
    track it.  But it isn't required for the algorithm to work).

						-Matt

:>     I believe that this conforms to the state of the SMP system much much
:>     better then my original asleep()/await() implementation, and has the
:>     advantage of extremely *LOW* overhead (virtually none in many cases).
:> 
:>     You could then use it to give the 'power of blocking' to the caller 
:>     rather then the callee.  This in turn gives you much greater flexibility
:>     in regards to who can hold mutexes when and who can hold mutexes through
:>     procedure calls to other subsystems.
:
:Jason Evans just added his conditional variables, you could change
:asleep/await into cv_attach/cv_await or something, that would give
:you less contention on the sleep/run queues, but you'd still need
:a spinlock or mutex on these variables.
:
:-- 
:-Alfred Perlstein - [bright@wintelcom.net|alfred@freebsd.org]
:"I have the heart of a child; I keep it in a jar on my desk."



To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-arch" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200101171958.f0HJwv649221>