xref: /freebsd/lib/librt/timer.c (revision 5e53a4f9)
15e53a4f9SPedro F. Giffuni /*-
25e53a4f9SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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  * $FreeBSD$
294acaec8fSDavid Xu  *
304acaec8fSDavid Xu  */
314acaec8fSDavid Xu 
324acaec8fSDavid Xu #include <sys/cdefs.h>
334acaec8fSDavid Xu #include <sys/types.h>
344acaec8fSDavid Xu #include <sys/syscall.h>
354acaec8fSDavid Xu 
364acaec8fSDavid Xu #include "namespace.h"
374acaec8fSDavid Xu #include <errno.h>
384acaec8fSDavid Xu #include <stddef.h>
394acaec8fSDavid Xu #include <signal.h>
404acaec8fSDavid Xu #include <stdlib.h>
414acaec8fSDavid Xu #include <time.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 
696348ace8SDavid Xu typedef void (*timer_func)(union sigval val, int overrun);
704acaec8fSDavid Xu 
714acaec8fSDavid Xu static void
726348ace8SDavid Xu timer_dispatch(struct sigev_node *sn)
734acaec8fSDavid Xu {
744acaec8fSDavid Xu 	timer_func f = sn->sn_func;
754acaec8fSDavid Xu 
764acaec8fSDavid Xu 	/* I want to avoid expired notification. */
776348ace8SDavid Xu 	if (sn->sn_info.si_value.sival_int == sn->sn_gen)
786348ace8SDavid Xu 		f(sn->sn_value, sn->sn_info.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()) {
107289317daSKonstantin Belousov 		free(timer);
1084acaec8fSDavid Xu 		errno = EINVAL;
1094acaec8fSDavid Xu 		return (-1);
1104acaec8fSDavid Xu 	}
1114acaec8fSDavid Xu 
1126348ace8SDavid Xu 	sn = __sigev_alloc(SI_TIMER, evp, NULL, 0);
1134acaec8fSDavid Xu 	if (sn == NULL) {
114289317daSKonstantin Belousov 		free(timer);
1154acaec8fSDavid Xu 		errno = EAGAIN;
1164acaec8fSDavid Xu 		return (-1);
1174acaec8fSDavid Xu 	}
1184acaec8fSDavid Xu 
1194acaec8fSDavid Xu 	__sigev_get_sigevent(sn, &ev, sn->sn_gen);
1204acaec8fSDavid Xu 	ret = __sys_ktimer_create(clockid, &ev, &timer->oshandle);
1214acaec8fSDavid Xu 	if (ret != 0) {
1224acaec8fSDavid Xu 		err = errno;
1234acaec8fSDavid Xu 		__sigev_free(sn);
1244acaec8fSDavid Xu 		free(timer);
1254acaec8fSDavid Xu 		errno = err;
1264acaec8fSDavid Xu 		return (-1);
1274acaec8fSDavid Xu 	}
12837fe7164SDavid Xu 	sn->sn_flags |= SNF_SYNC;
1294acaec8fSDavid Xu 	sn->sn_dispatch = timer_dispatch;
1304acaec8fSDavid Xu 	sn->sn_id = timer->oshandle;
131c402cadcSDavid Xu 	timer->node = sn;
1324acaec8fSDavid Xu 	__sigev_list_lock();
1334acaec8fSDavid Xu 	__sigev_register(sn);
1344acaec8fSDavid Xu 	__sigev_list_unlock();
1354acaec8fSDavid Xu 	*timerid = timer;
1364acaec8fSDavid Xu 	return (0);
1374acaec8fSDavid Xu }
1384acaec8fSDavid Xu 
1394acaec8fSDavid Xu int
1404acaec8fSDavid Xu __timer_delete(timer_t timerid)
1414acaec8fSDavid Xu {
1424acaec8fSDavid Xu 	int ret, err;
1434acaec8fSDavid Xu 
1444acaec8fSDavid Xu 	if (timerid->node != NULL) {
1454acaec8fSDavid Xu 		__sigev_list_lock();
1464acaec8fSDavid Xu 		__sigev_delete_node(timerid->node);
1474acaec8fSDavid Xu 		__sigev_list_unlock();
1484acaec8fSDavid Xu 	}
1494acaec8fSDavid Xu 	ret = __sys_ktimer_delete(timerid->oshandle);
1504acaec8fSDavid Xu 	err = errno;
1514acaec8fSDavid Xu 	free(timerid);
1524acaec8fSDavid Xu 	errno = err;
1534acaec8fSDavid Xu 	return (ret);
1544acaec8fSDavid Xu }
1554acaec8fSDavid Xu 
1564acaec8fSDavid Xu int
1574acaec8fSDavid Xu __timer_gettime(timer_t timerid, struct itimerspec *value)
1584acaec8fSDavid Xu {
1594acaec8fSDavid Xu 
1604acaec8fSDavid Xu 	return __sys_ktimer_gettime(timerid->oshandle, value);
1614acaec8fSDavid Xu }
1624acaec8fSDavid Xu 
1634acaec8fSDavid Xu int
1644acaec8fSDavid Xu __timer_getoverrun(timer_t timerid)
1654acaec8fSDavid Xu {
1664acaec8fSDavid Xu 
1674acaec8fSDavid Xu 	return __sys_ktimer_getoverrun(timerid->oshandle);
1684acaec8fSDavid Xu }
1694acaec8fSDavid Xu 
1704acaec8fSDavid Xu int
1714acaec8fSDavid Xu __timer_settime(timer_t timerid, int flags,
1724acaec8fSDavid Xu 	const struct itimerspec *__restrict value,
1734acaec8fSDavid Xu 	struct itimerspec *__restrict ovalue)
1744acaec8fSDavid Xu {
1754acaec8fSDavid Xu 
1764acaec8fSDavid Xu 	return __sys_ktimer_settime(timerid->oshandle,
1774acaec8fSDavid Xu 		flags, value, ovalue);
1784acaec8fSDavid Xu }
1794acaec8fSDavid Xu 
180ddce1c3dSKonstantin Belousov #pragma weak timer_oshandle_np
1814acaec8fSDavid Xu int
182ddce1c3dSKonstantin Belousov timer_oshandle_np(timer_t timerid)
1834acaec8fSDavid Xu {
1844acaec8fSDavid Xu 
1854acaec8fSDavid Xu 	return (timerid->oshandle);
1864acaec8fSDavid Xu }
187