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