mirror of
git://git.code.sf.net/p/cdesktopenv/code
synced 2025-03-09 15:50:02 +00:00
260 lines
5.7 KiB
C
260 lines
5.7 KiB
C
/***********************************************************************
|
|
* *
|
|
* This software is part of the ast package *
|
|
* Copyright (c) 1985-2013 AT&T Intellectual Property *
|
|
* Copyright (c) 2020-2021 Contributors to ksh 93u+m *
|
|
* and is licensed under the *
|
|
* Eclipse Public License, Version 1.0 *
|
|
* by AT&T Intellectual Property *
|
|
* *
|
|
* A copy of the License is available at *
|
|
* http://www.eclipse.org/org/documents/epl-v10.html *
|
|
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
|
|
* *
|
|
* Information and Software Systems Research *
|
|
* AT&T Research *
|
|
* Florham Park NJ *
|
|
* *
|
|
* Glenn Fowler <glenn.s.fowler@gmail.com> *
|
|
* David Korn <dgkorn@gmail.com> *
|
|
* Phong Vo <phongvo@gmail.com> *
|
|
* *
|
|
***********************************************************************/
|
|
#pragma prototyped
|
|
|
|
#include <assert.h>
|
|
#include <tv.h>
|
|
#include <tm.h>
|
|
#include <error.h>
|
|
|
|
#include "FEATURE/tvlib"
|
|
|
|
#if !_lib_nanosleep
|
|
# if _lib_select && !_prefer_poll
|
|
# if _sys_select
|
|
# include <sys/select.h>
|
|
# else
|
|
# include <sys/socket.h>
|
|
# endif
|
|
# elif _lib_poll_notimer
|
|
# undef _lib_poll
|
|
# elif _lib_poll
|
|
# include <poll.h>
|
|
# endif
|
|
#endif
|
|
|
|
#define NANOSECONDS 1000000000L
|
|
#define MILLISECONDS 1000
|
|
|
|
/*
|
|
* sleep for tv
|
|
* non-zero exit if sleep did not complete
|
|
* with remaining time in rv
|
|
*
|
|
* NOTE: some systems hide nanosleep() outside of libc
|
|
*/
|
|
|
|
int
|
|
tvsleep(register const Tv_t* tv, register Tv_t* rv)
|
|
{
|
|
assert(tv); /* Validate argument */
|
|
|
|
/* Return immediately if asked to sleep for no duration. */
|
|
if (!tv->tv_sec && !tv->tv_nsec)
|
|
return 0;
|
|
|
|
{
|
|
|
|
#if _lib_nanosleep
|
|
|
|
/* PRECISION: nanoseconds */
|
|
struct timespec stv = { tv->tv_sec, tv->tv_nsec };
|
|
struct timespec srv;
|
|
int r;
|
|
|
|
if ((r = nanosleep(&stv, &srv)) && errno == EINTR && rv)
|
|
{
|
|
rv->tv_sec = srv.tv_sec;
|
|
rv->tv_nsec = srv.tv_nsec;
|
|
}
|
|
return r;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
Tv_t tvBefore;
|
|
|
|
tvgettime(&tvBefore);
|
|
{
|
|
|
|
#if _lib_select && !_prefer_poll
|
|
|
|
/* PRECISION: microseconds */
|
|
struct timeval tvSleep = { tv->tv_sec, tv->tv_nsec / 1000 };
|
|
if (tv->tv_nsec % 1000)
|
|
++tvSleep.tv_usec;
|
|
(void)select(0, NiL, NiL, NiL, &tvSleep);
|
|
|
|
#elif _lib_poll
|
|
|
|
/* PRECISION: milliseconds
|
|
*
|
|
* We can sleep for up to 24 days with a single call to poll
|
|
* on systems with 32-bit integers, so calling sleep first
|
|
* only worsens precision with little gain. For example, the
|
|
* UnixWare manual page for usleep warns that a single call of
|
|
* that function requires eight system calls, but poll only
|
|
* requires one.
|
|
*/
|
|
struct pollfd dummy;
|
|
int timeout = INT_MAX; /* expose bugs */
|
|
|
|
if (tv->tv_sec <= (INT_MAX / MILLISECONDS))
|
|
{
|
|
timeout = tv->tv_sec * MILLISECONDS +
|
|
tv->tv_nsec / 1000000;
|
|
if (timeout < INT_MAX && tv->tv_nsec % 1000000)
|
|
++timeout;
|
|
}
|
|
(void)poll(&dummy, 0, timeout);
|
|
|
|
#else
|
|
|
|
uint32_t s = tv->tv_sec;
|
|
uint32_t n = tv->tv_nsec;
|
|
unsigned int t;
|
|
|
|
#if _lib_usleep
|
|
|
|
if (s < (0x7fffffff / 1000000))
|
|
{
|
|
int oerrno;
|
|
|
|
oerrno = errno;
|
|
errno = 0;
|
|
usleep(s * 1000000 + n / 1000);
|
|
if (!errno)
|
|
{
|
|
errno = oerrno;
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
#endif
|
|
|
|
if (s += (n + 999999999L) / 1000000000L)
|
|
{
|
|
while (s)
|
|
{
|
|
if (s > UINT_MAX)
|
|
{
|
|
t = UINT_MAX;
|
|
s -= UINT_MAX;
|
|
}
|
|
else
|
|
{
|
|
t = s;
|
|
s = 0;
|
|
}
|
|
if (t = sleep(t))
|
|
{
|
|
if (rv)
|
|
{
|
|
rv->tv_sec = s + t;
|
|
rv->tv_nsec = 0;
|
|
}
|
|
return -1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#if _lib_usleep
|
|
|
|
if (t = (n + 999L) / 1000L)
|
|
{
|
|
int oerrno;
|
|
|
|
oerrno = errno;
|
|
errno = 0;
|
|
usleep(t);
|
|
if (!errno)
|
|
{
|
|
errno = oerrno;
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
#endif
|
|
|
|
}
|
|
|
|
/* Unfortunately, some operating systems return success for select
|
|
* or poll without having slept for the specified duration, so check
|
|
* the clock.
|
|
*
|
|
* Although time discrepancies when sleeping are inevitable, tvsleep
|
|
* can guarantee that they always lie on or after the time specified,
|
|
* which is much more useful from the point of view of predictability
|
|
* than if they could also occur before.
|
|
*/
|
|
{
|
|
Tv_t tvAfter;
|
|
|
|
tvgettime(&tvAfter);
|
|
|
|
if (tvAfter.tv_nsec < tvBefore.tv_nsec)
|
|
{
|
|
if (!tvAfter.tv_sec)
|
|
return 0;
|
|
--tvAfter.tv_sec;
|
|
tvAfter.tv_nsec += (NANOSECONDS - tvBefore.tv_nsec);
|
|
}
|
|
else
|
|
{
|
|
tvAfter.tv_nsec -= tvBefore.tv_nsec;
|
|
}
|
|
if (tvAfter.tv_sec < tvBefore.tv_sec)
|
|
return 0;
|
|
tvAfter.tv_sec -= tvBefore.tv_sec;
|
|
/* tvAfter now holds the non-negative time slept */
|
|
|
|
tvBefore = *tv;
|
|
/* Normalize the time to sleep so that ns < 10e9 */
|
|
tvBefore.tv_sec += tvBefore.tv_nsec / NANOSECONDS;
|
|
tvBefore.tv_nsec %= NANOSECONDS;
|
|
|
|
if (tvBefore.tv_nsec < tvAfter.tv_nsec)
|
|
{
|
|
if (!tvBefore.tv_sec)
|
|
return 0;
|
|
--tvBefore.tv_sec;
|
|
tvBefore.tv_nsec += (NANOSECONDS - tvAfter.tv_nsec);
|
|
}
|
|
else
|
|
{
|
|
tvBefore.tv_nsec -= tvAfter.tv_nsec;
|
|
}
|
|
if (tvBefore.tv_sec < tvAfter.tv_sec)
|
|
return 0;
|
|
tvBefore.tv_sec -= tvAfter.tv_sec;
|
|
|
|
if (tvBefore.tv_sec > 0 || tvBefore.tv_nsec > 0)
|
|
{
|
|
if (rv)
|
|
*rv = tvBefore;
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|