14acaec8fSDavid Xu /* 24acaec8fSDavid Xu * Copyright (c) 2006 David Xu <davidxu@freebsd.org> 34acaec8fSDavid Xu * All rights reserved. 44acaec8fSDavid Xu * 54acaec8fSDavid Xu * Redistribution and use in source and binary forms, with or without 64acaec8fSDavid Xu * modification, are permitted provided that the following conditions 74acaec8fSDavid Xu * are met: 84acaec8fSDavid Xu * 1. Redistributions of source code must retain the above copyright 94acaec8fSDavid Xu * notice unmodified, this list of conditions, and the following 104acaec8fSDavid Xu * disclaimer. 114acaec8fSDavid Xu * 2. Redistributions in binary form must reproduce the above copyright 124acaec8fSDavid Xu * notice, this list of conditions and the following disclaimer in the 134acaec8fSDavid Xu * documentation and/or other materials provided with the distribution. 144acaec8fSDavid Xu * 154acaec8fSDavid Xu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 164acaec8fSDavid Xu * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 174acaec8fSDavid Xu * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 184acaec8fSDavid Xu * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 194acaec8fSDavid Xu * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 204acaec8fSDavid Xu * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 214acaec8fSDavid Xu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 224acaec8fSDavid Xu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 234acaec8fSDavid Xu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 244acaec8fSDavid Xu * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 254acaec8fSDavid Xu * 264acaec8fSDavid Xu * $FreeBSD$ 274acaec8fSDavid Xu * 284acaec8fSDavid Xu */ 294acaec8fSDavid Xu 304acaec8fSDavid Xu #include <sys/cdefs.h> 314acaec8fSDavid Xu #include <sys/types.h> 324acaec8fSDavid Xu #include <sys/syscall.h> 334acaec8fSDavid Xu 344acaec8fSDavid Xu #include "namespace.h" 354acaec8fSDavid Xu #include <errno.h> 364acaec8fSDavid Xu #include <pthread.h> 374acaec8fSDavid Xu #include <stddef.h> 384acaec8fSDavid Xu #include <signal.h> 394acaec8fSDavid Xu #include <stdlib.h> 404acaec8fSDavid Xu #include <time.h> 414acaec8fSDavid Xu #include <unistd.h> 424acaec8fSDavid Xu #include "sigev_thread.h" 434acaec8fSDavid Xu #include "un-namespace.h" 444acaec8fSDavid Xu 454acaec8fSDavid Xu extern int __sys_ktimer_create(clockid_t, struct sigevent *__restrict, 464acaec8fSDavid Xu int *__restrict); 474acaec8fSDavid Xu extern int __sys_ktimer_delete(int); 484acaec8fSDavid Xu extern int __sys_ktimer_gettime(int, struct itimerspec *); 494acaec8fSDavid Xu extern int __sys_ktimer_getoverrun(int); 504acaec8fSDavid Xu extern int __sys_ktimer_settime(int, int, 514acaec8fSDavid Xu const struct itimerspec *__restrict, struct itimerspec *__restrict); 524acaec8fSDavid Xu 534acaec8fSDavid Xu struct __timer { 544acaec8fSDavid Xu int oshandle; 554acaec8fSDavid Xu struct sigev_node *node; 564acaec8fSDavid Xu }; 574acaec8fSDavid Xu 584acaec8fSDavid Xu __weak_reference(__timer_create, timer_create); 594acaec8fSDavid Xu __weak_reference(__timer_create, _timer_create); 604acaec8fSDavid Xu __weak_reference(__timer_delete, timer_delete); 614acaec8fSDavid Xu __weak_reference(__timer_delete, _timer_delete); 624acaec8fSDavid Xu __weak_reference(__timer_gettime, timer_gettime); 634acaec8fSDavid Xu __weak_reference(__timer_gettime, _timer_gettime); 644acaec8fSDavid Xu __weak_reference(__timer_settime, timer_settime); 654acaec8fSDavid Xu __weak_reference(__timer_settime, _timer_settime); 664acaec8fSDavid Xu __weak_reference(__timer_getoverrun, timer_getoverrun); 674acaec8fSDavid Xu __weak_reference(__timer_getoverrun, _timer_getoverrun); 684acaec8fSDavid Xu 694acaec8fSDavid Xu typedef void (*timer_func)(union sigval val, int timerid, int overrun); 704acaec8fSDavid Xu 714acaec8fSDavid Xu static void 724acaec8fSDavid Xu timer_dispatch(struct sigev_node *sn, siginfo_t *si) 734acaec8fSDavid Xu { 744acaec8fSDavid Xu timer_func f = sn->sn_func; 754acaec8fSDavid Xu 764acaec8fSDavid Xu /* I want to avoid expired notification. */ 774acaec8fSDavid Xu if (si->si_value.sival_int == sn->sn_gen) 784acaec8fSDavid Xu f(sn->sn_value, si->si_timerid, si->si_overrun); 794acaec8fSDavid Xu } 804acaec8fSDavid Xu 814acaec8fSDavid Xu int 824acaec8fSDavid Xu __timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid) 834acaec8fSDavid Xu { 844acaec8fSDavid Xu struct __timer *timer; 854acaec8fSDavid Xu struct sigevent ev; 864acaec8fSDavid Xu struct sigev_node *sn; 874acaec8fSDavid Xu int ret, err; 884acaec8fSDavid Xu 894acaec8fSDavid Xu timer = malloc(sizeof(struct __timer)); 904acaec8fSDavid Xu if (timer == NULL) 914acaec8fSDavid Xu return (-1); 924acaec8fSDavid Xu 934acaec8fSDavid Xu if (evp == NULL || evp->sigev_notify != SIGEV_THREAD) { 944acaec8fSDavid Xu ret = __sys_ktimer_create(clockid, evp, &timer->oshandle); 954acaec8fSDavid Xu if (ret == -1) { 964acaec8fSDavid Xu err = errno; 974acaec8fSDavid Xu free(timer); 984acaec8fSDavid Xu errno = err; 994acaec8fSDavid Xu return (ret); 1004acaec8fSDavid Xu } 1014acaec8fSDavid Xu timer->node = NULL; 1024acaec8fSDavid Xu *timerid = timer; 1034acaec8fSDavid Xu return (0); 1044acaec8fSDavid Xu } 1054acaec8fSDavid Xu 1064acaec8fSDavid Xu if (__sigev_check_init()) { 1074acaec8fSDavid Xu errno = EINVAL; 1084acaec8fSDavid Xu return (-1); 1094acaec8fSDavid Xu } 1104acaec8fSDavid Xu 1114acaec8fSDavid Xu sn = __sigev_alloc(SI_TIMER, evp); 1124acaec8fSDavid Xu if (sn == NULL) { 1134acaec8fSDavid Xu errno = EAGAIN; 1144acaec8fSDavid Xu return (-1); 1154acaec8fSDavid Xu } 1164acaec8fSDavid Xu 1174acaec8fSDavid Xu __sigev_get_sigevent(sn, &ev, sn->sn_gen); 1184acaec8fSDavid Xu ret = __sys_ktimer_create(clockid, &ev, &timer->oshandle); 1194acaec8fSDavid Xu if (ret != 0) { 1204acaec8fSDavid Xu err = errno; 1214acaec8fSDavid Xu __sigev_free(sn); 1224acaec8fSDavid Xu free(timer); 1234acaec8fSDavid Xu errno = err; 1244acaec8fSDavid Xu return (-1); 1254acaec8fSDavid Xu } 1264acaec8fSDavid Xu sn->sn_dispatch = timer_dispatch; 1274acaec8fSDavid Xu sn->sn_id = timer->oshandle; 1284acaec8fSDavid Xu __sigev_list_lock(); 1294acaec8fSDavid Xu __sigev_register(sn); 1304acaec8fSDavid Xu __sigev_list_unlock(); 1314acaec8fSDavid Xu *timerid = timer; 1324acaec8fSDavid Xu return (0); 1334acaec8fSDavid Xu } 1344acaec8fSDavid Xu 1354acaec8fSDavid Xu int 1364acaec8fSDavid Xu __timer_delete(timer_t timerid) 1374acaec8fSDavid Xu { 1384acaec8fSDavid Xu int ret, err; 1394acaec8fSDavid Xu 1404acaec8fSDavid Xu if (timerid->node != NULL) { 1414acaec8fSDavid Xu __sigev_list_lock(); 1424acaec8fSDavid Xu __sigev_delete_node(timerid->node); 1434acaec8fSDavid Xu __sigev_list_unlock(); 1444acaec8fSDavid Xu } 1454acaec8fSDavid Xu ret = __sys_ktimer_delete(timerid->oshandle); 1464acaec8fSDavid Xu err = errno; 1474acaec8fSDavid Xu free(timerid); 1484acaec8fSDavid Xu errno = err; 1494acaec8fSDavid Xu return (ret); 1504acaec8fSDavid Xu } 1514acaec8fSDavid Xu 1524acaec8fSDavid Xu int 1534acaec8fSDavid Xu __timer_gettime(timer_t timerid, struct itimerspec *value) 1544acaec8fSDavid Xu { 1554acaec8fSDavid Xu 1564acaec8fSDavid Xu return __sys_ktimer_gettime(timerid->oshandle, value); 1574acaec8fSDavid Xu } 1584acaec8fSDavid Xu 1594acaec8fSDavid Xu int 1604acaec8fSDavid Xu __timer_getoverrun(timer_t timerid) 1614acaec8fSDavid Xu { 1624acaec8fSDavid Xu 1634acaec8fSDavid Xu return __sys_ktimer_getoverrun(timerid->oshandle); 1644acaec8fSDavid Xu } 1654acaec8fSDavid Xu 1664acaec8fSDavid Xu int 1674acaec8fSDavid Xu __timer_settime(timer_t timerid, int flags, 1684acaec8fSDavid Xu const struct itimerspec *__restrict value, 1694acaec8fSDavid Xu struct itimerspec *__restrict ovalue) 1704acaec8fSDavid Xu { 1714acaec8fSDavid Xu 1724acaec8fSDavid Xu return __sys_ktimer_settime(timerid->oshandle, 1734acaec8fSDavid Xu flags, value, ovalue); 1744acaec8fSDavid Xu } 1754acaec8fSDavid Xu 1764acaec8fSDavid Xu int 1774acaec8fSDavid Xu __timer_oshandle(timer_t timerid) 1784acaec8fSDavid Xu { 1794acaec8fSDavid Xu 1804acaec8fSDavid Xu return (timerid->oshandle); 1814acaec8fSDavid Xu } 182