Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 4 Jun 2004 14:27:52 -0700 (PDT)
From:      Nate Lawson <nate@root.org>
To:        John Baldwin <jhb@FreeBSD.org>
Cc:        freebsd-current@FreeBSD.org
Subject:   Re: reboot or shutdown not working with -current
Message-ID:  <20040604135848.K52586@root.org>
In-Reply-To: <200406041646.23134.jhb@FreeBSD.org>
References:  <714DBA6C-B565-11D8-B32B-000393AB07D8@verizon.net> <200406041108.33170.jhb@FreeBSD.org> <20040604123934.D52021@root.org> <200406041646.23134.jhb@FreeBSD.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Fri, 4 Jun 2004, John Baldwin wrote:
> On Friday 04 June 2004 03:46 pm, Nate Lawson wrote:
> > My goal with this originally was to drain all threads out of the idle
> > handler before continuing the shutdown process.  The assumption that
> > changed with the ithread commit was that the idle thread gets to run
> > sometime after an interrupt occurs.  It's actually kind of tough to have
> > a sched switch before any instructions get to execute after the "go to
> > sleep" one since I profile the length of the sleep to figure out how deep
> > a sleep to use the next cycle.  This is to keep sporadically loaded
> > machines responsive.  So if a preemption can happen every sleep, I'll have
> > to redo this approach and go with one that doesn't require profiling and
> > executes no code after the sleep.
>
> I think your current code is fine though.  As soon as you send out the IPI,
> any CPUs that are idle will bounce.  Is there anything dangerous after you
> enable interrupts again on the processor?  For C1, you don't seem to go near
> any ACPI-specific code after resume, and for C2/C3 you seem to defer enabling
> interrupts until you have read the counters (and I assume that C2/C3 resume
> doesn't actually handle the interrupt until you do sti) so you shouldn't have
> to worry about the CPU doing the shutdown since if it ever returns to the
> idlethread it will already be out of the critical section.  Thus, I don't
> think you need the while loop or busy counter at all.

You're right about that.  I had forgotten only C1 automatically re-enables
interrupts.  For C2/C3, the IO port read merely returns and it's up to the
caller to re-enable interrupts.

After looking at the code again, the refcount was to protect accesses to
the softc->cpu_cx_states array.  I assumed that the softc cannot be
touched after device_shutdown returns 0 since the device and its softc
will be gone.  So a thread is sleeping and we IPI all processors and the
idle thread gets switched away from, it may get switched back to after
device_shutdown has complete and the softc is invalid memory.  Then the
array access at the bottom would be invalid.

Another complicating factor that hasn't gone in yet but is sitting in my
tree pending careful analysis is shared use of a single processor's P_LVLx
register.  This is for future machines that have only one P_BLK defined
but shared between multiple processors.  For those machines, only
acpi_cpu0 will have a valid sc->cpu_cx_states array and other processors
will all share it if their P_BLKs are null.  With the global refcount, my
goal was to prevent modifying any idle-related data in the softc (i.e.
re-evaluating registers in response to a notify on _CST) if any threads
are currently idle.  Instead, the appropriate response was to disable
entry to the idle function, evict all threads, make the mods, then
re-enable idle.  (This function in my local tree has been generalized to
acpi_cpu_evict and is used in more than device_shutdown.)  Since this is a
really rare event (i.e. when changing AC line status) but the idle thread
running is really common (every 10 us), using a mutex or sx lock is not as
good.

So I guess I still need a way to guarantee other threads are no longer in
the idle function after calling smp_rendezvous. Since smp_rendezvous
ensures that every CPU has "checked in" before returning, that gets me the
guarantee that device_shutdown won't return before every idle thread has
been awoken.  But that's still not good enough because when the idle
thread is resumed, it will continue after the sti instruction and
reference invalid data at the end of the function.  I'm thinking I can
add a check that idle has been disabled after the call to sleep but before
interrupts are enabled.  If disabled, return immediately and skip the
profiling step.  If the thread was woken via acpi_cpu_evict(), then idling
will always be disabled at this point and the thread will exit immediately
(and not re-enter) without accessing the softc.  If the thread woke up
normally, there's a harmless race.  1. If acpi_cpu_evict() has disabled
entry to idle but not called smp_rendezvous() yet, then the thread will
exit without recording stats.  2.  If acpi_cpu_evict() has not disabled
entry to idle, then it will continue executing the rest of the function
normally.  Hmm, I'll need to think about this a little.

The main goal is to do as little as possible after sleeping as this adds
latency to handling whatever thread is ready to run.  It's ok to do extra
work up front before going to sleep though since the system is idle
anyway.

-Nate



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