14acaec8fSDavid Xu /*- 24acaec8fSDavid Xu * Copyright (c) 2006 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, this list of conditions and the following disclaimer. 104acaec8fSDavid Xu * 2. Redistributions in binary form must reproduce the above copyright 114acaec8fSDavid Xu * notice, this list of conditions and the following disclaimer in the 124acaec8fSDavid Xu * documentation and/or other materials provided with the distribution. 134acaec8fSDavid Xu * 144acaec8fSDavid Xu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 154acaec8fSDavid Xu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 164acaec8fSDavid Xu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 174acaec8fSDavid Xu * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 184acaec8fSDavid Xu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 194acaec8fSDavid Xu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 204acaec8fSDavid Xu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 214acaec8fSDavid Xu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 224acaec8fSDavid Xu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 234acaec8fSDavid Xu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 244acaec8fSDavid Xu * SUCH DAMAGE. 254acaec8fSDavid Xu * 264acaec8fSDavid Xu * $FreeBSD$ 274acaec8fSDavid Xu */ 284acaec8fSDavid Xu 294acaec8fSDavid Xu #include <sys/cdefs.h> 304acaec8fSDavid Xu #include <sys/types.h> 314acaec8fSDavid Xu #include <sys/syscall.h> 324acaec8fSDavid Xu #include <sys/mqueue.h> 334acaec8fSDavid Xu 344acaec8fSDavid Xu #include "namespace.h" 354acaec8fSDavid Xu #include <errno.h> 364acaec8fSDavid Xu #include <pthread.h> 374acaec8fSDavid Xu #include <stddef.h> 384acaec8fSDavid Xu #include <stdlib.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 extern int __sys_kmq_notify(int, const struct sigevent *); 454acaec8fSDavid Xu extern int __sys_kmq_open(const char *, int, mode_t); 464acaec8fSDavid Xu extern int __sys_kmq_setattr(int, const struct mq_attr *__restrict, 474acaec8fSDavid Xu struct mq_attr *__restrict); 484acaec8fSDavid Xu extern ssize_t __sys_kmq_timedreceive(int, char *__restrict, size_t, 494acaec8fSDavid Xu unsigned *__restrict, const struct timespec *__restrict); 504acaec8fSDavid Xu extern int __sys_kmq_timedsend(int, const char *, size_t, unsigned, 514acaec8fSDavid Xu const struct timespec *); 524acaec8fSDavid Xu extern int __sys_kmq_unlink(const char *); 534acaec8fSDavid Xu extern int __sys_close(int fd); 544acaec8fSDavid Xu 554acaec8fSDavid Xu struct __mq { 564acaec8fSDavid Xu int oshandle; 574acaec8fSDavid Xu struct sigev_node *node; 584acaec8fSDavid Xu }; 594acaec8fSDavid Xu 604acaec8fSDavid Xu __weak_reference(__mq_open, mq_open); 614acaec8fSDavid Xu __weak_reference(__mq_open, _mq_open); 624acaec8fSDavid Xu __weak_reference(__mq_close, mq_close); 634acaec8fSDavid Xu __weak_reference(__mq_close, _mq_close); 644acaec8fSDavid Xu __weak_reference(__mq_notify, mq_notify); 654acaec8fSDavid Xu __weak_reference(__mq_notify, _mq_notify); 664acaec8fSDavid Xu __weak_reference(__mq_getattr, mq_getattr); 674acaec8fSDavid Xu __weak_reference(__mq_getattr, _mq_getattr); 684acaec8fSDavid Xu __weak_reference(__mq_setattr, mq_setattr); 694acaec8fSDavid Xu __weak_reference(__mq_setattr, _mq_setattr); 704acaec8fSDavid Xu __weak_reference(__mq_timedreceive, mq_timedreceive); 714acaec8fSDavid Xu __weak_reference(__mq_timedreceive, _mq_timedreceive); 724acaec8fSDavid Xu __weak_reference(__mq_timedsend, mq_timedsend); 734acaec8fSDavid Xu __weak_reference(__mq_timedsend, _mq_timedsend); 744acaec8fSDavid Xu __weak_reference(__mq_unlink, mq_unlink); 754acaec8fSDavid Xu __weak_reference(__mq_unlink, _mq_unlink); 764acaec8fSDavid Xu __weak_reference(__mq_send, mq_send); 774acaec8fSDavid Xu __weak_reference(__mq_send, _mq_send); 784acaec8fSDavid Xu __weak_reference(__mq_receive, mq_receive); 794acaec8fSDavid Xu __weak_reference(__mq_receive, _mq_receive); 804acaec8fSDavid Xu 814acaec8fSDavid Xu mqd_t 824acaec8fSDavid Xu __mq_open(const char *name, int oflag, mode_t mode) 834acaec8fSDavid Xu { 844acaec8fSDavid Xu struct __mq *mq; 854acaec8fSDavid Xu int err; 864acaec8fSDavid Xu 874acaec8fSDavid Xu mq = malloc(sizeof(struct __mq)); 884acaec8fSDavid Xu if (mq == NULL) 894acaec8fSDavid Xu return (NULL); 904acaec8fSDavid Xu 914acaec8fSDavid Xu mq->oshandle = __sys_kmq_open(name, oflag, mode); 924acaec8fSDavid Xu if (mq->oshandle != -1) { 934acaec8fSDavid Xu mq->node = NULL; 944acaec8fSDavid Xu return (mq); 954acaec8fSDavid Xu } 964acaec8fSDavid Xu err = errno; 974acaec8fSDavid Xu free(mq); 984acaec8fSDavid Xu errno = err; 994acaec8fSDavid Xu return ((mqd_t)-1L); 1004acaec8fSDavid Xu } 1014acaec8fSDavid Xu 1024acaec8fSDavid Xu int 1034acaec8fSDavid Xu __mq_close(mqd_t mqd) 1044acaec8fSDavid Xu { 1054acaec8fSDavid Xu int h; 1064acaec8fSDavid Xu 1074acaec8fSDavid Xu if (mqd->node != NULL) { 1084acaec8fSDavid Xu __sigev_list_lock(); 1094acaec8fSDavid Xu __sigev_delete_node(mqd->node); 1104acaec8fSDavid Xu __sigev_list_unlock(); 1114acaec8fSDavid Xu } 1124acaec8fSDavid Xu h = mqd->oshandle; 1134acaec8fSDavid Xu free(mqd); 1144acaec8fSDavid Xu return (__sys_close(h)); 1154acaec8fSDavid Xu } 1164acaec8fSDavid Xu 1174acaec8fSDavid Xu typedef void (*mq_func)(union sigval val); 1184acaec8fSDavid Xu 1194acaec8fSDavid Xu static void 1204acaec8fSDavid Xu mq_dispatch(struct sigev_node *sn, siginfo_t *si) 1214acaec8fSDavid Xu { 1224acaec8fSDavid Xu mq_func f = sn->sn_func; 1234acaec8fSDavid Xu 1244acaec8fSDavid Xu /* 1254acaec8fSDavid Xu * Check generation before calling user function, 1264acaec8fSDavid Xu * this should avoid expired notification. 1274acaec8fSDavid Xu */ 1284acaec8fSDavid Xu if (sn->sn_gen == si->si_value.sival_int) 1294acaec8fSDavid Xu f(sn->sn_value); 1304acaec8fSDavid Xu } 1314acaec8fSDavid Xu 1324acaec8fSDavid Xu int 1334acaec8fSDavid Xu __mq_notify(mqd_t mqd, const struct sigevent *evp) 1344acaec8fSDavid Xu { 1354acaec8fSDavid Xu struct sigevent ev; 1364acaec8fSDavid Xu struct sigev_node *sn; 1374acaec8fSDavid Xu int ret; 1384acaec8fSDavid Xu 1394acaec8fSDavid Xu if (evp == NULL || evp->sigev_notify != SIGEV_THREAD) { 1404acaec8fSDavid Xu if (mqd->node != NULL) { 1414acaec8fSDavid Xu __sigev_list_lock(); 1424acaec8fSDavid Xu __sigev_delete_node(mqd->node); 1434acaec8fSDavid Xu mqd->node = NULL; 1444acaec8fSDavid Xu __sigev_list_unlock(); 1454acaec8fSDavid Xu } 1464acaec8fSDavid Xu return __sys_kmq_notify(mqd->oshandle, evp); 1474acaec8fSDavid Xu } 1484acaec8fSDavid Xu 1494acaec8fSDavid Xu if (__sigev_check_init()) { 1504acaec8fSDavid Xu /* 1514acaec8fSDavid Xu * Thread library is not enabled. 1524acaec8fSDavid Xu */ 1534acaec8fSDavid Xu errno = EINVAL; 1544acaec8fSDavid Xu return (-1); 1554acaec8fSDavid Xu } 1564acaec8fSDavid Xu 1574acaec8fSDavid Xu sn = __sigev_alloc(SI_MESGQ, evp); 1584acaec8fSDavid Xu if (sn == NULL) { 1594acaec8fSDavid Xu errno = EAGAIN; 1604acaec8fSDavid Xu return (-1); 1614acaec8fSDavid Xu } 1624acaec8fSDavid Xu 1634acaec8fSDavid Xu sn->sn_id = mqd->oshandle; 1644acaec8fSDavid Xu sn->sn_dispatch = mq_dispatch; 1654acaec8fSDavid Xu __sigev_get_sigevent(sn, &ev, sn->sn_gen); 1664acaec8fSDavid Xu __sigev_list_lock(); 1674acaec8fSDavid Xu if (mqd->node != NULL) 1684acaec8fSDavid Xu __sigev_delete_node(mqd->node); 1694acaec8fSDavid Xu mqd->node = sn; 1704acaec8fSDavid Xu __sigev_register(sn); 1714acaec8fSDavid Xu ret = __sys_kmq_notify(mqd->oshandle, &ev); 1724acaec8fSDavid Xu __sigev_list_unlock(); 1734acaec8fSDavid Xu return (ret); 1744acaec8fSDavid Xu } 1754acaec8fSDavid Xu 1764acaec8fSDavid Xu int 1774acaec8fSDavid Xu __mq_getattr(mqd_t mqd, struct mq_attr *attr) 1784acaec8fSDavid Xu { 1794acaec8fSDavid Xu 1804acaec8fSDavid Xu return __sys_kmq_setattr(mqd->oshandle, NULL, attr); 1814acaec8fSDavid Xu } 1824acaec8fSDavid Xu 1834acaec8fSDavid Xu int 1844acaec8fSDavid Xu __mq_setattr(mqd_t mqd, const struct mq_attr *newattr, struct mq_attr *oldattr) 1854acaec8fSDavid Xu { 1864acaec8fSDavid Xu 1874acaec8fSDavid Xu return __sys_kmq_setattr(mqd->oshandle, newattr, oldattr); 1884acaec8fSDavid Xu } 1894acaec8fSDavid Xu 1904acaec8fSDavid Xu ssize_t 1914acaec8fSDavid Xu __mq_timedreceive(mqd_t mqd, char *buf, size_t len, 1924acaec8fSDavid Xu unsigned *prio, const struct timespec *timeout) 1934acaec8fSDavid Xu { 1944acaec8fSDavid Xu 1954acaec8fSDavid Xu return __sys_kmq_timedreceive(mqd->oshandle, buf, len, prio, timeout); 1964acaec8fSDavid Xu } 1974acaec8fSDavid Xu 1984acaec8fSDavid Xu ssize_t 1994acaec8fSDavid Xu __mq_receive(mqd_t mqd, char *buf, size_t len, unsigned *prio) 2004acaec8fSDavid Xu { 2014acaec8fSDavid Xu 2024acaec8fSDavid Xu return __sys_kmq_timedreceive(mqd->oshandle, buf, len, prio, NULL); 2034acaec8fSDavid Xu } 2044acaec8fSDavid Xu 2054acaec8fSDavid Xu ssize_t 2064acaec8fSDavid Xu __mq_timedsend(mqd_t mqd, char *buf, size_t len, 2074acaec8fSDavid Xu unsigned prio, const struct timespec *timeout) 2084acaec8fSDavid Xu { 2094acaec8fSDavid Xu 2104acaec8fSDavid Xu return __sys_kmq_timedsend(mqd->oshandle, buf, len, prio, timeout); 2114acaec8fSDavid Xu } 2124acaec8fSDavid Xu 2134acaec8fSDavid Xu ssize_t 2144acaec8fSDavid Xu __mq_send(mqd_t mqd, char *buf, size_t len, unsigned prio) 2154acaec8fSDavid Xu { 2164acaec8fSDavid Xu 2174acaec8fSDavid Xu return __sys_kmq_timedsend(mqd->oshandle, buf, len, prio, NULL); 2184acaec8fSDavid Xu } 2194acaec8fSDavid Xu 2204acaec8fSDavid Xu int 2214acaec8fSDavid Xu __mq_unlink(const char *path) 2224acaec8fSDavid Xu { 2234acaec8fSDavid Xu 2244acaec8fSDavid Xu return __sys_kmq_unlink(path); 2254acaec8fSDavid Xu } 2264acaec8fSDavid Xu 2274acaec8fSDavid Xu int 2284acaec8fSDavid Xu __mq_oshandle(mqd_t mqd) 2294acaec8fSDavid Xu { 2304acaec8fSDavid Xu return mqd->oshandle; 2314acaec8fSDavid Xu } 232