19931033bSDmitry Chagin/*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 39931033bSDmitry Chagin * 49931033bSDmitry Chagin * Copyright (c) 2012 Konstantin Belousov <kib@FreeBSD.org> 59931033bSDmitry Chagin * Copyright (c) 2021 Dmitry Chagin <dchagin@FreeBSD.org> 69931033bSDmitry Chagin * 79931033bSDmitry Chagin * Redistribution and use in source and binary forms, with or without 89931033bSDmitry Chagin * modification, are permitted provided that the following conditions 99931033bSDmitry Chagin * are met: 109931033bSDmitry Chagin * 1. Redistributions of source code must retain the above copyright 119931033bSDmitry Chagin * notice, this list of conditions and the following disclaimer. 129931033bSDmitry Chagin * 2. Redistributions in binary form must reproduce the above copyright 139931033bSDmitry Chagin * notice, this list of conditions and the following disclaimer in the 149931033bSDmitry Chagin * documentation and/or other materials provided with the distribution. 159931033bSDmitry Chagin * 169931033bSDmitry Chagin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 179931033bSDmitry Chagin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 189931033bSDmitry Chagin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 199931033bSDmitry Chagin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 209931033bSDmitry Chagin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 219931033bSDmitry Chagin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 229931033bSDmitry Chagin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 239931033bSDmitry Chagin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 249931033bSDmitry Chagin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 259931033bSDmitry Chagin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 269931033bSDmitry Chagin * SUCH DAMAGE. 279931033bSDmitry Chagin */ 289931033bSDmitry Chagin 29*a129642cSDmitry Chagin#if defined(__aarch64__) 30*a129642cSDmitry Chagin#define __VDSO_PREFIX __kernel 31*a129642cSDmitry Chagin#else 32*a129642cSDmitry Chagin#define __VDSO_PREFIX __vdso 33*a129642cSDmitry Chagin#endif 34*a129642cSDmitry Chagin 35*a129642cSDmitry Chagin#define __vdsoN(x) __CONCAT(__CONCAT(__VDSO_PREFIX,_),x) 36*a129642cSDmitry Chagin 37f3379401SDmitry Chaginstatic int 38f3379401SDmitry Chaginfls(int mask) 39f3379401SDmitry Chagin{ 40f3379401SDmitry Chagin 41f3379401SDmitry Chagin if (mask == 0) 42f3379401SDmitry Chagin return (0); 43f3379401SDmitry Chagin return ((__builtin_clz(mask) ^ 0x1f) + 1); 44f3379401SDmitry Chagin} 45f3379401SDmitry Chagin 46f3379401SDmitry Chagin#ifdef _LP64 47f3379401SDmitry Chaginstatic int 48c6df2176SDmitry Chaginflsl(long mask) 49f3379401SDmitry Chagin{ 50f3379401SDmitry Chagin int bit; 51f3379401SDmitry Chagin 52f3379401SDmitry Chagin if (mask == 0) 53f3379401SDmitry Chagin return (0); 54c6df2176SDmitry Chagin for (bit = 1; mask != 1; bit++) 55f3379401SDmitry Chagin mask = (unsigned long)mask >> 1; 56f3379401SDmitry Chagin return (bit); 57f3379401SDmitry Chagin} 58f3379401SDmitry Chagin#else 59f3379401SDmitry Chaginstatic int 60c6df2176SDmitry Chaginflsll(long long mask) 61f3379401SDmitry Chagin{ 62f3379401SDmitry Chagin int bit; 63f3379401SDmitry Chagin 64f3379401SDmitry Chagin if (mask == 0) 65f3379401SDmitry Chagin return (0); 66c6df2176SDmitry Chagin for (bit = 1; mask != 1; bit++) 67f3379401SDmitry Chagin mask = (unsigned long long)mask >> 1; 68f3379401SDmitry Chagin return (bit); 69f3379401SDmitry Chagin} 70f3379401SDmitry Chagin#endif 719931033bSDmitry Chagin 729931033bSDmitry Chaginstatic int 739931033bSDmitry Chagin__vdso_native_to_linux_timespec(struct l_timespec *lts, 749931033bSDmitry Chagin struct timespec *nts) 759931033bSDmitry Chagin{ 769931033bSDmitry Chagin 779931033bSDmitry Chagin#ifdef COMPAT_LINUX32 789931033bSDmitry Chagin if (nts->tv_sec > INT_MAX || nts->tv_sec < INT_MIN) 799931033bSDmitry Chagin return (LINUX_EOVERFLOW); 809931033bSDmitry Chagin#endif 819931033bSDmitry Chagin lts->tv_sec = nts->tv_sec; 829931033bSDmitry Chagin lts->tv_nsec = nts->tv_nsec; 839931033bSDmitry Chagin return (0); 849931033bSDmitry Chagin} 859931033bSDmitry Chagin 869931033bSDmitry Chaginstatic int 879931033bSDmitry Chagin__vdso_native_to_linux_timeval(l_timeval *ltv, 889931033bSDmitry Chagin struct timeval *ntv) 899931033bSDmitry Chagin{ 909931033bSDmitry Chagin 919931033bSDmitry Chagin#ifdef COMPAT_LINUX32 929931033bSDmitry Chagin if (ntv->tv_sec > INT_MAX || ntv->tv_sec < INT_MIN) 939931033bSDmitry Chagin return (LINUX_EOVERFLOW); 949931033bSDmitry Chagin#endif 959931033bSDmitry Chagin ltv->tv_sec = ntv->tv_sec; 969931033bSDmitry Chagin ltv->tv_usec = ntv->tv_usec; 979931033bSDmitry Chagin return (0); 989931033bSDmitry Chagin} 999931033bSDmitry Chagin 1009931033bSDmitry Chagin 1019931033bSDmitry Chagin#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32)) 1029931033bSDmitry Chaginstatic int 1039931033bSDmitry Chagin__vdso_native_to_linux_timespec64(struct l_timespec64 *lts, 1049931033bSDmitry Chagin struct timespec *nts) 1059931033bSDmitry Chagin{ 1069931033bSDmitry Chagin 1079931033bSDmitry Chagin lts->tv_sec = nts->tv_sec; 1089931033bSDmitry Chagin lts->tv_nsec = nts->tv_nsec; 1099931033bSDmitry Chagin return (0); 1109931033bSDmitry Chagin} 1119931033bSDmitry Chagin#endif 1129931033bSDmitry Chagin 1139931033bSDmitry Chaginstatic int 1149931033bSDmitry Chagin__vdso_linux_to_native_clockid(clockid_t *n, clockid_t l) 1159931033bSDmitry Chagin{ 1169931033bSDmitry Chagin 1179931033bSDmitry Chagin switch (l) { 1189931033bSDmitry Chagin case LINUX_CLOCK_REALTIME: 1199931033bSDmitry Chagin *n = CLOCK_REALTIME; 1209931033bSDmitry Chagin break; 1219931033bSDmitry Chagin case LINUX_CLOCK_MONOTONIC: 1229931033bSDmitry Chagin *n = CLOCK_MONOTONIC; 1239931033bSDmitry Chagin break; 1249931033bSDmitry Chagin case LINUX_CLOCK_REALTIME_COARSE: 1259931033bSDmitry Chagin *n = CLOCK_REALTIME_FAST; 1269931033bSDmitry Chagin break; 1279931033bSDmitry Chagin case LINUX_CLOCK_MONOTONIC_COARSE: 1289931033bSDmitry Chagin case LINUX_CLOCK_MONOTONIC_RAW: 1299931033bSDmitry Chagin *n = CLOCK_MONOTONIC_FAST; 1309931033bSDmitry Chagin break; 1319931033bSDmitry Chagin case LINUX_CLOCK_BOOTTIME: 1329931033bSDmitry Chagin *n = CLOCK_UPTIME; 1339931033bSDmitry Chagin break; 1349931033bSDmitry Chagin default: 1359931033bSDmitry Chagin return (LINUX_EINVAL); 1369931033bSDmitry Chagin } 1379931033bSDmitry Chagin return (0); 1389931033bSDmitry Chagin} 1399931033bSDmitry Chagin 1409931033bSDmitry Chagin/* 1419931033bSDmitry Chagin * The code below adapted from 1429931033bSDmitry Chagin * lib/libc/sys/__vdso_gettimeofday.c 1439931033bSDmitry Chagin */ 1449931033bSDmitry Chagin 1459931033bSDmitry Chaginstatic inline void 1469931033bSDmitry Chagin__vdso_gettimekeep(struct vdso_timekeep **tk) 1479931033bSDmitry Chagin{ 1489931033bSDmitry Chagin 1499931033bSDmitry Chagin *tk = (struct vdso_timekeep *)kern_timekeep_base; 1509931033bSDmitry Chagin} 1519931033bSDmitry Chagin 1529931033bSDmitry Chaginstatic int 1539931033bSDmitry Chagintc_delta(const struct vdso_timehands *th, u_int *delta) 1549931033bSDmitry Chagin{ 1559931033bSDmitry Chagin int error; 1569931033bSDmitry Chagin u_int tc; 1579931033bSDmitry Chagin 1589931033bSDmitry Chagin error = __vdso_gettc(th, &tc); 1599931033bSDmitry Chagin if (error == 0) 1609931033bSDmitry Chagin *delta = (tc - th->th_offset_count) & th->th_counter_mask; 1619931033bSDmitry Chagin return (error); 1629931033bSDmitry Chagin} 1639931033bSDmitry Chagin 1649931033bSDmitry Chagin/* 1659931033bSDmitry Chagin * Calculate the absolute or boot-relative time from the 1669931033bSDmitry Chagin * machine-specific fast timecounter and the published timehands 1679931033bSDmitry Chagin * structure read from the shared page. 1689931033bSDmitry Chagin * 1699931033bSDmitry Chagin * The lockless reading scheme is similar to the one used to read the 1709931033bSDmitry Chagin * in-kernel timehands, see sys/kern/kern_tc.c:binuptime(). This code 1719931033bSDmitry Chagin * is based on the kernel implementation. 1729931033bSDmitry Chagin */ 1739931033bSDmitry Chaginstatic int 1749931033bSDmitry Chaginfreebsd_binuptime(struct bintime *bt, struct vdso_timekeep *tk, bool abs) 1759931033bSDmitry Chagin{ 1769931033bSDmitry Chagin struct vdso_timehands *th; 1779931033bSDmitry Chagin uint32_t curr, gen; 1789931033bSDmitry Chagin uint64_t scale, x; 1799931033bSDmitry Chagin u_int delta, scale_bits; 1809931033bSDmitry Chagin int error; 1819931033bSDmitry Chagin 1829931033bSDmitry Chagin do { 1839931033bSDmitry Chagin if (!tk->tk_enabled) 1849931033bSDmitry Chagin return (ENOSYS); 1859931033bSDmitry Chagin 1869931033bSDmitry Chagin curr = atomic_load_acq_32(&tk->tk_current); 1879931033bSDmitry Chagin th = &tk->tk_th[curr]; 1889931033bSDmitry Chagin gen = atomic_load_acq_32(&th->th_gen); 1899931033bSDmitry Chagin *bt = th->th_offset; 1909931033bSDmitry Chagin error = tc_delta(th, &delta); 1919931033bSDmitry Chagin if (error == EAGAIN) 1929931033bSDmitry Chagin continue; 1939931033bSDmitry Chagin if (error != 0) 1949931033bSDmitry Chagin return (error); 1959931033bSDmitry Chagin scale = th->th_scale; 1969931033bSDmitry Chagin#ifdef _LP64 197c6df2176SDmitry Chagin scale_bits = flsl(scale); 1989931033bSDmitry Chagin#else 199c6df2176SDmitry Chagin scale_bits = flsll(scale); 2009931033bSDmitry Chagin#endif 2019931033bSDmitry Chagin if (__predict_false(scale_bits + fls(delta) > 63)) { 2029931033bSDmitry Chagin x = (scale >> 32) * delta; 2039931033bSDmitry Chagin scale &= 0xffffffff; 2049931033bSDmitry Chagin bt->sec += x >> 32; 2059931033bSDmitry Chagin bintime_addx(bt, x << 32); 2069931033bSDmitry Chagin } 2079931033bSDmitry Chagin bintime_addx(bt, scale * delta); 2089931033bSDmitry Chagin if (abs) 2099931033bSDmitry Chagin bintime_add(bt, &th->th_boottime); 2109931033bSDmitry Chagin 2119931033bSDmitry Chagin /* 2129931033bSDmitry Chagin * Ensure that the load of th_offset is completed 2139931033bSDmitry Chagin * before the load of th_gen. 2149931033bSDmitry Chagin */ 2159931033bSDmitry Chagin atomic_thread_fence_acq(); 2169931033bSDmitry Chagin } while (curr != tk->tk_current || gen == 0 || gen != th->th_gen); 2179931033bSDmitry Chagin return (0); 2189931033bSDmitry Chagin} 2199931033bSDmitry Chagin 2209931033bSDmitry Chaginstatic int 2219931033bSDmitry Chaginfreebsd_getnanouptime(struct bintime *bt, struct vdso_timekeep *tk) 2229931033bSDmitry Chagin{ 2239931033bSDmitry Chagin struct vdso_timehands *th; 2249931033bSDmitry Chagin uint32_t curr, gen; 2259931033bSDmitry Chagin 2269931033bSDmitry Chagin do { 2279931033bSDmitry Chagin if (!tk->tk_enabled) 2289931033bSDmitry Chagin return (ENOSYS); 2299931033bSDmitry Chagin 2309931033bSDmitry Chagin curr = atomic_load_acq_32(&tk->tk_current); 2319931033bSDmitry Chagin th = &tk->tk_th[curr]; 2329931033bSDmitry Chagin gen = atomic_load_acq_32(&th->th_gen); 2339931033bSDmitry Chagin *bt = th->th_offset; 2349931033bSDmitry Chagin 2359931033bSDmitry Chagin /* 2369931033bSDmitry Chagin * Ensure that the load of th_offset is completed 2379931033bSDmitry Chagin * before the load of th_gen. 2389931033bSDmitry Chagin */ 2399931033bSDmitry Chagin atomic_thread_fence_acq(); 2409931033bSDmitry Chagin } while (curr != tk->tk_current || gen == 0 || gen != th->th_gen); 2419931033bSDmitry Chagin return (0); 2429931033bSDmitry Chagin} 2439931033bSDmitry Chagin 2449931033bSDmitry Chaginstatic int 2459931033bSDmitry Chaginfreebsd_gettimeofday(struct timeval *tv, struct timezone *tz) 2469931033bSDmitry Chagin{ 2479931033bSDmitry Chagin struct vdso_timekeep *tk; 2489931033bSDmitry Chagin struct bintime bt; 2499931033bSDmitry Chagin int error; 2509931033bSDmitry Chagin 2519931033bSDmitry Chagin if (tz != NULL) 2529931033bSDmitry Chagin return (ENOSYS); 2539931033bSDmitry Chagin __vdso_gettimekeep(&tk); 2549931033bSDmitry Chagin if (tk == NULL) 2559931033bSDmitry Chagin return (ENOSYS); 2569931033bSDmitry Chagin if (tk->tk_ver != VDSO_TK_VER_CURR) 2579931033bSDmitry Chagin return (ENOSYS); 2589931033bSDmitry Chagin error = freebsd_binuptime(&bt, tk, true); 2599931033bSDmitry Chagin if (error == 0) 2609931033bSDmitry Chagin bintime2timeval(&bt, tv); 2619931033bSDmitry Chagin return (error); 2629931033bSDmitry Chagin} 2639931033bSDmitry Chagin 2649931033bSDmitry Chaginstatic int 2659931033bSDmitry Chaginfreebsd_clock_gettime(clockid_t clock_id, struct timespec *ts) 2669931033bSDmitry Chagin{ 2679931033bSDmitry Chagin struct vdso_timekeep *tk; 2689931033bSDmitry Chagin struct bintime bt; 2699931033bSDmitry Chagin int error; 2709931033bSDmitry Chagin 2719931033bSDmitry Chagin __vdso_gettimekeep(&tk); 2729931033bSDmitry Chagin if (tk == NULL) 2739931033bSDmitry Chagin return (ENOSYS); 2749931033bSDmitry Chagin if (tk->tk_ver != VDSO_TK_VER_CURR) 2759931033bSDmitry Chagin return (ENOSYS); 2769931033bSDmitry Chagin switch (clock_id) { 2779931033bSDmitry Chagin case CLOCK_REALTIME: 2789931033bSDmitry Chagin case CLOCK_REALTIME_PRECISE: 2799931033bSDmitry Chagin case CLOCK_REALTIME_FAST: 2809931033bSDmitry Chagin error = freebsd_binuptime(&bt, tk, true); 2819931033bSDmitry Chagin break; 2829931033bSDmitry Chagin case CLOCK_MONOTONIC: 2839931033bSDmitry Chagin case CLOCK_MONOTONIC_PRECISE: 2849931033bSDmitry Chagin case CLOCK_UPTIME: 2859931033bSDmitry Chagin case CLOCK_UPTIME_PRECISE: 2869931033bSDmitry Chagin error = freebsd_binuptime(&bt, tk, false); 2879931033bSDmitry Chagin break; 2889931033bSDmitry Chagin case CLOCK_MONOTONIC_FAST: 2899931033bSDmitry Chagin case CLOCK_UPTIME_FAST: 2909931033bSDmitry Chagin error = freebsd_getnanouptime(&bt, tk); 2919931033bSDmitry Chagin break; 2929931033bSDmitry Chagin default: 2939931033bSDmitry Chagin error = ENOSYS; 2949931033bSDmitry Chagin break; 2959931033bSDmitry Chagin } 2969931033bSDmitry Chagin if (error == 0) 2979931033bSDmitry Chagin bintime2timespec(&bt, ts); 2989931033bSDmitry Chagin return (error); 2999931033bSDmitry Chagin} 3009931033bSDmitry Chagin 3019931033bSDmitry Chagin/* 3029931033bSDmitry Chagin * Linux vDSO interfaces 3039931033bSDmitry Chagin * 3049931033bSDmitry Chagin */ 3059931033bSDmitry Chaginint 306*a129642cSDmitry Chagin__vdsoN(clock_gettime)(clockid_t clock_id, struct l_timespec *lts) 3079931033bSDmitry Chagin{ 3089931033bSDmitry Chagin struct timespec ts; 3099931033bSDmitry Chagin clockid_t which; 3109931033bSDmitry Chagin int error; 3119931033bSDmitry Chagin 3129931033bSDmitry Chagin error = __vdso_linux_to_native_clockid(&which, clock_id); 3139931033bSDmitry Chagin if (error != 0) 3149931033bSDmitry Chagin return (__vdso_clock_gettime_fallback(clock_id, lts)); 3159931033bSDmitry Chagin error = freebsd_clock_gettime(which, &ts); 3169931033bSDmitry Chagin if (error == 0) 3179931033bSDmitry Chagin return (-__vdso_native_to_linux_timespec(lts, &ts)); 3189931033bSDmitry Chagin else 3199931033bSDmitry Chagin return (__vdso_clock_gettime_fallback(clock_id, lts)); 3209931033bSDmitry Chagin} 3219931033bSDmitry Chagin 3229931033bSDmitry Chaginint 323*a129642cSDmitry Chagin__vdsoN(gettimeofday)(l_timeval *ltv, struct timezone *tz) 3249931033bSDmitry Chagin{ 3259931033bSDmitry Chagin struct timeval tv; 3269931033bSDmitry Chagin int error; 3279931033bSDmitry Chagin 3289931033bSDmitry Chagin error = freebsd_gettimeofday(&tv, tz); 3299931033bSDmitry Chagin if (error != 0) 3309931033bSDmitry Chagin return (__vdso_gettimeofday_fallback(ltv, tz)); 3319931033bSDmitry Chagin return (-__vdso_native_to_linux_timeval(ltv, &tv)); 3329931033bSDmitry Chagin} 3339931033bSDmitry Chagin 3349931033bSDmitry Chaginint 335*a129642cSDmitry Chagin__vdsoN(clock_getres)(clockid_t clock_id, struct l_timespec *lts) 3369931033bSDmitry Chagin{ 3379931033bSDmitry Chagin 3389931033bSDmitry Chagin return (__vdso_clock_getres_fallback(clock_id, lts)); 3399931033bSDmitry Chagin} 3409931033bSDmitry Chagin 3419931033bSDmitry Chagin#if defined(__i386__) || defined(COMPAT_LINUX32) 3429931033bSDmitry Chaginint 3439931033bSDmitry Chagin__vdso_clock_gettime64(clockid_t clock_id, struct l_timespec64 *lts) 3449931033bSDmitry Chagin{ 3459931033bSDmitry Chagin struct timespec ts; 3469931033bSDmitry Chagin clockid_t which; 3479931033bSDmitry Chagin int error; 3489931033bSDmitry Chagin 3499931033bSDmitry Chagin error = __vdso_linux_to_native_clockid(&which, clock_id); 3509931033bSDmitry Chagin if (error != 0) 3519931033bSDmitry Chagin return (__vdso_clock_gettime64_fallback(clock_id, lts)); 3529931033bSDmitry Chagin error = freebsd_clock_gettime(which, &ts); 3539931033bSDmitry Chagin if (error == 0) 3549931033bSDmitry Chagin return(-__vdso_native_to_linux_timespec64(lts, &ts)); 3559931033bSDmitry Chagin else 3569931033bSDmitry Chagin return(__vdso_clock_gettime64_fallback(clock_id, lts)); 3579931033bSDmitry Chagin} 3589931033bSDmitry Chagin 3599931033bSDmitry Chaginint clock_gettime64(clockid_t clock_id, struct l_timespec64 *lts) 3609931033bSDmitry Chagin __attribute__((weak, alias("__vdso_clock_gettime64"))); 3619931033bSDmitry Chagin#endif 3629931033bSDmitry Chagin 3635a6a4fb2SDmitry Chagin#if defined(__i386__) || defined(__amd64__) 3649931033bSDmitry Chaginint 3659931033bSDmitry Chagin__vdso_getcpu(uint32_t *cpu, uint32_t *node, void *cache) 3669931033bSDmitry Chagin{ 3675a6a4fb2SDmitry Chagin int ret; 3689931033bSDmitry Chagin 3695a6a4fb2SDmitry Chagin if (node != NULL) 3709931033bSDmitry Chagin return (__vdso_getcpu_fallback(cpu, node, cache)); 3715a6a4fb2SDmitry Chagin ret = __vdso_getcpu_try(); 3725a6a4fb2SDmitry Chagin if (ret < 0) 3735a6a4fb2SDmitry Chagin return (__vdso_getcpu_fallback(cpu, node, cache)); 3745a6a4fb2SDmitry Chagin *cpu = ret; 3755a6a4fb2SDmitry Chagin return (0); 3769931033bSDmitry Chagin} 3779931033bSDmitry Chagin#endif 3789931033bSDmitry Chagin 3799931033bSDmitry Chagin#if defined(__i386__) || defined(__amd64__) 3809931033bSDmitry Chaginint 3819931033bSDmitry Chagin__vdso_time(long *tm) 3829931033bSDmitry Chagin{ 38342317e64SDmitry Chagin struct timeval tv; 38442317e64SDmitry Chagin int error; 3859931033bSDmitry Chagin 38642317e64SDmitry Chagin error = freebsd_gettimeofday(&tv, NULL); 38742317e64SDmitry Chagin if (error != 0) 3889931033bSDmitry Chagin return (__vdso_time_fallback(tm)); 38942317e64SDmitry Chagin if (tm != NULL) 39042317e64SDmitry Chagin *tm = tv.tv_sec; 39142317e64SDmitry Chagin return (tv.tv_sec); 3929931033bSDmitry Chagin} 3939931033bSDmitry Chagin#endif 394