Title: time.sleep(-1.0) behaviour
Type: behavior Stage: patch review
Components: Extension Modules Versions: Python 3.3
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: rhettinger Nosy List: daniel.urban, eckhardt, giampaolo.rodola, jcea, pitrou, python-dev, rhettinger, santoso.wijaya, vstinner
Priority: low Keywords: patch

Created on 2011-07-01 06:45 by eckhardt, last changed 2011-07-05 20:01 by vstinner. This issue is now closed.

File name Uploaded Description Edit
sleep_negative.patch vstinner, 2011-07-01 09:33 review
Messages (8)
msg139548 - (view) Author: Ulrich Eckhardt (eckhardt) Date: 2011-07-01 06:45
For reference, see the thread on the users' mailinglist/newsgroup from 2011-06-29 "how to call a function for evry 10 seconds" and the thread on the developers' mailinglist from 2011-06-30 "time.sleep(-1) behaviour".

The problem is how negative arguments to time.sleep() are handled. Python 2.x (tested 2.5 and 2.7) implementations on MS Windows seems to have a 32-bit underflow while converting the given argument to the DWORD that is passed to win32's Sleep() function. This causes a small negative value to sleep for a long time.

On Linux, using Python 2.6, you get an IOError instead. While an error is better than blocking effectively forever, the use of an IOError to signal the wrong argument is at least confusing. I guess it is an artifact of the implementation, but that shouldn't be visible prominently.

IMHH, both versions should raise a ValueError to signal invalid arguments. However, there was also the suggestion to simply treat negative values as zero, after all time.sleep() is already documented to possibly sleep longer than specified.
msg139558 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2011-07-01 09:33
I think that time.sleep() should behave as (issue #11757, commit 3982be773b54) and signal.sigtimedwait(): raise a ValueError if the timeout is negative. A good reason to always raise an error is that floatsleep() has different implementations. Especially, the select() implementation behaves differently depending on the platform: negative timeout raises an error (select.error(22, 'Invalid argument')) or returns immediatly.

Attached patch raises an error if the time length is negative. It avoids the integer overflow in the Windows implementation.
msg139559 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2011-07-01 09:34
I agree with the ValueError suggestion. Since it would slightly change existing behaviour, it can only be done in a feature release (3.3).

According to Google Code Search, deliberate uses of sleep(-1) are almost non-existent:
msg139560 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2011-07-01 09:41
> According to Google Code Search, deliberate uses of sleep(-1)
> are almost non-existent:

The search gives two results, in pycaf and a plone installer (in ""). I don't know what is the expected behaviour: "infinite" sleep? wait for a SIGINT signal? I'm ok to only change this in Python 3.3, it's not a good idea to introduce subtle differences in minor Python releases.
msg139563 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2011-07-01 10:26
See also #12462, I found something weird in the signal handling of floatsleep().
msg139573 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2011-07-01 12:48
Tim Lesher on python-dev: "On the Windows side, Sleep(-1) as "infinite" is correct and documented:"

Wine defines INFINITE using "#define INFINITE 0xFFFFFFFF":

-1 becomes INFINITE because of an integer overflow (because of a cast from double to *unsigned* long). time.sleep(-2) doesn't sleep for an infinite time, but for more than 136 years (maybe more in 64 bits?):

>>> print(datetime.timedelta(seconds=-2 & 0xFFFFFFFF))
49710 days, 6:28:14

What is the usecase of Sleep(INFINITE)? Wait a signal or wait another event?

Because other platforms don't support the INFINITE timeout, I suggest to always raise an error to have the same behaviour on all platforms. 

On POSIX, you can use pause(), sigwait(), select() or other functions to wait a signal for example. If we something something like that on Windows, we need a new function, but not a magic time.sleep(-1) please.
msg139901 - (view) Author: Roundup Robot (python-dev) (Python triager) Date: 2011-07-05 20:00
New changeset 0e5485634817 by Victor Stinner in branch 'default':
Issue #12459: time.sleep() now raises a ValueError if the sleep length is
msg139902 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2011-07-05 20:01
Tim Lesher agreed to raise an exception ("That makes sense. Better to be consistent within the time API--I know the different semantics of time.clock() have confused people around here."), so I think that everybody agreed to raise an exception.

I commited my commit, let close this issue.
Date User Action Args
2011-07-05 20:01:45vstinnersetstatus: open -> closed
resolution: fixed
messages: + msg139902
2011-07-05 20:00:34python-devsetnosy: + python-dev
messages: + msg139901
2011-07-02 11:48:35jceasetnosy: + jcea
2011-07-01 17:49:45santoso.wijayasetnosy: + santoso.wijaya
2011-07-01 16:34:53daniel.urbansetnosy: + daniel.urban
2011-07-01 15:09:04giampaolo.rodolasetnosy: + giampaolo.rodola
2011-07-01 12:48:13vstinnersetmessages: + msg139573
2011-07-01 10:26:15vstinnersetmessages: + msg139563
2011-07-01 09:41:52vstinnersetmessages: + msg139560
2011-07-01 09:34:21pitrousetversions: + Python 3.3
nosy: + pitrou

messages: + msg139559

components: + Extension Modules
stage: patch review
2011-07-01 09:33:22vstinnersetfiles: + sleep_negative.patch

nosy: + vstinner
messages: + msg139558

keywords: + patch
2011-07-01 07:47:00rhettingersetpriority: normal -> low
assignee: rhettinger

nosy: + rhettinger
2011-07-01 06:45:50eckhardtcreate