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 <pthread.h> 384acaec8fSDavid Xu #include <stddef.h> 394acaec8fSDavid Xu #include <signal.h> 404acaec8fSDavid Xu #include <unistd.h> 414acaec8fSDavid Xu #include "sigev_thread.h" 424acaec8fSDavid Xu #include "un-namespace.h" 434acaec8fSDavid Xu 444acaec8fSDavid Xu __weak_reference(__aio_read, _aio_read); 454acaec8fSDavid Xu __weak_reference(__aio_read, aio_read); 464acaec8fSDavid Xu __weak_reference(__aio_write, _aio_write); 474acaec8fSDavid Xu __weak_reference(__aio_write, aio_write); 484acaec8fSDavid Xu __weak_reference(__aio_return, _aio_return); 494acaec8fSDavid Xu __weak_reference(__aio_return, aio_return); 504acaec8fSDavid Xu __weak_reference(__aio_waitcomplete, _aio_waitcomplete); 514acaec8fSDavid Xu __weak_reference(__aio_waitcomplete, aio_waitcomplete); 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); 604acaec8fSDavid Xu 614acaec8fSDavid Xu static void 624acaec8fSDavid Xu aio_dispatch(struct sigev_node *sn, siginfo_t *si) 634acaec8fSDavid Xu { 644acaec8fSDavid Xu aio_func f = sn->sn_func; 654acaec8fSDavid Xu 664acaec8fSDavid Xu f(sn->sn_value, (struct aiocb *)sn->sn_id); 674acaec8fSDavid Xu } 684acaec8fSDavid Xu 694acaec8fSDavid Xu static int 704acaec8fSDavid Xu aio_io(struct aiocb *iocb, int (*sysfunc)(struct aiocb *iocb)) 714acaec8fSDavid Xu { 724acaec8fSDavid Xu struct sigev_node *sn; 734acaec8fSDavid Xu struct sigevent saved_ev; 744acaec8fSDavid Xu int ret; 754acaec8fSDavid Xu 764acaec8fSDavid Xu if (iocb->aio_sigevent.sigev_notify != SIGEV_THREAD) { 774acaec8fSDavid Xu ret = sysfunc(iocb); 784acaec8fSDavid Xu return (ret); 794acaec8fSDavid Xu } 804acaec8fSDavid Xu 814acaec8fSDavid Xu if (__sigev_check_init()) { 824acaec8fSDavid Xu /* This might be that thread library is not enabled. */ 834acaec8fSDavid Xu errno = EINVAL; 844acaec8fSDavid Xu return (-1); 854acaec8fSDavid Xu } 864acaec8fSDavid Xu 874acaec8fSDavid Xu sn = __sigev_alloc(SI_ASYNCIO, &iocb->aio_sigevent); 884acaec8fSDavid Xu if (sn == NULL) { 894acaec8fSDavid Xu errno = EAGAIN; 904acaec8fSDavid Xu return (-1); 914acaec8fSDavid Xu } 924acaec8fSDavid Xu 934acaec8fSDavid Xu saved_ev = iocb->aio_sigevent; 944acaec8fSDavid Xu sn->sn_id = (sigev_id_t)iocb; 954acaec8fSDavid Xu sn->sn_flags |= SNF_ONESHOT; 964acaec8fSDavid Xu __sigev_get_sigevent(sn, &iocb->aio_sigevent, sn->sn_id); 974acaec8fSDavid Xu 984acaec8fSDavid Xu __sigev_list_lock(); 994acaec8fSDavid Xu __sigev_register(sn); 1004acaec8fSDavid Xu __sigev_list_unlock(); 1014acaec8fSDavid Xu 1024acaec8fSDavid Xu sn->sn_dispatch = aio_dispatch; 1034acaec8fSDavid Xu ret = sysfunc(iocb); 1044acaec8fSDavid Xu iocb->aio_sigevent = saved_ev; 1054acaec8fSDavid Xu 1064acaec8fSDavid Xu if (ret != 0) { 1074acaec8fSDavid Xu __sigev_list_lock(); 1084acaec8fSDavid Xu __sigev_delete_node(sn); 1094acaec8fSDavid Xu __sigev_list_unlock(); 1104acaec8fSDavid Xu } 1114acaec8fSDavid Xu return (ret); 1124acaec8fSDavid Xu } 1134acaec8fSDavid Xu 1144acaec8fSDavid Xu int 1154acaec8fSDavid Xu __aio_read(struct aiocb *iocb) 1164acaec8fSDavid Xu { 1174acaec8fSDavid Xu return aio_io(iocb, &__sys_aio_read); 1184acaec8fSDavid Xu } 1194acaec8fSDavid Xu 1204acaec8fSDavid Xu int 1214acaec8fSDavid Xu __aio_write(struct aiocb *iocb) 1224acaec8fSDavid Xu { 1234acaec8fSDavid Xu return aio_io(iocb, &__sys_aio_write); 1244acaec8fSDavid Xu } 1254acaec8fSDavid Xu 1264acaec8fSDavid Xu int 1274acaec8fSDavid Xu __aio_waitcomplete(struct aiocb **iocbp, struct timespec *timeout) 1284acaec8fSDavid Xu { 1294acaec8fSDavid Xu int ret = __sys_aio_waitcomplete(iocbp, timeout); 1304acaec8fSDavid Xu 1314acaec8fSDavid Xu if (*iocbp) { 1324acaec8fSDavid Xu if ((*iocbp)->aio_sigevent.sigev_notify == SIGEV_THREAD) { 1334acaec8fSDavid Xu __sigev_list_lock(); 1344acaec8fSDavid Xu __sigev_delete(SI_ASYNCIO, (sigev_id_t)(*iocbp)); 1354acaec8fSDavid Xu __sigev_list_unlock(); 1364acaec8fSDavid Xu } 1374acaec8fSDavid Xu } 1384acaec8fSDavid Xu 1394acaec8fSDavid Xu return (ret); 1404acaec8fSDavid Xu } 1414acaec8fSDavid Xu 1424acaec8fSDavid Xu int 1434acaec8fSDavid Xu __aio_return(struct aiocb *iocb) 1444acaec8fSDavid Xu { 1454acaec8fSDavid Xu int ret = __sys_aio_return(iocb); 1464acaec8fSDavid Xu int err = __sys_aio_error(iocb); 1474acaec8fSDavid Xu 1484acaec8fSDavid Xu if (err != EINPROGRESS && 1494acaec8fSDavid Xu iocb->aio_sigevent.sigev_notify == SIGEV_THREAD) { 1504acaec8fSDavid Xu __sigev_list_lock(); 1514acaec8fSDavid Xu __sigev_delete(SI_ASYNCIO, (sigev_id_t)iocb); 1524acaec8fSDavid Xu __sigev_list_unlock(); 1534acaec8fSDavid Xu } 1544acaec8fSDavid Xu 1554acaec8fSDavid Xu return (ret); 1564acaec8fSDavid Xu } 157