xref: /freebsd/lib/librt/aio.c (revision 3c7787282452ef6cbb983403008bac7542776b29)
14acaec8fSDavid Xu /*
24acaec8fSDavid Xu  * Copyright (c) 2005 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 #include <sys/aio.h>
344acaec8fSDavid Xu 
354acaec8fSDavid Xu #include "namespace.h"
364acaec8fSDavid Xu #include <errno.h>
374acaec8fSDavid Xu #include <stddef.h>
384acaec8fSDavid Xu #include <signal.h>
394acaec8fSDavid Xu #include "sigev_thread.h"
404acaec8fSDavid Xu #include "un-namespace.h"
414acaec8fSDavid Xu 
424acaec8fSDavid Xu __weak_reference(__aio_read, _aio_read);
434acaec8fSDavid Xu __weak_reference(__aio_read, aio_read);
444acaec8fSDavid Xu __weak_reference(__aio_write, _aio_write);
454acaec8fSDavid Xu __weak_reference(__aio_write, aio_write);
464acaec8fSDavid Xu __weak_reference(__aio_return, _aio_return);
474acaec8fSDavid Xu __weak_reference(__aio_return, aio_return);
484acaec8fSDavid Xu __weak_reference(__aio_waitcomplete, _aio_waitcomplete);
494acaec8fSDavid Xu __weak_reference(__aio_waitcomplete, aio_waitcomplete);
503c778728SDavid Xu __weak_reference(__aio_fsync, _aio_fsync);
513c778728SDavid Xu __weak_reference(__aio_fsync, aio_fsync);
524acaec8fSDavid Xu 
534acaec8fSDavid Xu typedef void (*aio_func)(union sigval val, struct aiocb *iocb);
544acaec8fSDavid Xu 
554acaec8fSDavid Xu extern int __sys_aio_read(struct aiocb *iocb);
564acaec8fSDavid Xu extern int __sys_aio_write(struct aiocb *iocb);
574acaec8fSDavid Xu extern int __sys_aio_waitcomplete(struct aiocb **iocbp, struct timespec *timeout);
584acaec8fSDavid Xu extern int __sys_aio_return(struct aiocb *iocb);
594acaec8fSDavid Xu extern int __sys_aio_error(struct aiocb *iocb);
603c778728SDavid Xu extern int __sys_aio_fsync(int op, struct aiocb *iocb);
614acaec8fSDavid Xu 
624acaec8fSDavid Xu static void
636348ace8SDavid Xu aio_dispatch(struct sigev_node *sn)
644acaec8fSDavid Xu {
654acaec8fSDavid Xu 	aio_func f = sn->sn_func;
664acaec8fSDavid Xu 
674acaec8fSDavid Xu 	f(sn->sn_value, (struct aiocb *)sn->sn_id);
684acaec8fSDavid Xu }
694acaec8fSDavid Xu 
704acaec8fSDavid Xu static int
713c778728SDavid Xu aio_sigev_alloc(struct aiocb *iocb, struct sigev_node **sn,
723c778728SDavid Xu 	struct sigevent *saved_ev)
733c778728SDavid Xu {
743c778728SDavid Xu 	if (__sigev_check_init()) {
753c778728SDavid Xu 		/* This might be that thread library is not enabled. */
763c778728SDavid Xu 		errno = EINVAL;
773c778728SDavid Xu 		return (-1);
783c778728SDavid Xu 	}
793c778728SDavid Xu 
803c778728SDavid Xu 	*sn = __sigev_alloc(SI_ASYNCIO, &iocb->aio_sigevent, NULL, 1);
813c778728SDavid Xu 	if (*sn == NULL) {
823c778728SDavid Xu 		errno = EAGAIN;
833c778728SDavid Xu 		return (-1);
843c778728SDavid Xu 	}
853c778728SDavid Xu 
863c778728SDavid Xu 	*saved_ev = iocb->aio_sigevent;
873c778728SDavid Xu 	(*sn)->sn_id = (sigev_id_t)iocb;
883c778728SDavid Xu 	__sigev_get_sigevent(*sn, &iocb->aio_sigevent, (*sn)->sn_id);
893c778728SDavid Xu 	(*sn)->sn_dispatch = aio_dispatch;
903c778728SDavid Xu 
913c778728SDavid Xu 	__sigev_list_lock();
923c778728SDavid Xu 	__sigev_register(*sn);
933c778728SDavid Xu 	__sigev_list_unlock();
943c778728SDavid Xu 
953c778728SDavid Xu 	return (0);
963c778728SDavid Xu }
973c778728SDavid Xu 
983c778728SDavid Xu static int
994acaec8fSDavid Xu aio_io(struct aiocb *iocb, int (*sysfunc)(struct aiocb *iocb))
1004acaec8fSDavid Xu {
1014acaec8fSDavid Xu 	struct sigev_node *sn;
1024acaec8fSDavid Xu 	struct sigevent saved_ev;
1031b4610feSDavid Xu 	int ret, err;
1044acaec8fSDavid Xu 
1054acaec8fSDavid Xu 	if (iocb->aio_sigevent.sigev_notify != SIGEV_THREAD) {
1064acaec8fSDavid Xu 		ret = sysfunc(iocb);
1074acaec8fSDavid Xu 		return (ret);
1084acaec8fSDavid Xu 	}
1094acaec8fSDavid Xu 
1103c778728SDavid Xu 	ret = aio_sigev_alloc(iocb, &sn, &saved_ev);
1113c778728SDavid Xu 	if (ret)
1123c778728SDavid Xu 		return (ret);
1134acaec8fSDavid Xu 	ret = sysfunc(iocb);
1144acaec8fSDavid Xu 	iocb->aio_sigevent = saved_ev;
1154acaec8fSDavid Xu 	if (ret != 0) {
1161b4610feSDavid Xu 		err = errno;
1174acaec8fSDavid Xu 		__sigev_list_lock();
1184acaec8fSDavid Xu 		__sigev_delete_node(sn);
1194acaec8fSDavid Xu 		__sigev_list_unlock();
1201b4610feSDavid Xu 		errno = err;
1214acaec8fSDavid Xu 	}
1224acaec8fSDavid Xu 	return (ret);
1234acaec8fSDavid Xu }
1244acaec8fSDavid Xu 
1254acaec8fSDavid Xu int
1264acaec8fSDavid Xu __aio_read(struct aiocb *iocb)
1274acaec8fSDavid Xu {
1281b4610feSDavid Xu 
1294acaec8fSDavid Xu 	return aio_io(iocb, &__sys_aio_read);
1304acaec8fSDavid Xu }
1314acaec8fSDavid Xu 
1324acaec8fSDavid Xu int
1334acaec8fSDavid Xu __aio_write(struct aiocb *iocb)
1344acaec8fSDavid Xu {
1351b4610feSDavid Xu 
1364acaec8fSDavid Xu 	return aio_io(iocb, &__sys_aio_write);
1374acaec8fSDavid Xu }
1384acaec8fSDavid Xu 
1394acaec8fSDavid Xu int
1404acaec8fSDavid Xu __aio_waitcomplete(struct aiocb **iocbp, struct timespec *timeout)
1414acaec8fSDavid Xu {
1421b4610feSDavid Xu 	int err;
1434acaec8fSDavid Xu 	int ret = __sys_aio_waitcomplete(iocbp, timeout);
1444acaec8fSDavid Xu 
1454acaec8fSDavid Xu 	if (*iocbp) {
1464acaec8fSDavid Xu 		if ((*iocbp)->aio_sigevent.sigev_notify == SIGEV_THREAD) {
1471b4610feSDavid Xu 			err = errno;
1484acaec8fSDavid Xu 			__sigev_list_lock();
1494acaec8fSDavid Xu 			__sigev_delete(SI_ASYNCIO, (sigev_id_t)(*iocbp));
1504acaec8fSDavid Xu 			__sigev_list_unlock();
1511b4610feSDavid Xu 			errno = err;
1524acaec8fSDavid Xu 		}
1534acaec8fSDavid Xu 	}
1544acaec8fSDavid Xu 
1554acaec8fSDavid Xu 	return (ret);
1564acaec8fSDavid Xu }
1574acaec8fSDavid Xu 
1584acaec8fSDavid Xu int
1594acaec8fSDavid Xu __aio_return(struct aiocb *iocb)
1604acaec8fSDavid Xu {
1614acaec8fSDavid Xu 
1621b4610feSDavid Xu 	if (iocb->aio_sigevent.sigev_notify == SIGEV_THREAD) {
1631b4610feSDavid Xu 		if (__sys_aio_error(iocb) == EINPROGRESS)
1641b4610feSDavid Xu 			return (EINPROGRESS);
1654acaec8fSDavid Xu 		__sigev_list_lock();
1664acaec8fSDavid Xu 		__sigev_delete(SI_ASYNCIO, (sigev_id_t)iocb);
1674acaec8fSDavid Xu 		__sigev_list_unlock();
1684acaec8fSDavid Xu 	}
1694acaec8fSDavid Xu 
1701b4610feSDavid Xu 	return __sys_aio_return(iocb);
1714acaec8fSDavid Xu }
1723c778728SDavid Xu 
1733c778728SDavid Xu int
1743c778728SDavid Xu __aio_fsync(int op, struct aiocb *iocb)
1753c778728SDavid Xu {
1763c778728SDavid Xu 	struct sigev_node *sn;
1773c778728SDavid Xu 	struct sigevent saved_ev;
1783c778728SDavid Xu 	int ret, err;
1793c778728SDavid Xu 
1803c778728SDavid Xu 	if (iocb->aio_sigevent.sigev_notify != SIGEV_THREAD)
1813c778728SDavid Xu 		return __sys_aio_fsync(op, iocb);
1823c778728SDavid Xu 
1833c778728SDavid Xu 	ret = aio_sigev_alloc(iocb, &sn, &saved_ev);
1843c778728SDavid Xu 	if (ret)
1853c778728SDavid Xu 		return (ret);
1863c778728SDavid Xu 	ret = __sys_aio_fsync(op, iocb);
1873c778728SDavid Xu 	iocb->aio_sigevent = saved_ev;
1883c778728SDavid Xu 	if (ret != 0) {
1893c778728SDavid Xu 		err = errno;
1903c778728SDavid Xu 		__sigev_list_lock();
1913c778728SDavid Xu 		__sigev_delete_node(sn);
1923c778728SDavid Xu 		__sigev_list_unlock();
1933c778728SDavid Xu 		errno = err;
1943c778728SDavid Xu 	}
1953c778728SDavid Xu 	return (ret);
1963c778728SDavid Xu }
197