Thread: Use nanosleep(2) in pg_usleep, if available?

Use nanosleep(2) in pg_usleep, if available?

From
Tom Lane
Date:
In the thread about vacuum_cost_delay vs vacuum_cost_limit,
I wondered whether nanosleep(2) would provide any better
timing resolution than select(2).  Some experimentation
suggests that it doesn't, but nonetheless I see a good reason
why we should consider making pg_usleep use nanosleep() if
possible: it's got much better-defined semantics for what
happens if a signal arrives.  The comments for pg_usleep
lay out the problems with relying on select():

 * CAUTION: the behavior when a signal arrives during the sleep is platform
 * dependent.  On most Unix-ish platforms, a signal does not terminate the
 * sleep; but on some, it will (the Windows implementation also allows signals
 * to terminate pg_usleep).  And there are platforms where not only does a
 * signal not terminate the sleep, but it actually resets the timeout counter
 * so that the sleep effectively starts over!  It is therefore rather hazardous
 * to use this for long sleeps; a continuing stream of signal events could
 * prevent the sleep from ever terminating.  Better practice for long sleeps
 * is to use WaitLatch() with a timeout.

While the WaitLatch alternative avoids the problem, I doubt
we're ever going to remove pg_usleep entirely, so it'd be
good if it had fewer sharp edges.  nanosleep() has the
same behavior as Windows, ie, the sleep is guaranteed to be
terminated by a signal.  So if we used nanosleep() where available
we'd have that behavior on just about every interesting platform.

nanosleep() does exist pretty far back: it's in SUSv2, though
that version of the standard allows it to fail with ENOSYS.
Not sure if we'd need to teach configure to check for that
possibility.

Thoughts?

            regards, tom lane


Re: Use nanosleep(2) in pg_usleep, if available?

From
Robert Haas
Date:
On Mon, Mar 11, 2019 at 8:03 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
> While the WaitLatch alternative avoids the problem, I doubt
> we're ever going to remove pg_usleep entirely, so it'd be
> good if it had fewer sharp edges.  nanosleep() has the
> same behavior as Windows, ie, the sleep is guaranteed to be
> terminated by a signal.  So if we used nanosleep() where available
> we'd have that behavior on just about every interesting platform.

Is there any feasible way to go the other way, and make pg_usleep()
actually always sleep for the requested time, rather than terminating
early?

(Probably not, but I'm just asking.)

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company


Re: Use nanosleep(2) in pg_usleep, if available?

From
Tom Lane
Date:
Robert Haas <robertmhaas@gmail.com> writes:
> On Mon, Mar 11, 2019 at 8:03 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> While the WaitLatch alternative avoids the problem, I doubt
>> we're ever going to remove pg_usleep entirely, so it'd be
>> good if it had fewer sharp edges.  nanosleep() has the
>> same behavior as Windows, ie, the sleep is guaranteed to be
>> terminated by a signal.  So if we used nanosleep() where available
>> we'd have that behavior on just about every interesting platform.

> Is there any feasible way to go the other way, and make pg_usleep()
> actually always sleep for the requested time, rather than terminating
> early?

> (Probably not, but I'm just asking.)

Yes, nanosleep would support that; it returns the remaining time after
an interrupt, so we could just loop till done.  The select-based
implementation would have a hard time supporting it, though, and
I have no idea about Windows.

Now, this proposal is predicated on the idea that we won't need
to care too much about the select case because few if any
platforms would end up using it.  So really the question boils
down to whether we can provide the continue-to-wait behavior on
Windows.  Anyone?

(I'm not sure what I think about which behavior is really more
desirable.  We can debate that if there's actually a plausible
choice to be made, which seems to depend on Windows.)

            regards, tom lane


Re: Use nanosleep(2) in pg_usleep, if available?

From
Robert Haas
Date:
On Tue, Mar 12, 2019 at 1:13 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
> (I'm not sure what I think about which behavior is really more
> desirable.  We can debate that if there's actually a plausible
> choice to be made, which seems to depend on Windows.)

Yeah, that's a fair question.  My motivation for asking was that I
sometimes try to insert sleeps when debugging things, and they don't
actually sleep, because they get interrupted.  That's not dispositive,
though.

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company


Re: Use nanosleep(2) in pg_usleep, if available?

From
Andres Freund
Date:
Hi,

On March 12, 2019 10:17:19 AM PDT, Robert Haas <robertmhaas@gmail.com> wrote:
>On Tue, Mar 12, 2019 at 1:13 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> (I'm not sure what I think about which behavior is really more
>> desirable.  We can debate that if there's actually a plausible
>> choice to be made, which seems to depend on Windows.)
>
>Yeah, that's a fair question.  My motivation for asking was that I
>sometimes try to insert sleeps when debugging things, and they don't
>actually sleep, because they get interrupted.  That's not dispositive,
>though.

Had that happen annoyingly often too. OTOH, we have some sleep loops where it's probably mildly helpful to react faster
whenan interrupt happens. But those probably should be rewritten to use latches. 

Andres
--
Sent from my Android device with K-9 Mail. Please excuse my brevity.


Re: Use nanosleep(2) in pg_usleep, if available?

From
Tom Lane
Date:
Robert Haas <robertmhaas@gmail.com> writes:
> On Tue, Mar 12, 2019 at 1:13 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> (I'm not sure what I think about which behavior is really more
>> desirable.  We can debate that if there's actually a plausible
>> choice to be made, which seems to depend on Windows.)

> Yeah, that's a fair question.  My motivation for asking was that I
> sometimes try to insert sleeps when debugging things, and they don't
> actually sleep, because they get interrupted.  That's not dispositive,
> though.

There never has been a guarantee that we won't sleep for *more*
than the requested time; the kernel might not give us back the
CPU right away.  But re-sleeping would at least ensure that
we won't sleep for *less* than the requested time.  So my opinion
after five minutes' thought is that re-sleeping is better, because
it gives you at least some kind of promise related to the function's
nominal semantics.

It still depends on whether we can make Windows do it, though.
I suppose a brute-force way would be like what WaitLatch does:
do our own timekeeping using instr_time.h.  (That'd work for
select as well, I guess.)

            regards, tom lane


Re: Use nanosleep(2) in pg_usleep, if available?

From
Magnus Hagander
Date:
On Tue, Mar 12, 2019 at 6:13 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
Robert Haas <robertmhaas@gmail.com> writes:
> On Mon, Mar 11, 2019 at 8:03 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> While the WaitLatch alternative avoids the problem, I doubt
>> we're ever going to remove pg_usleep entirely, so it'd be
>> good if it had fewer sharp edges.  nanosleep() has the
>> same behavior as Windows, ie, the sleep is guaranteed to be
>> terminated by a signal.  So if we used nanosleep() where available
>> we'd have that behavior on just about every interesting platform.

> Is there any feasible way to go the other way, and make pg_usleep()
> actually always sleep for the requested time, rather than terminating
> early?

> (Probably not, but I'm just asking.)

Yes, nanosleep would support that; it returns the remaining time after
an interrupt, so we could just loop till done.  The select-based
implementation would have a hard time supporting it, though, and
I have no idea about Windows.

Now, this proposal is predicated on the idea that we won't need
to care too much about the select case because few if any
platforms would end up using it.  So really the question boils
down to whether we can provide the continue-to-wait behavior on
Windows.  Anyone?

pg_usleep() on Windows uses WaitForSingleObject with a timeout, which cannot do that.

It seems we could fairly easily reimplement nthat on top of a waitable timer (CreateWaitableTimer/SetWaitableTimer) which should handle this situation. As long as it's only in pg_usleep() we need to change things, the change should be trivial.

--