Thread: Use nanosleep(2) in pg_usleep, if available?
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
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
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
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
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.
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
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.