Project

General

Profile

Bug #1605

System time changes combined with spurios wakeups cause DP_POLL to return prematurely

Added by Matt Amdur almost 8 years ago. Updated almost 8 years ago.

Status:
Resolved
Priority:
Normal
Assignee:
Category:
kernel
Start date:
2011-10-05
Due date:
% Done:

0%

Estimated time:
Difficulty:
Medium
Tags:
needs-triage

Description

The dvpoll argument of the DP_POLL ioctl includes a relative timeout in
milliseconds. According to the man page for poll.7d the ioctl should block until
events are ready for any of the file descriptors, the timeout expires, or
a signal is received. In cases where the system time changes, however, DP_POLL
may return prematurely (before the timeout has expired with no events ready).
When DP_POLL returns prematurely it looks to applications that the timeout has
expired. This has caused a number of problems for java applications using
java.nio.channels.Selector, which is implemented via DP_POLL and /dev/poll.

The problem is a result of dpioctl using cv_waituntil_sig to wait for events
to be ready or for a signal to be delivered. cv_waituntil_sig takes an
absolute timeout in the future and blocks until a signal is received, the
timeout expires, or it's woken up (aka events are ready). Since
cv_waituntil_sig takes an absolute timeout is has additional logic to handle
cases where the system time changes. In the event that time has changed it
returns -1, which callers interpret as the timeout expiring.

dpioctl interprets cv_waituntil_sig returning -1 as the specified timeout
expiring, it doesn't differentiate between the time changing and the actual
timeout expiring. This in turn causes the premature return from DP_POLL to the caller.
In the common case we don't see this problem, the system time changing doesn't
cause threads blocked in cv_waituntil_sig to wakeup. In order to trigger this
something needs to wake up the blocked thread after the time has been changed.
We typically see this happen as a result of the process forking from a
different thread, which causes all of the threads block in cv_waituntil_sig to
wakeup. The dpioctl logic correctly detects this as a spurious wakeup (aka no
events were ready) and calls back to cv_waituntil_sig, but as a result of the
timechanged variable being incremented cv_waituntil_sig immediately returns
-1.

I've written a simple test program in C that triggers the behavior, I'll
attach it to the bug. I've tested a fix for the issue that changes dpioctl to
use a wrapper around cv_relwait_sig rather then cv_waituntil_sig.
cv_relwait_sig expects a relative timeout rather then an absolute timeout, so
we avoid the problems associated with time changing.


Files

devpoll_test.c (9.44 KB) devpoll_test.c Matt Amdur, 2011-10-05 07:21 PM

History

#1

Updated by Matt Amdur almost 8 years ago

While testing the fix I noticed the same issue exists for poll_common (which implements poll/select/pselect). I've generalized the fix to cover both cases and I've tested the fixes locally.

#2

Updated by Gordon Ross almost 8 years ago

There's one more now, in here:
$SRC/uts/common/io/ksocket/ksocket.c

#3

Updated by Matt Amdur almost 8 years ago

I took a look at $SRC/uts/common/io/ksocket/ksocket.c. It doesn't look like it calls cv_waituntil_sig (it uses cv_wait_sig / cv_timedwait_sig), so I don't think it suffers from the same problem.

#4

Updated by Eric Schrock almost 8 years ago

  • Status changed from New to Resolved

changeset: 13491:fdfb21800636
tag: tip
user: Matt Amdur <>
date: Thu Oct 20 07:54:20 2011 -0700

description:
1605 System time changes combined with spurios wakeups cause DP_POLL to return prematurely
Reviewed by: Adam Leventhal <>
Reviewed by: George Wilson <>
Reviewed by: Richard Lowe <>
Reviewed by: Robert Mustacchi <>
Approved by: Eric Schrock <>

modified:
usr/src/uts/common/io/devpoll.c
usr/src/uts/common/os/condvar.c
usr/src/uts/common/sys/condvar.h
usr/src/uts/common/syscall/poll.c

Also available in: Atom PDF