Comment 15 for bug 1258655

Revision history for this message
Seth Forshee (sforshee) wrote :

I've been poking at this a bit today, and I think it comes down to a race between powerd and the kernel's earlysuspend code. Here's the sequence of events I see in the logs for one case (there may also be other sequences that are problematic).

1. The initial state is that the screen is on. The power button is pressed.
2. powerd receives the button press, turns off the display, and releases its internal active state request.
3. powerd determines that suspend is possible and writes "mem" to /sys/power/state. The kernel schedules the earlysuspend work on an internal workqueue and the write call returns back to powerd.
4. The kernel starts processing the earlysuspend work.
5. Before the kernel earlysuspend work is complete, powerd receives another button press.
6. powerd looks to see whether it's safe to turn on the screen. At this point earlysuspend hasn't completed to the point where it's signaling that the framebuffer is asleep, so powerd determines that it is safe to turn on the display.
7. Unity tries to turn on the display, but the display device is in some partially or fully suspended state so something goes wrong.
8. Early suspend finishes and the fb state is updated, making powerd aware that the framebuffer is asleep.
8. Somewhere in this time frame powerd will also writes "on" to /sys/power/state to disable autosuspend. The kernel queues late resume work, but if early suspend has started then it must complete before late reusme runs and brings the framebuffer back to the awake state.

I'm not sure yet what the solution is. We can't simply synchronize the display state on wait_for_fb_* because it's at least theoretically possible to write "mem" then "on" to /sys/power/state quickly enough that early suspend never runs, and also because turning off the display doesn't necessarily imply enabling early suspend. One possible solution would be to make powerd's main thread block until the wait_for_fb_* status changes after writing to /sys/power/state for the earlysuspend implementation, but that would need to be done carefully to ensure that it wouldn't block indefinitely if something went wrong.