summaryrefslogtreecommitdiff
path: root/src/time
diff options
context:
space:
mode:
Diffstat (limited to 'src/time')
-rw-r--r--src/time/__map_file.c2
-rw-r--r--src/time/__tz.c61
-rw-r--r--src/time/__year_to_secs.c4
-rw-r--r--src/time/clock_getcpuclockid.c1
-rw-r--r--src/time/clock_getres.c14
-rw-r--r--src/time/clock_gettime.c59
-rw-r--r--src/time/clock_nanosleep.c35
-rw-r--r--src/time/clock_settime.c17
-rw-r--r--src/time/nanosleep.c2
-rw-r--r--src/time/strftime.c8
-rw-r--r--src/time/strptime.c66
-rw-r--r--src/time/timer_create.c40
-rw-r--r--src/time/timer_gettime.c16
-rw-r--r--src/time/timer_settime.c25
14 files changed, 299 insertions, 51 deletions
diff --git a/src/time/__map_file.c b/src/time/__map_file.c
index 9d376222..c2b29fe8 100644
--- a/src/time/__map_file.c
+++ b/src/time/__map_file.c
@@ -9,7 +9,7 @@ const char unsigned *__map_file(const char *pathname, size_t *size)
const unsigned char *map = MAP_FAILED;
int fd = sys_open(pathname, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
if (fd < 0) return 0;
- if (!syscall(SYS_fstat, fd, &st)) {
+ if (!__fstat(fd, &st)) {
map = __mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
*size = st.st_size;
}
diff --git a/src/time/__tz.c b/src/time/__tz.c
index 185642e8..c34b3eb7 100644
--- a/src/time/__tz.c
+++ b/src/time/__tz.c
@@ -4,8 +4,15 @@
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
+#include <ctype.h>
#include "libc.h"
#include "lock.h"
+#include "fork_impl.h"
+
+#define malloc __libc_malloc
+#define calloc undef
+#define realloc undef
+#define free undef
long __timezone = 0;
int __daylight = 0;
@@ -30,6 +37,7 @@ static char *old_tz = old_tz_buf;
static size_t old_tz_size = sizeof old_tz_buf;
static volatile int lock[1];
+volatile int *const __timezone_lockptr = lock;
static int getint(const char **p)
{
@@ -86,15 +94,15 @@ static void getname(char *d, const char **p)
int i;
if (**p == '<') {
++*p;
- for (i=0; (*p)[i]!='>' && i<TZNAME_MAX; i++)
- d[i] = (*p)[i];
- ++*p;
+ for (i=0; (*p)[i] && (*p)[i]!='>'; i++)
+ if (i<TZNAME_MAX) d[i] = (*p)[i];
+ if ((*p)[i]) ++*p;
} else {
- for (i=0; ((*p)[i]|32)-'a'<26U && i<TZNAME_MAX; i++)
- d[i] = (*p)[i];
+ for (i=0; ((*p)[i]|32)-'a'<26U; i++)
+ if (i<TZNAME_MAX) d[i] = (*p)[i];
}
*p += i;
- d[i] = 0;
+ d[i<TZNAME_MAX?i:TZNAME_MAX] = 0;
}
#define VEC(...) ((const unsigned char[]){__VA_ARGS__})
@@ -147,10 +155,21 @@ static void do_tzset()
}
if (old_tz) memcpy(old_tz, s, i+1);
+ int posix_form = 0;
+ if (*s != ':') {
+ p = s;
+ char dummy_name[TZNAME_MAX+1];
+ getname(dummy_name, &p);
+ if (p!=s && (*p == '+' || *p == '-' || isdigit(*p)
+ || !strcmp(dummy_name, "UTC")
+ || !strcmp(dummy_name, "GMT")))
+ posix_form = 1;
+ }
+
/* Non-suid can use an absolute tzfile pathname or a relative
* pathame beginning with "."; in secure mode, only the
* standard path will be searched. */
- if (*s == ':' || ((p=strchr(s, '/')) && !memchr(s, ',', p-s))) {
+ if (!posix_form) {
if (*s == ':') s++;
if (*s == '/' || *s == '.') {
if (!libc.secure || !strcmp(s, "/etc/localtime"))
@@ -178,7 +197,7 @@ static void do_tzset()
zi = map;
if (map) {
int scale = 2;
- if (sizeof(time_t) > 4 && map[4]=='2') {
+ if (map[4]!='1') {
size_t skip = zi_dotprod(zi+20, VEC(1,1,8,5,6,1), 6);
trans = zi+skip+44+44;
scale++;
@@ -274,22 +293,20 @@ static size_t scan_trans(long long t, int local, size_t *alt)
n = (index-trans)>>scale;
if (a == n-1) return -1;
if (a == 0) {
- x = zi_read32(trans + (a<<scale));
- if (scale == 3) x = x<<32 | zi_read32(trans + (a<<scale) + 4);
+ x = zi_read32(trans);
+ if (scale == 3) x = x<<32 | zi_read32(trans + 4);
else x = (int32_t)x;
- if (local) off = (int32_t)zi_read32(types + 6 * index[a-1]);
+ /* Find the lowest non-DST type, or 0 if none. */
+ size_t j = 0;
+ for (size_t i=abbrevs-types; i; i-=6) {
+ if (!types[i-6+4]) j = i-6;
+ }
+ if (local) off = (int32_t)zi_read32(types + j);
+ /* If t is before first transition, use the above-found type
+ * and the index-zero (after transition) type as the alt. */
if (t - off < (int64_t)x) {
- for (a=0; a<(abbrevs-types)/6; a++) {
- if (types[6*a+4] != types[4]) break;
- }
- if (a == (abbrevs-types)/6) a = 0;
- if (types[6*a+4]) {
- *alt = a;
- return 0;
- } else {
- *alt = 0;
- return a;
- }
+ if (alt) *alt = index[0];
+ return j/6;
}
}
diff --git a/src/time/__year_to_secs.c b/src/time/__year_to_secs.c
index 2824ec6d..b42f5a6d 100644
--- a/src/time/__year_to_secs.c
+++ b/src/time/__year_to_secs.c
@@ -10,9 +10,9 @@ long long __year_to_secs(long long year, int *is_leap)
return 31536000*(y-70) + 86400*leaps;
}
- int cycles, centuries, leaps, rem;
+ int cycles, centuries, leaps, rem, dummy;
- if (!is_leap) is_leap = &(int){0};
+ if (!is_leap) is_leap = &dummy;
cycles = (year-100) / 400;
rem = (year-100) % 400;
if (rem < 0) {
diff --git a/src/time/clock_getcpuclockid.c b/src/time/clock_getcpuclockid.c
index 8a0e2d4c..bce1e8ab 100644
--- a/src/time/clock_getcpuclockid.c
+++ b/src/time/clock_getcpuclockid.c
@@ -8,6 +8,7 @@ int clock_getcpuclockid(pid_t pid, clockid_t *clk)
struct timespec ts;
clockid_t id = (-pid-1)*8U + 2;
int ret = __syscall(SYS_clock_getres, id, &ts);
+ if (ret == -EINVAL) ret = -ESRCH;
if (ret) return -ret;
*clk = id;
return 0;
diff --git a/src/time/clock_getres.c b/src/time/clock_getres.c
index 36a0d695..81c67037 100644
--- a/src/time/clock_getres.c
+++ b/src/time/clock_getres.c
@@ -3,5 +3,19 @@
int clock_getres(clockid_t clk, struct timespec *ts)
{
+#ifdef SYS_clock_getres_time64
+ /* On a 32-bit arch, use the old syscall if it exists. */
+ if (SYS_clock_getres != SYS_clock_getres_time64) {
+ long ts32[2];
+ int r = __syscall(SYS_clock_getres, clk, ts32);
+ if (!r && ts) {
+ ts->tv_sec = ts32[0];
+ ts->tv_nsec = ts32[1];
+ }
+ return __syscall_ret(r);
+ }
+#endif
+ /* If reaching this point, it's a 64-bit arch or time64-only
+ * 32-bit arch and we can get result directly into timespec. */
return syscall(SYS_clock_getres, clk, ts);
}
diff --git a/src/time/clock_gettime.c b/src/time/clock_gettime.c
index 8fd1b8f5..4d2ec22f 100644
--- a/src/time/clock_gettime.c
+++ b/src/time/clock_gettime.c
@@ -8,9 +8,44 @@
static void *volatile vdso_func;
+#ifdef VDSO_CGT32_SYM
+static void *volatile vdso_func_32;
+static int cgt_time32_wrap(clockid_t clk, struct timespec *ts)
+{
+ long ts32[2];
+ int (*f)(clockid_t, long[2]) =
+ (int (*)(clockid_t, long[2]))vdso_func_32;
+ int r = f(clk, ts32);
+ if (!r) {
+ /* Fallback to syscalls if time32 overflowed. Maybe
+ * we lucked out and somehow migrated to a kernel with
+ * time64 syscalls available. */
+ if (ts32[0] < 0) {
+ a_cas_p(&vdso_func, (void *)cgt_time32_wrap, 0);
+ return -ENOSYS;
+ }
+ ts->tv_sec = ts32[0];
+ ts->tv_nsec = ts32[1];
+ }
+ return r;
+}
+#endif
+
static int cgt_init(clockid_t clk, struct timespec *ts)
{
void *p = __vdsosym(VDSO_CGT_VER, VDSO_CGT_SYM);
+#ifdef VDSO_CGT32_SYM
+ if (!p) {
+ void *q = __vdsosym(VDSO_CGT32_VER, VDSO_CGT32_SYM);
+ if (q) {
+ a_cas_p(&vdso_func_32, 0, q);
+ p = cgt_time32_wrap;
+ }
+ }
+#ifdef VDSO_CGT_WORKAROUND
+ if (!__vdsosym(VDSO_CGT32_VER, VDSO_CGT32_SYM)) p = 0;
+#endif
+#endif
int (*f)(clockid_t, struct timespec *) =
(int (*)(clockid_t, struct timespec *))p;
a_cas_p(&vdso_func, (void *)cgt_init, p);
@@ -40,7 +75,29 @@ int __clock_gettime(clockid_t clk, struct timespec *ts)
}
#endif
+#ifdef SYS_clock_gettime64
+ r = -ENOSYS;
+ if (sizeof(time_t) > 4)
+ r = __syscall(SYS_clock_gettime64, clk, ts);
+ if (SYS_clock_gettime == SYS_clock_gettime64 || r!=-ENOSYS)
+ return __syscall_ret(r);
+ long ts32[2];
+ r = __syscall(SYS_clock_gettime, clk, ts32);
+#ifdef SYS_gettimeofday
+ if (r==-ENOSYS && clk==CLOCK_REALTIME) {
+ r = __syscall(SYS_gettimeofday, ts32, 0);
+ ts32[1] *= 1000;
+ }
+#endif
+ if (!r) {
+ ts->tv_sec = ts32[0];
+ ts->tv_nsec = ts32[1];
+ return r;
+ }
+ return __syscall_ret(r);
+#else
r = __syscall(SYS_clock_gettime, clk, ts);
+#ifdef SYS_gettimeofday
if (r == -ENOSYS) {
if (clk == CLOCK_REALTIME) {
__syscall(SYS_gettimeofday, ts, 0);
@@ -49,7 +106,9 @@ int __clock_gettime(clockid_t clk, struct timespec *ts)
}
r = -EINVAL;
}
+#endif
return __syscall_ret(r);
+#endif
}
weak_alias(__clock_gettime, clock_gettime);
diff --git a/src/time/clock_nanosleep.c b/src/time/clock_nanosleep.c
index 32f0c07e..e195499c 100644
--- a/src/time/clock_nanosleep.c
+++ b/src/time/clock_nanosleep.c
@@ -2,8 +2,37 @@
#include <errno.h>
#include "syscall.h"
-int clock_nanosleep(clockid_t clk, int flags, const struct timespec *req, struct timespec *rem)
+#define IS32BIT(x) !((x)+0x80000000ULL>>32)
+#define CLAMP(x) (int)(IS32BIT(x) ? (x) : 0x7fffffffU+((0ULL+(x))>>63))
+
+int __clock_nanosleep(clockid_t clk, int flags, const struct timespec *req, struct timespec *rem)
{
- int r = -__syscall_cp(SYS_clock_nanosleep, clk, flags, req, rem);
- return clk == CLOCK_THREAD_CPUTIME_ID ? EINVAL : r;
+ if (clk == CLOCK_THREAD_CPUTIME_ID) return EINVAL;
+#ifdef SYS_clock_nanosleep_time64
+ time_t s = req->tv_sec;
+ long ns = req->tv_nsec;
+ int r = -ENOSYS;
+ if (SYS_clock_nanosleep == SYS_clock_nanosleep_time64 || !IS32BIT(s))
+ r = __syscall_cp(SYS_clock_nanosleep_time64, clk, flags,
+ ((long long[]){s, ns}), rem);
+ if (SYS_clock_nanosleep == SYS_clock_nanosleep_time64 || r!=-ENOSYS)
+ return -r;
+ long long extra = s - CLAMP(s);
+ long ts32[2] = { CLAMP(s), ns };
+ if (clk == CLOCK_REALTIME && !flags)
+ r = __syscall_cp(SYS_nanosleep, &ts32, &ts32);
+ else
+ r = __syscall_cp(SYS_clock_nanosleep, clk, flags, &ts32, &ts32);
+ if (r==-EINTR && rem && !(flags & TIMER_ABSTIME)) {
+ rem->tv_sec = ts32[0] + extra;
+ rem->tv_nsec = ts32[1];
+ }
+ return -r;
+#else
+ if (clk == CLOCK_REALTIME && !flags)
+ return -__syscall_cp(SYS_nanosleep, req, rem);
+ return -__syscall_cp(SYS_clock_nanosleep, clk, flags, req, rem);
+#endif
}
+
+weak_alias(__clock_nanosleep, clock_nanosleep);
diff --git a/src/time/clock_settime.c b/src/time/clock_settime.c
index 66b8162d..1004ed15 100644
--- a/src/time/clock_settime.c
+++ b/src/time/clock_settime.c
@@ -1,7 +1,24 @@
#include <time.h>
+#include <errno.h>
#include "syscall.h"
+#define IS32BIT(x) !((x)+0x80000000ULL>>32)
+
int clock_settime(clockid_t clk, const struct timespec *ts)
{
+#ifdef SYS_clock_settime64
+ time_t s = ts->tv_sec;
+ long ns = ts->tv_nsec;
+ int r = -ENOSYS;
+ if (SYS_clock_settime == SYS_clock_settime64 || !IS32BIT(s))
+ r = __syscall(SYS_clock_settime64, clk,
+ ((long long[]){s, ns}));
+ if (SYS_clock_settime == SYS_clock_settime64 || r!=-ENOSYS)
+ return __syscall_ret(r);
+ if (!IS32BIT(s))
+ return __syscall_ret(-ENOTSUP);
+ return syscall(SYS_clock_settime, clk, ((long[]){s, ns}));
+#else
return syscall(SYS_clock_settime, clk, ts);
+#endif
}
diff --git a/src/time/nanosleep.c b/src/time/nanosleep.c
index 1e6f3922..bc9f7895 100644
--- a/src/time/nanosleep.c
+++ b/src/time/nanosleep.c
@@ -3,5 +3,5 @@
int nanosleep(const struct timespec *req, struct timespec *rem)
{
- return syscall_cp(SYS_nanosleep, req, rem);
+ return __syscall_ret(-__clock_nanosleep(CLOCK_REALTIME, 0, req, rem));
}
diff --git a/src/time/strftime.c b/src/time/strftime.c
index cc53d536..c40246db 100644
--- a/src/time/strftime.c
+++ b/src/time/strftime.c
@@ -3,6 +3,7 @@
#include <string.h>
#include <langinfo.h>
#include <locale.h>
+#include <ctype.h>
#include <time.h>
#include <limits.h>
#include "locale_impl.h"
@@ -233,7 +234,12 @@ size_t __strftime_l(char *restrict s, size_t n, const char *restrict f, const st
pad = 0;
if (*f == '-' || *f == '_' || *f == '0') pad = *f++;
if ((plus = (*f == '+'))) f++;
- width = strtoul(f, &p, 10);
+ if (isdigit(*f)) {
+ width = strtoul(f, &p, 10);
+ } else {
+ width = 0;
+ p = (void *)f;
+ }
if (*p == 'C' || *p == 'F' || *p == 'G' || *p == 'Y') {
if (!width && p!=f) width = 1;
} else {
diff --git a/src/time/strptime.c b/src/time/strptime.c
index c54a0d8c..b1147242 100644
--- a/src/time/strptime.c
+++ b/src/time/strptime.c
@@ -59,6 +59,22 @@ char *strptime(const char *restrict s, const char *restrict f, struct tm *restri
s = strptime(s, "%m/%d/%y", tm);
if (!s) return 0;
break;
+ case 'F':
+ /* Use temp buffer to implement the odd requirement
+ * that entire field be width-limited but the year
+ * subfield not itself be limited. */
+ i = 0;
+ char tmp[20];
+ if (*s == '-' || *s == '+') tmp[i++] = *s++;
+ while (*s=='0' && isdigit(s[1])) s++;
+ for (; *s && i<(size_t)w && i+1<sizeof tmp; i++) {
+ tmp[i] = *s++;
+ }
+ tmp[i] = 0;
+ char *p = strptime(tmp, "%12Y-%m-%d", tm);
+ if (!p) return 0;
+ s -= tmp+i-p;
+ break;
case 'H':
dest = &tm->tm_hour;
min = 0;
@@ -114,6 +130,13 @@ char *strptime(const char *restrict s, const char *restrict f, struct tm *restri
s = strptime(s, "%H:%M", tm);
if (!s) return 0;
break;
+ case 's':
+ /* Parse only. Effect on tm is unspecified
+ * and presently no effect is implemented.. */
+ if (*s == '-') s++;
+ if (!isdigit(*s)) return 0;
+ while (isdigit(*s)) s++;
+ break;
case 'S':
dest = &tm->tm_sec;
min = 0;
@@ -125,11 +148,30 @@ char *strptime(const char *restrict s, const char *restrict f, struct tm *restri
break;
case 'U':
case 'W':
- /* Throw away result, for now. (FIXME?) */
+ /* Throw away result of %U, %V, %W, %g, and %G. Effect
+ * is unspecified and there is no clear right choice. */
dest = &dummy;
min = 0;
range = 54;
goto numeric_range;
+ case 'V':
+ dest = &dummy;
+ min = 1;
+ range = 53;
+ goto numeric_range;
+ case 'g':
+ dest = &dummy;
+ w = 2;
+ goto numeric_digits;
+ case 'G':
+ dest = &dummy;
+ if (w<0) w=4;
+ goto numeric_digits;
+ case 'u':
+ dest = &tm->tm_wday;
+ min = 1;
+ range = 7;
+ goto numeric_range;
case 'w':
dest = &tm->tm_wday;
min = 0;
@@ -154,6 +196,28 @@ char *strptime(const char *restrict s, const char *restrict f, struct tm *restri
adj = 1900;
want_century = 0;
goto numeric_digits;
+ case 'z':
+ if (*s == '+') neg = 0;
+ else if (*s == '-') neg = 1;
+ else return 0;
+ for (i=0; i<4; i++) if (!isdigit(s[1+i])) return 0;
+ tm->__tm_gmtoff = (s[1]-'0')*36000+(s[2]-'0')*3600
+ + (s[3]-'0')*600 + (s[4]-'0')*60;
+ if (neg) tm->__tm_gmtoff = -tm->__tm_gmtoff;
+ s += 5;
+ break;
+ case 'Z':
+ if (!strncmp(s, tzname[0], len = strlen(tzname[0]))) {
+ tm->tm_isdst = 0;
+ s += len;
+ } else if (!strncmp(s, tzname[1], len=strlen(tzname[1]))) {
+ tm->tm_isdst = 1;
+ s += len;
+ } else {
+ /* FIXME: is this supposed to be an error? */
+ while ((*s|32)-'a' <= 'z'-'a') s++;
+ }
+ break;
case '%':
if (*s++ != '%') return 0;
break;
diff --git a/src/time/timer_create.c b/src/time/timer_create.c
index c5e40a19..9216b3ab 100644
--- a/src/time/timer_create.c
+++ b/src/time/timer_create.c
@@ -1,6 +1,8 @@
#include <time.h>
#include <setjmp.h>
+#include <limits.h>
#include "pthread_impl.h"
+#include "atomic.h"
struct ksigevent {
union sigval sigev_value;
@@ -31,30 +33,18 @@ static void cleanup_fromsig(void *p)
longjmp(p, 1);
}
-static void timer_handler(int sig, siginfo_t *si, void *ctx)
-{
-}
-
-static void install_handler()
-{
- struct sigaction sa = {
- .sa_sigaction = timer_handler,
- .sa_flags = SA_SIGINFO | SA_RESTART
- };
- __libc_sigaction(SIGTIMER, &sa, 0);
-}
-
static void *start(void *arg)
{
pthread_t self = __pthread_self();
struct start_args *args = arg;
- int id = self->timer_id;
jmp_buf jb;
void (*notify)(union sigval) = args->sev->sigev_notify_function;
union sigval val = args->sev->sigev_value;
pthread_barrier_wait(&args->b);
+ if (self->cancel)
+ return 0;
for (;;) {
siginfo_t si;
while (sigwaitinfo(SIGTIMER_SET, &si) < 0);
@@ -65,13 +55,13 @@ static void *start(void *arg)
}
if (self->timer_id < 0) break;
}
- __syscall(SYS_timer_delete, id);
+ __syscall(SYS_timer_delete, self->timer_id & INT_MAX);
return 0;
}
int timer_create(clockid_t clk, struct sigevent *restrict evp, timer_t *restrict res)
{
- static pthread_once_t once = PTHREAD_ONCE_INIT;
+ static volatile int init = 0;
pthread_t td;
pthread_attr_t attr;
int r;
@@ -83,11 +73,15 @@ int timer_create(clockid_t clk, struct sigevent *restrict evp, timer_t *restrict
switch (evp ? evp->sigev_notify : SIGEV_SIGNAL) {
case SIGEV_NONE:
case SIGEV_SIGNAL:
+ case SIGEV_THREAD_ID:
if (evp) {
ksev.sigev_value = evp->sigev_value;
ksev.sigev_signo = evp->sigev_signo;
ksev.sigev_notify = evp->sigev_notify;
- ksev.sigev_tid = 0;
+ if (evp->sigev_notify == SIGEV_THREAD_ID)
+ ksev.sigev_tid = evp->sigev_notify_thread_id;
+ else
+ ksev.sigev_tid = 0;
ksevp = &ksev;
}
if (syscall(SYS_timer_create, clk, ksevp, &timerid) < 0)
@@ -95,7 +89,11 @@ int timer_create(clockid_t clk, struct sigevent *restrict evp, timer_t *restrict
*res = (void *)(intptr_t)timerid;
break;
case SIGEV_THREAD:
- pthread_once(&once, install_handler);
+ if (!init) {
+ struct sigaction sa = { .sa_handler = SIG_DFL };
+ __libc_sigaction(SIGTIMER, &sa, 0);
+ a_store(&init, 1);
+ }
if (evp->sigev_notify_attributes)
attr = *evp->sigev_notify_attributes;
else
@@ -115,10 +113,12 @@ int timer_create(clockid_t clk, struct sigevent *restrict evp, timer_t *restrict
ksev.sigev_value.sival_ptr = 0;
ksev.sigev_signo = SIGTIMER;
- ksev.sigev_notify = 4; /* SIGEV_THREAD_ID */
+ ksev.sigev_notify = SIGEV_THREAD_ID;
ksev.sigev_tid = td->tid;
- if (syscall(SYS_timer_create, clk, &ksev, &timerid) < 0)
+ if (syscall(SYS_timer_create, clk, &ksev, &timerid) < 0) {
timerid = -1;
+ td->cancel = 1;
+ }
td->timer_id = timerid;
pthread_barrier_wait(&args.b);
if (timerid < 0) return -1;
diff --git a/src/time/timer_gettime.c b/src/time/timer_gettime.c
index ed6d8d65..21c9d32c 100644
--- a/src/time/timer_gettime.c
+++ b/src/time/timer_gettime.c
@@ -8,5 +8,21 @@ int timer_gettime(timer_t t, struct itimerspec *val)
pthread_t td = (void *)((uintptr_t)t << 1);
t = (void *)(uintptr_t)(td->timer_id & INT_MAX);
}
+#ifdef SYS_timer_gettime64
+ int r = -ENOSYS;
+ if (sizeof(time_t) > 4)
+ r = __syscall(SYS_timer_gettime64, t, val);
+ if (SYS_timer_gettime == SYS_timer_gettime64 || r!=-ENOSYS)
+ return __syscall_ret(r);
+ long val32[4];
+ r = __syscall(SYS_timer_gettime, t, val32);
+ if (!r) {
+ val->it_interval.tv_sec = val32[0];
+ val->it_interval.tv_nsec = val32[1];
+ val->it_value.tv_sec = val32[2];
+ val->it_value.tv_nsec = val32[3];
+ }
+ return __syscall_ret(r);
+#endif
return syscall(SYS_timer_gettime, t, val);
}
diff --git a/src/time/timer_settime.c b/src/time/timer_settime.c
index 62631aa4..373f00ce 100644
--- a/src/time/timer_settime.c
+++ b/src/time/timer_settime.c
@@ -2,11 +2,36 @@
#include <limits.h>
#include "pthread_impl.h"
+#define IS32BIT(x) !((x)+0x80000000ULL>>32)
+
int timer_settime(timer_t t, int flags, const struct itimerspec *restrict val, struct itimerspec *restrict old)
{
if ((intptr_t)t < 0) {
pthread_t td = (void *)((uintptr_t)t << 1);
t = (void *)(uintptr_t)(td->timer_id & INT_MAX);
}
+#ifdef SYS_timer_settime64
+ time_t is = val->it_interval.tv_sec, vs = val->it_value.tv_sec;
+ long ins = val->it_interval.tv_nsec, vns = val->it_value.tv_nsec;
+ int r = -ENOSYS;
+ if (SYS_timer_settime == SYS_timer_settime64
+ || !IS32BIT(is) || !IS32BIT(vs) || (sizeof(time_t)>4 && old))
+ r = __syscall(SYS_timer_settime64, t, flags,
+ ((long long[]){is, ins, vs, vns}), old);
+ if (SYS_timer_settime == SYS_timer_settime64 || r!=-ENOSYS)
+ return __syscall_ret(r);
+ if (!IS32BIT(is) || !IS32BIT(vs))
+ return __syscall_ret(-ENOTSUP);
+ long old32[4];
+ r = __syscall(SYS_timer_settime, t, flags,
+ ((long[]){is, ins, vs, vns}), old32);
+ if (!r && old) {
+ old->it_interval.tv_sec = old32[0];
+ old->it_interval.tv_nsec = old32[1];
+ old->it_value.tv_sec = old32[2];
+ old->it_value.tv_nsec = old32[3];
+ }
+ return __syscall_ret(r);
+#endif
return syscall(SYS_timer_settime, t, flags, val, old);
}