Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 22 Feb 2017 08:46:05 -0700
From:      Ian Lepore <ian@freebsd.org>
To:        Eric van Gyzen <vangyzen@FreeBSD.org>, Sebastian Huber <sebastian.huber@embedded-brains.de>, FreeBSD <freebsd-hackers@freebsd.org>
Subject:   Re: Absolute timeouts and clock adjustments
Message-ID:  <1487778365.73144.144.camel@freebsd.org>
In-Reply-To: <1ff4d78a-a157-53c5-af7e-b516bc1b6187@FreeBSD.org>
References:  <58AD5802.30908@embedded-brains.de> <1ff4d78a-a157-53c5-af7e-b516bc1b6187@FreeBSD.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Wed, 2017-02-22 at 09:19 -0600, Eric van Gyzen wrote:
> On 02/22/2017 03:21, Sebastian Huber wrote:
> > 
> > Hello,
> > 
> > I try to figure out how the timeout mechanisms work in current
> > FreeBSD. My
> > interpretation (which could be completely wrong) of POSIX is
> > something like this
> > should happen:
> > 
> > now 2017-02-22
> > sem_timedwait(s, 2023-12-13)
> > external entity adjusts time to 2050-01-01
> > timeout of sem_timedwait() occurs due to the time adjustment
> This is correct.
> 
> > 
> > Inside the kernel all absolute timeouts seem to use the uptime. The
> > sem_timedwait() seems to end up eventually in:
> > 
> > /*
> >  * Put thread into sleep state, before sleeping, check if
> >  * thread was removed from umtx queue.
> >  */
> > static inline int
> > umtxq_sleep(struct umtx_q *uq, const char *wmesg, struct
> > abs_timeout *abstime)
> > {
> >     struct umtxq_chain *uc;
> >     int error, timo;
> > 
> >     uc = umtxq_getchain(&uq->uq_key);
> >     UMTXQ_LOCKED_ASSERT(uc);
> >     for (;;) {
> >         if (!(uq->uq_flags & UQF_UMTXQ))
> >             return (0);
> >         if (abstime != NULL) {
> >             timo = abs_timeout_gethz(abstime);
> >             if (timo < 0)
> >                 return (ETIMEDOUT);
> >         } else
> >             timo = 0;
> >         error = msleep(uq, &uc->uc_lock, PCATCH | PDROP, wmesg,
> > timo);
> >         if (error != EWOULDBLOCK) {
> >             umtxq_lock(&uq->uq_key);
> >             break;
> >         }
> >         if (abstime != NULL)
> >             abs_timeout_update(abstime);
> >         umtxq_lock(&uq->uq_key);
> >     }
> >     return (error);
> > }
> > 
> > The abs_timeout_gethz() returns the interval length in ticks of
> > [abstime->cur,
> > abstime->end]. Since the msleep() uses the uptime, does this mean
> > that timeouts
> > trigger not immediately due to time adjustments in FreeBSD?
> This is also correct.  The sleep will not be affected by the clock
> adjustment. 
> This is contrary to POSIX.
> 
> Note that CentOS 6 (Linux 3.10) behaves the same way.  Fedora 24
> (Linux 4.8) 
> behaves according to POSIX.  I don't know when this changed.  I also
> don't know 
> if it's configurable.
> 
> By a curious coincidence, I'm working on adding a new
> sem_clockwait_np() 
> function to FreeBSD.  It allows the caller to specify the reference
> clock and 
> choose between absolute and relative mode.  In relative mode, the
> remaining time 
> can be returned.
> 
> 	https://reviews.freebsd.org/D9656
> 
> My changes will not make sem_timedwait() comply with POSIX, but they
> will let 
> the caller use CLOCK_MONOTONIC and avoid the issue.
> 
> Eric

Using CLOCK_MONOTONIC doesn't avoid the issue, it just explicitly asks
for the current behavior.  If the behavior you need is to wake up when
CLOCK_REALTIME exceeds some value, you're still screwed.

It would be easy enough to fix the current behavior by adding something
like "if (timo > hz) timo = hz;" to the existing loop so that
CLOCK_REALTIME gets re-checked once a second.

-- Ian



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?1487778365.73144.144.camel>