From owner-freebsd-arch Wed Jan 17 11:59:26 2001 Delivered-To: freebsd-arch@freebsd.org Received: from earth.backplane.com (placeholder-dcat-1076843399.broadbandoffice.net [64.47.83.135]) by hub.freebsd.org (Postfix) with ESMTP id F268D37B6A5 for ; Wed, 17 Jan 2001 11:59:02 -0800 (PST) Received: (from dillon@localhost) by earth.backplane.com (8.11.1/8.9.3) id f0HJwv649221; Wed, 17 Jan 2001 11:58:57 -0800 (PST) (envelope-from dillon) Date: Wed, 17 Jan 2001 11:58:57 -0800 (PST) From: Matt Dillon Message-Id: <200101171958.f0HJwv649221@earth.backplane.com> To: Alfred Perlstein Cc: arch@FreeBSD.ORG Subject: Re: HEADS-UP: await/asleep removal imminent References: <200101171138.MAA11834@freebsd.dk> <20010117092109.O7240@fw.wintelcom.net> <20010117100516.Q7240@fw.wintelcom.net> <200101171907.f0HJ7Qe48680@earth.backplane.com> <20010117112850.X7240@fw.wintelcom.net> Sender: owner-freebsd-arch@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.ORG :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