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