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> 3672757b75SDavid Xu #include <pthread.h> 374acaec8fSDavid Xu #include <stddef.h> 384acaec8fSDavid Xu #include <stdlib.h> 394acaec8fSDavid Xu #include <signal.h> 404acaec8fSDavid Xu #include "sigev_thread.h" 414acaec8fSDavid Xu #include "un-namespace.h" 42f4213b90SDavid Xu #include "libc_private.h" 434acaec8fSDavid Xu 444acaec8fSDavid Xu extern int __sys_kmq_notify(int, const struct sigevent *); 453171d99dSDavid Xu extern int __sys_kmq_open(const char *, int, mode_t, 463171d99dSDavid Xu const struct mq_attr *); 474acaec8fSDavid Xu extern int __sys_kmq_setattr(int, const struct mq_attr *__restrict, 484acaec8fSDavid Xu struct mq_attr *__restrict); 494acaec8fSDavid Xu extern ssize_t __sys_kmq_timedreceive(int, char *__restrict, size_t, 504acaec8fSDavid Xu unsigned *__restrict, const struct timespec *__restrict); 514acaec8fSDavid Xu extern int __sys_kmq_timedsend(int, const char *, size_t, unsigned, 524acaec8fSDavid Xu const struct timespec *); 534acaec8fSDavid Xu extern int __sys_kmq_unlink(const char *); 544acaec8fSDavid Xu extern int __sys_close(int fd); 554acaec8fSDavid Xu 564acaec8fSDavid Xu struct __mq { 574acaec8fSDavid Xu int oshandle; 584acaec8fSDavid Xu struct sigev_node *node; 594acaec8fSDavid Xu }; 604acaec8fSDavid Xu 614acaec8fSDavid Xu __weak_reference(__mq_open, mq_open); 624acaec8fSDavid Xu __weak_reference(__mq_open, _mq_open); 634acaec8fSDavid Xu __weak_reference(__mq_close, mq_close); 644acaec8fSDavid Xu __weak_reference(__mq_close, _mq_close); 654acaec8fSDavid Xu __weak_reference(__mq_notify, mq_notify); 664acaec8fSDavid Xu __weak_reference(__mq_notify, _mq_notify); 674acaec8fSDavid Xu __weak_reference(__mq_getattr, mq_getattr); 684acaec8fSDavid Xu __weak_reference(__mq_getattr, _mq_getattr); 694acaec8fSDavid Xu __weak_reference(__mq_setattr, mq_setattr); 704acaec8fSDavid Xu __weak_reference(__mq_setattr, _mq_setattr); 7172757b75SDavid Xu __weak_reference(__mq_timedreceive_cancel, mq_timedreceive); 724acaec8fSDavid Xu __weak_reference(__mq_timedreceive, _mq_timedreceive); 7372757b75SDavid Xu __weak_reference(__mq_timedsend_cancel, mq_timedsend); 744acaec8fSDavid Xu __weak_reference(__mq_timedsend, _mq_timedsend); 754acaec8fSDavid Xu __weak_reference(__mq_unlink, mq_unlink); 764acaec8fSDavid Xu __weak_reference(__mq_unlink, _mq_unlink); 7772757b75SDavid Xu __weak_reference(__mq_send_cancel, mq_send); 784acaec8fSDavid Xu __weak_reference(__mq_send, _mq_send); 7972757b75SDavid Xu __weak_reference(__mq_receive_cancel, mq_receive); 804acaec8fSDavid Xu __weak_reference(__mq_receive, _mq_receive); 814acaec8fSDavid Xu 824acaec8fSDavid Xu mqd_t 833171d99dSDavid Xu __mq_open(const char *name, int oflag, mode_t mode, 843171d99dSDavid Xu const struct mq_attr *attr) 854acaec8fSDavid Xu { 864acaec8fSDavid Xu struct __mq *mq; 874acaec8fSDavid Xu int err; 884acaec8fSDavid Xu 894acaec8fSDavid Xu mq = malloc(sizeof(struct __mq)); 904acaec8fSDavid Xu if (mq == NULL) 914acaec8fSDavid Xu return (NULL); 924acaec8fSDavid Xu 933171d99dSDavid Xu mq->oshandle = __sys_kmq_open(name, oflag, mode, attr); 944acaec8fSDavid Xu if (mq->oshandle != -1) { 954acaec8fSDavid Xu mq->node = NULL; 964acaec8fSDavid Xu return (mq); 974acaec8fSDavid Xu } 984acaec8fSDavid Xu err = errno; 994acaec8fSDavid Xu free(mq); 1004acaec8fSDavid Xu errno = err; 1014acaec8fSDavid Xu return ((mqd_t)-1L); 1024acaec8fSDavid Xu } 1034acaec8fSDavid Xu 1044acaec8fSDavid Xu int 1054acaec8fSDavid Xu __mq_close(mqd_t mqd) 1064acaec8fSDavid Xu { 1074acaec8fSDavid Xu int h; 1084acaec8fSDavid Xu 1094acaec8fSDavid Xu if (mqd->node != NULL) { 1104acaec8fSDavid Xu __sigev_list_lock(); 1114acaec8fSDavid Xu __sigev_delete_node(mqd->node); 1124acaec8fSDavid Xu __sigev_list_unlock(); 1134acaec8fSDavid Xu } 1144acaec8fSDavid Xu h = mqd->oshandle; 1154acaec8fSDavid Xu free(mqd); 1164acaec8fSDavid Xu return (__sys_close(h)); 1174acaec8fSDavid Xu } 1184acaec8fSDavid Xu 1194acaec8fSDavid Xu typedef void (*mq_func)(union sigval val); 1204acaec8fSDavid Xu 1214acaec8fSDavid Xu static void 1226348ace8SDavid Xu mq_dispatch(struct sigev_node *sn) 1234acaec8fSDavid Xu { 1244acaec8fSDavid Xu mq_func f = sn->sn_func; 1254acaec8fSDavid Xu 1264acaec8fSDavid Xu /* 1274acaec8fSDavid Xu * Check generation before calling user function, 1284acaec8fSDavid Xu * this should avoid expired notification. 1294acaec8fSDavid Xu */ 1306348ace8SDavid Xu if (sn->sn_gen == sn->sn_info.si_value.sival_int) 1314acaec8fSDavid Xu f(sn->sn_value); 1324acaec8fSDavid Xu } 1334acaec8fSDavid Xu 1344acaec8fSDavid Xu int 1354acaec8fSDavid Xu __mq_notify(mqd_t mqd, const struct sigevent *evp) 1364acaec8fSDavid Xu { 1374acaec8fSDavid Xu struct sigevent ev; 1384acaec8fSDavid Xu struct sigev_node *sn; 1394acaec8fSDavid Xu int ret; 1404acaec8fSDavid Xu 1414acaec8fSDavid Xu if (evp == NULL || evp->sigev_notify != SIGEV_THREAD) { 1424acaec8fSDavid Xu if (mqd->node != NULL) { 1434acaec8fSDavid Xu __sigev_list_lock(); 1444acaec8fSDavid Xu __sigev_delete_node(mqd->node); 1454acaec8fSDavid Xu mqd->node = NULL; 1464acaec8fSDavid Xu __sigev_list_unlock(); 1474acaec8fSDavid Xu } 1484acaec8fSDavid Xu return __sys_kmq_notify(mqd->oshandle, evp); 1494acaec8fSDavid Xu } 1504acaec8fSDavid Xu 1514acaec8fSDavid Xu if (__sigev_check_init()) { 1524acaec8fSDavid Xu /* 1534acaec8fSDavid Xu * Thread library is not enabled. 1544acaec8fSDavid Xu */ 1554acaec8fSDavid Xu errno = EINVAL; 1564acaec8fSDavid Xu return (-1); 1574acaec8fSDavid Xu } 1584acaec8fSDavid Xu 1596348ace8SDavid Xu sn = __sigev_alloc(SI_MESGQ, evp, mqd->node, 1); 1604acaec8fSDavid Xu if (sn == NULL) { 1614acaec8fSDavid Xu errno = EAGAIN; 1624acaec8fSDavid Xu return (-1); 1634acaec8fSDavid Xu } 1644acaec8fSDavid Xu 1654acaec8fSDavid Xu sn->sn_id = mqd->oshandle; 1664acaec8fSDavid Xu sn->sn_dispatch = mq_dispatch; 1674acaec8fSDavid Xu __sigev_get_sigevent(sn, &ev, sn->sn_gen); 1684acaec8fSDavid Xu __sigev_list_lock(); 1694acaec8fSDavid Xu if (mqd->node != NULL) 1704acaec8fSDavid Xu __sigev_delete_node(mqd->node); 1714acaec8fSDavid Xu mqd->node = sn; 1724acaec8fSDavid Xu __sigev_register(sn); 1734acaec8fSDavid Xu ret = __sys_kmq_notify(mqd->oshandle, &ev); 1744acaec8fSDavid Xu __sigev_list_unlock(); 1754acaec8fSDavid Xu return (ret); 1764acaec8fSDavid Xu } 1774acaec8fSDavid Xu 1784acaec8fSDavid Xu int 1794acaec8fSDavid Xu __mq_getattr(mqd_t mqd, struct mq_attr *attr) 1804acaec8fSDavid Xu { 1814acaec8fSDavid Xu 1824acaec8fSDavid Xu return __sys_kmq_setattr(mqd->oshandle, NULL, attr); 1834acaec8fSDavid Xu } 1844acaec8fSDavid Xu 1854acaec8fSDavid Xu int 1864acaec8fSDavid Xu __mq_setattr(mqd_t mqd, const struct mq_attr *newattr, struct mq_attr *oldattr) 1874acaec8fSDavid Xu { 1884acaec8fSDavid Xu 1894acaec8fSDavid Xu return __sys_kmq_setattr(mqd->oshandle, newattr, oldattr); 1904acaec8fSDavid Xu } 1914acaec8fSDavid Xu 1924acaec8fSDavid Xu ssize_t 1934acaec8fSDavid Xu __mq_timedreceive(mqd_t mqd, char *buf, size_t len, 1944acaec8fSDavid Xu unsigned *prio, const struct timespec *timeout) 1954acaec8fSDavid Xu { 1964acaec8fSDavid Xu 1974acaec8fSDavid Xu return __sys_kmq_timedreceive(mqd->oshandle, buf, len, prio, timeout); 1984acaec8fSDavid Xu } 1994acaec8fSDavid Xu 2004acaec8fSDavid Xu ssize_t 20172757b75SDavid Xu __mq_timedreceive_cancel(mqd_t mqd, char *buf, size_t len, 20272757b75SDavid Xu unsigned *prio, const struct timespec *timeout) 20372757b75SDavid Xu { 20472757b75SDavid Xu int ret; 20572757b75SDavid Xu 206f4213b90SDavid Xu _pthread_cancel_enter(1); 20772757b75SDavid Xu ret = __sys_kmq_timedreceive(mqd->oshandle, buf, len, prio, timeout); 208f4213b90SDavid Xu _pthread_cancel_leave(ret == -1); 20972757b75SDavid Xu return (ret); 21072757b75SDavid Xu } 21172757b75SDavid Xu 21272757b75SDavid Xu ssize_t 2134acaec8fSDavid Xu __mq_receive(mqd_t mqd, char *buf, size_t len, unsigned *prio) 2144acaec8fSDavid Xu { 2154acaec8fSDavid Xu 2164acaec8fSDavid Xu return __sys_kmq_timedreceive(mqd->oshandle, buf, len, prio, NULL); 2174acaec8fSDavid Xu } 2184acaec8fSDavid Xu 2194acaec8fSDavid Xu ssize_t 22072757b75SDavid Xu __mq_receive_cancel(mqd_t mqd, char *buf, size_t len, unsigned *prio) 22172757b75SDavid Xu { 22272757b75SDavid Xu int ret; 22372757b75SDavid Xu 224f4213b90SDavid Xu _pthread_cancel_enter(1); 22572757b75SDavid Xu ret = __sys_kmq_timedreceive(mqd->oshandle, buf, len, prio, NULL); 226f4213b90SDavid Xu _pthread_cancel_leave(ret == -1); 22772757b75SDavid Xu return (ret); 22872757b75SDavid Xu } 22972757b75SDavid Xu ssize_t 2304acaec8fSDavid Xu __mq_timedsend(mqd_t mqd, char *buf, size_t len, 2314acaec8fSDavid Xu unsigned prio, const struct timespec *timeout) 2324acaec8fSDavid Xu { 2334acaec8fSDavid Xu 2344acaec8fSDavid Xu return __sys_kmq_timedsend(mqd->oshandle, buf, len, prio, timeout); 2354acaec8fSDavid Xu } 2364acaec8fSDavid Xu 2374acaec8fSDavid Xu ssize_t 23872757b75SDavid Xu __mq_timedsend_cancel(mqd_t mqd, char *buf, size_t len, 23972757b75SDavid Xu unsigned prio, const struct timespec *timeout) 24072757b75SDavid Xu { 24172757b75SDavid Xu int ret; 24272757b75SDavid Xu 243f4213b90SDavid Xu _pthread_cancel_enter(1); 24472757b75SDavid Xu ret = __sys_kmq_timedsend(mqd->oshandle, buf, len, prio, timeout); 245f4213b90SDavid Xu _pthread_cancel_leave(ret == -1); 24672757b75SDavid Xu return (ret); 24772757b75SDavid Xu } 24872757b75SDavid Xu 24972757b75SDavid Xu ssize_t 2504acaec8fSDavid Xu __mq_send(mqd_t mqd, char *buf, size_t len, unsigned prio) 2514acaec8fSDavid Xu { 2524acaec8fSDavid Xu 2534acaec8fSDavid Xu return __sys_kmq_timedsend(mqd->oshandle, buf, len, prio, NULL); 2544acaec8fSDavid Xu } 2554acaec8fSDavid Xu 25672757b75SDavid Xu 25772757b75SDavid Xu ssize_t 25872757b75SDavid Xu __mq_send_cancel(mqd_t mqd, char *buf, size_t len, unsigned prio) 25972757b75SDavid Xu { 26072757b75SDavid Xu int ret; 26172757b75SDavid Xu 262f4213b90SDavid Xu _pthread_cancel_enter(1); 26372757b75SDavid Xu ret = __sys_kmq_timedsend(mqd->oshandle, buf, len, prio, NULL); 264f4213b90SDavid Xu _pthread_cancel_leave(ret == -1); 26572757b75SDavid Xu return (ret); 26672757b75SDavid Xu } 26772757b75SDavid Xu 2684acaec8fSDavid Xu int 2694acaec8fSDavid Xu __mq_unlink(const char *path) 2704acaec8fSDavid Xu { 2714acaec8fSDavid Xu 2724acaec8fSDavid Xu return __sys_kmq_unlink(path); 2734acaec8fSDavid Xu } 2744acaec8fSDavid Xu 275*ddce1c3dSKonstantin Belousov #pragma weak mq_getfd_np 2764acaec8fSDavid Xu int 277*ddce1c3dSKonstantin Belousov mq_getfd_np(mqd_t mqd) 2784acaec8fSDavid Xu { 279a620d098SDavid Xu 280a620d098SDavid Xu return (mqd->oshandle); 2814acaec8fSDavid Xu } 282