Alan Stern wrote:
On Wed, 22 Sep 2004, David Brownell wrote:
The root cause of the self-deadlocks is that the driver model
code has to be re-entrant, so that logic in suspend/resume
paths can do things that can be done at other times too. That
means the locking mustn't be context-dependent, and the lock
scope must shrink to something sane (like, not held during
potentially long-lasting outcalls).
The context-dependency problems are solved by making the semaphore public,
not private to the PM core. If the core required callers to hold the
lock, and always invoked callbacks with the lock held, then there wouldn't
be any deadlock.
Yeech. Even if it were necessary -- which it is not! -- I say: Yeech.
Public locks are error prone, even in controlled environments; and
I seem to have noticed that Linux isn't particularly controlled!
The scope problem is something else. I'm saying that by increasing the
scope greatly, deadlock can be prevented. Of course this just worsens the
situation with regard to potentially long-lasting callbacks and such. In
fact it makes things as bad as possible: all operations are completely
serialized. That's why I didn't say this was the right thing to do -- I
only said it would prevent deadlock.
That's only part of what "worsens"! :)
I see what you mean about preventing deadlock, but then if every
driver is going to be lock-aware why not make the scopes _small_
so that those structural problems are minimized?
(In fact, it's the push-locking-outside step which is what solves
the reentrancy design issues. It wasn't clear to me from what
you said before that you had such a step.)
By the way, the PM lists aren't necessary. By using the existing list
pointers in the device structure it's possible to do a proper tree
traversal with bounded stack usage. I don't know if anyone's interested
in that...
I've had the same thought about bounded memory, but I don't think
they'd work well without separate PM lists. At least without
adding rude "whole system is serialized" constraints ...
I do want to add PMcore primitives to walk a (sub)tree in constant
stak space, so that USB can rely on that to ensure subtrees (as for
example USB hub to USB-storage to SCSI-Host to SCSI-Disk) can work
even when they jump out of the USB domain.
The existing PM data structures aren't quite up to the job. But if the
children of each parent were linked in a "siblings" list (which struct
device does include but struct dev_pm_info doesn't) it would be possible.
Yes. If pm_info had a list entry, normally empty, then it could
be used to flatten any subtree prior to something (USBcore, PMcore, etc)
walking the list and then removing the entries.
Here's the algorithm for the device tree (not the PM tree). Locking
optional... :-)
I was thinking of something different, something like
this for a prefix walk (as for resume):
walk_subtree(DEV, visitor)
list_head MYLIST = ..initialize me..;
grab flatten lock;
if dev->pm.list not empty
fail;
add DEV to MYLIST using pm.list
list_for_each ENTRY in MYLIST safely
list_for_each CHILD in ENTRY->children
if CHILD->pm.list not empty
fail
append CHILD to mylist using pm.list
drop flatten lock
// front-to-back walk for resume
// back-to-front walk for suspend
list_for_each ENTRY in MYLIST safely
visit(ENTRY)
delete from ENTRY->pm.list
VOILA!
Clearly those "fail" cases need attention; they could maybe
just wait_event. Little glitches: hey, did you notice
that the "PM Tree" is really a forest? Multiple roots.
One difference between that scheme and the one you sketched
is that the "fail" cases exist ... so that when two tasks
are concurrently working on subtrees, they get sequenced
properly. Yes, locktree() does that too... :)
- Dave
void walk_sub_tree(struct device *start_dev) {
struct device *d = start_dev;
for (;;) {
// Pre-order traversal tasks go here
if (!list_empty(d->children)) {
d = d->children.next;
continue;
}
up_one_level:
// Post-order traversal tasks go here
if (d == start_dev)
break;
if (d->parent == d->node.next) {
d = d->parent;
goto up_one_level;
}
d = d->node.next;
}
}
You might want to change the .next's to .prev's for the resume traversal,
to make it the reverse of the suspend traversal.
Alan Stern
-------------------------------------------------------
This SF.Net email is sponsored by: YOU BE THE JUDGE. Be one of 170
Project Admins to receive an Apple iPod Mini FREE for your judgement on
who ports your project to Linux PPC the best. Sponsored by IBM.
Deadline: Sept. 24. Go here: http://sf.net/ppc_contest.php
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel