14acaec8fSDavid Xu /*- 2*5e53a4f9SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*5e53a4f9SPedro F. Giffuni * 44acaec8fSDavid Xu * Copyright (c) 2006 David Xu <davidxu@freebsd.org> 54acaec8fSDavid Xu * All rights reserved. 64acaec8fSDavid Xu * 74acaec8fSDavid Xu * Redistribution and use in source and binary forms, with or without 84acaec8fSDavid Xu * modification, are permitted provided that the following conditions 94acaec8fSDavid Xu * are met: 104acaec8fSDavid Xu * 1. Redistributions of source code must retain the above copyright 114acaec8fSDavid Xu * notice, this list of conditions and the following disclaimer. 124acaec8fSDavid Xu * 2. Redistributions in binary form must reproduce the above copyright 134acaec8fSDavid Xu * notice, this list of conditions and the following disclaimer in the 144acaec8fSDavid Xu * documentation and/or other materials provided with the distribution. 154acaec8fSDavid Xu * 164acaec8fSDavid Xu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 174acaec8fSDavid Xu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 184acaec8fSDavid Xu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 194acaec8fSDavid Xu * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 204acaec8fSDavid Xu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 214acaec8fSDavid Xu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 224acaec8fSDavid Xu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 234acaec8fSDavid Xu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 244acaec8fSDavid Xu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 254acaec8fSDavid Xu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 264acaec8fSDavid Xu * SUCH DAMAGE. 274acaec8fSDavid Xu * 284acaec8fSDavid Xu * $FreeBSD$ 294acaec8fSDavid Xu */ 304acaec8fSDavid Xu 314acaec8fSDavid Xu #include <sys/cdefs.h> 324acaec8fSDavid Xu #include <sys/types.h> 334acaec8fSDavid Xu #include <sys/syscall.h> 344acaec8fSDavid Xu #include <sys/mqueue.h> 354acaec8fSDavid Xu 364acaec8fSDavid Xu #include "namespace.h" 374acaec8fSDavid Xu #include <errno.h> 3872757b75SDavid Xu #include <pthread.h> 394acaec8fSDavid Xu #include <stddef.h> 404acaec8fSDavid Xu #include <stdlib.h> 414acaec8fSDavid Xu #include <signal.h> 424acaec8fSDavid Xu #include "sigev_thread.h" 434acaec8fSDavid Xu #include "un-namespace.h" 44f4213b90SDavid Xu #include "libc_private.h" 454acaec8fSDavid Xu 464acaec8fSDavid Xu extern int __sys_kmq_notify(int, const struct sigevent *); 473171d99dSDavid Xu extern int __sys_kmq_open(const char *, int, mode_t, 483171d99dSDavid Xu const struct mq_attr *); 494acaec8fSDavid Xu extern int __sys_kmq_setattr(int, const struct mq_attr *__restrict, 504acaec8fSDavid Xu struct mq_attr *__restrict); 514acaec8fSDavid Xu extern ssize_t __sys_kmq_timedreceive(int, char *__restrict, size_t, 524acaec8fSDavid Xu unsigned *__restrict, const struct timespec *__restrict); 534acaec8fSDavid Xu extern int __sys_kmq_timedsend(int, const char *, size_t, unsigned, 544acaec8fSDavid Xu const struct timespec *); 554acaec8fSDavid Xu extern int __sys_kmq_unlink(const char *); 564acaec8fSDavid Xu extern int __sys_close(int fd); 574acaec8fSDavid Xu 584acaec8fSDavid Xu struct __mq { 594acaec8fSDavid Xu int oshandle; 604acaec8fSDavid Xu struct sigev_node *node; 614acaec8fSDavid Xu }; 624acaec8fSDavid Xu 634acaec8fSDavid Xu __weak_reference(__mq_open, mq_open); 644acaec8fSDavid Xu __weak_reference(__mq_open, _mq_open); 654acaec8fSDavid Xu __weak_reference(__mq_close, mq_close); 664acaec8fSDavid Xu __weak_reference(__mq_close, _mq_close); 674acaec8fSDavid Xu __weak_reference(__mq_notify, mq_notify); 684acaec8fSDavid Xu __weak_reference(__mq_notify, _mq_notify); 694acaec8fSDavid Xu __weak_reference(__mq_getattr, mq_getattr); 704acaec8fSDavid Xu __weak_reference(__mq_getattr, _mq_getattr); 714acaec8fSDavid Xu __weak_reference(__mq_setattr, mq_setattr); 724acaec8fSDavid Xu __weak_reference(__mq_setattr, _mq_setattr); 7372757b75SDavid Xu __weak_reference(__mq_timedreceive_cancel, mq_timedreceive); 744acaec8fSDavid Xu __weak_reference(__mq_timedreceive, _mq_timedreceive); 7572757b75SDavid Xu __weak_reference(__mq_timedsend_cancel, mq_timedsend); 764acaec8fSDavid Xu __weak_reference(__mq_timedsend, _mq_timedsend); 774acaec8fSDavid Xu __weak_reference(__mq_unlink, mq_unlink); 784acaec8fSDavid Xu __weak_reference(__mq_unlink, _mq_unlink); 7972757b75SDavid Xu __weak_reference(__mq_send_cancel, mq_send); 804acaec8fSDavid Xu __weak_reference(__mq_send, _mq_send); 8172757b75SDavid Xu __weak_reference(__mq_receive_cancel, mq_receive); 824acaec8fSDavid Xu __weak_reference(__mq_receive, _mq_receive); 834acaec8fSDavid Xu 844acaec8fSDavid Xu mqd_t 853171d99dSDavid Xu __mq_open(const char *name, int oflag, mode_t mode, 863171d99dSDavid Xu const struct mq_attr *attr) 874acaec8fSDavid Xu { 884acaec8fSDavid Xu struct __mq *mq; 894acaec8fSDavid Xu int err; 904acaec8fSDavid Xu 914acaec8fSDavid Xu mq = malloc(sizeof(struct __mq)); 924acaec8fSDavid Xu if (mq == NULL) 934acaec8fSDavid Xu return (NULL); 944acaec8fSDavid Xu 953171d99dSDavid Xu mq->oshandle = __sys_kmq_open(name, oflag, mode, attr); 964acaec8fSDavid Xu if (mq->oshandle != -1) { 974acaec8fSDavid Xu mq->node = NULL; 984acaec8fSDavid Xu return (mq); 994acaec8fSDavid Xu } 1004acaec8fSDavid Xu err = errno; 1014acaec8fSDavid Xu free(mq); 1024acaec8fSDavid Xu errno = err; 1034acaec8fSDavid Xu return ((mqd_t)-1L); 1044acaec8fSDavid Xu } 1054acaec8fSDavid Xu 1064acaec8fSDavid Xu int 1074acaec8fSDavid Xu __mq_close(mqd_t mqd) 1084acaec8fSDavid Xu { 1094acaec8fSDavid Xu int h; 1104acaec8fSDavid Xu 1114acaec8fSDavid Xu if (mqd->node != NULL) { 1124acaec8fSDavid Xu __sigev_list_lock(); 1134acaec8fSDavid Xu __sigev_delete_node(mqd->node); 1144acaec8fSDavid Xu __sigev_list_unlock(); 1154acaec8fSDavid Xu } 1164acaec8fSDavid Xu h = mqd->oshandle; 1174acaec8fSDavid Xu free(mqd); 1184acaec8fSDavid Xu return (__sys_close(h)); 1194acaec8fSDavid Xu } 1204acaec8fSDavid Xu 1214acaec8fSDavid Xu typedef void (*mq_func)(union sigval val); 1224acaec8fSDavid Xu 1234acaec8fSDavid Xu static void 1246348ace8SDavid Xu mq_dispatch(struct sigev_node *sn) 1254acaec8fSDavid Xu { 1264acaec8fSDavid Xu mq_func f = sn->sn_func; 1274acaec8fSDavid Xu 1284acaec8fSDavid Xu /* 1294acaec8fSDavid Xu * Check generation before calling user function, 1304acaec8fSDavid Xu * this should avoid expired notification. 1314acaec8fSDavid Xu */ 1326348ace8SDavid Xu if (sn->sn_gen == sn->sn_info.si_value.sival_int) 1334acaec8fSDavid Xu f(sn->sn_value); 1344acaec8fSDavid Xu } 1354acaec8fSDavid Xu 1364acaec8fSDavid Xu int 1374acaec8fSDavid Xu __mq_notify(mqd_t mqd, const struct sigevent *evp) 1384acaec8fSDavid Xu { 1394acaec8fSDavid Xu struct sigevent ev; 1404acaec8fSDavid Xu struct sigev_node *sn; 1414acaec8fSDavid Xu int ret; 1424acaec8fSDavid Xu 1434acaec8fSDavid Xu if (evp == NULL || evp->sigev_notify != SIGEV_THREAD) { 1444acaec8fSDavid Xu if (mqd->node != NULL) { 1454acaec8fSDavid Xu __sigev_list_lock(); 1464acaec8fSDavid Xu __sigev_delete_node(mqd->node); 1474acaec8fSDavid Xu mqd->node = NULL; 1484acaec8fSDavid Xu __sigev_list_unlock(); 1494acaec8fSDavid Xu } 1504acaec8fSDavid Xu return __sys_kmq_notify(mqd->oshandle, evp); 1514acaec8fSDavid Xu } 1524acaec8fSDavid Xu 1534acaec8fSDavid Xu if (__sigev_check_init()) { 1544acaec8fSDavid Xu /* 1554acaec8fSDavid Xu * Thread library is not enabled. 1564acaec8fSDavid Xu */ 1574acaec8fSDavid Xu errno = EINVAL; 1584acaec8fSDavid Xu return (-1); 1594acaec8fSDavid Xu } 1604acaec8fSDavid Xu 1616348ace8SDavid Xu sn = __sigev_alloc(SI_MESGQ, evp, mqd->node, 1); 1624acaec8fSDavid Xu if (sn == NULL) { 1634acaec8fSDavid Xu errno = EAGAIN; 1644acaec8fSDavid Xu return (-1); 1654acaec8fSDavid Xu } 1664acaec8fSDavid Xu 1674acaec8fSDavid Xu sn->sn_id = mqd->oshandle; 1684acaec8fSDavid Xu sn->sn_dispatch = mq_dispatch; 1694acaec8fSDavid Xu __sigev_get_sigevent(sn, &ev, sn->sn_gen); 1704acaec8fSDavid Xu __sigev_list_lock(); 1714acaec8fSDavid Xu if (mqd->node != NULL) 1724acaec8fSDavid Xu __sigev_delete_node(mqd->node); 1734acaec8fSDavid Xu mqd->node = sn; 1744acaec8fSDavid Xu __sigev_register(sn); 1754acaec8fSDavid Xu ret = __sys_kmq_notify(mqd->oshandle, &ev); 1764acaec8fSDavid Xu __sigev_list_unlock(); 1774acaec8fSDavid Xu return (ret); 1784acaec8fSDavid Xu } 1794acaec8fSDavid Xu 1804acaec8fSDavid Xu int 1814acaec8fSDavid Xu __mq_getattr(mqd_t mqd, struct mq_attr *attr) 1824acaec8fSDavid Xu { 1834acaec8fSDavid Xu 1844acaec8fSDavid Xu return __sys_kmq_setattr(mqd->oshandle, NULL, attr); 1854acaec8fSDavid Xu } 1864acaec8fSDavid Xu 1874acaec8fSDavid Xu int 1884acaec8fSDavid Xu __mq_setattr(mqd_t mqd, const struct mq_attr *newattr, struct mq_attr *oldattr) 1894acaec8fSDavid Xu { 1904acaec8fSDavid Xu 1914acaec8fSDavid Xu return __sys_kmq_setattr(mqd->oshandle, newattr, oldattr); 1924acaec8fSDavid Xu } 1934acaec8fSDavid Xu 1944acaec8fSDavid Xu ssize_t 1954acaec8fSDavid Xu __mq_timedreceive(mqd_t mqd, char *buf, size_t len, 1964acaec8fSDavid Xu unsigned *prio, const struct timespec *timeout) 1974acaec8fSDavid Xu { 1984acaec8fSDavid Xu 1994acaec8fSDavid Xu return __sys_kmq_timedreceive(mqd->oshandle, buf, len, prio, timeout); 2004acaec8fSDavid Xu } 2014acaec8fSDavid Xu 2024acaec8fSDavid Xu ssize_t 20372757b75SDavid Xu __mq_timedreceive_cancel(mqd_t mqd, char *buf, size_t len, 20472757b75SDavid Xu unsigned *prio, const struct timespec *timeout) 20572757b75SDavid Xu { 20672757b75SDavid Xu int ret; 20772757b75SDavid Xu 208f4213b90SDavid Xu _pthread_cancel_enter(1); 20972757b75SDavid Xu ret = __sys_kmq_timedreceive(mqd->oshandle, buf, len, prio, timeout); 210f4213b90SDavid Xu _pthread_cancel_leave(ret == -1); 21172757b75SDavid Xu return (ret); 21272757b75SDavid Xu } 21372757b75SDavid Xu 21472757b75SDavid Xu ssize_t 2154acaec8fSDavid Xu __mq_receive(mqd_t mqd, char *buf, size_t len, unsigned *prio) 2164acaec8fSDavid Xu { 2174acaec8fSDavid Xu 2184acaec8fSDavid Xu return __sys_kmq_timedreceive(mqd->oshandle, buf, len, prio, NULL); 2194acaec8fSDavid Xu } 2204acaec8fSDavid Xu 2214acaec8fSDavid Xu ssize_t 22272757b75SDavid Xu __mq_receive_cancel(mqd_t mqd, char *buf, size_t len, unsigned *prio) 22372757b75SDavid Xu { 22472757b75SDavid Xu int ret; 22572757b75SDavid Xu 226f4213b90SDavid Xu _pthread_cancel_enter(1); 22772757b75SDavid Xu ret = __sys_kmq_timedreceive(mqd->oshandle, buf, len, prio, NULL); 228f4213b90SDavid Xu _pthread_cancel_leave(ret == -1); 22972757b75SDavid Xu return (ret); 23072757b75SDavid Xu } 23172757b75SDavid Xu ssize_t 2324acaec8fSDavid Xu __mq_timedsend(mqd_t mqd, char *buf, size_t len, 2334acaec8fSDavid Xu unsigned prio, const struct timespec *timeout) 2344acaec8fSDavid Xu { 2354acaec8fSDavid Xu 2364acaec8fSDavid Xu return __sys_kmq_timedsend(mqd->oshandle, buf, len, prio, timeout); 2374acaec8fSDavid Xu } 2384acaec8fSDavid Xu 2394acaec8fSDavid Xu ssize_t 24072757b75SDavid Xu __mq_timedsend_cancel(mqd_t mqd, char *buf, size_t len, 24172757b75SDavid Xu unsigned prio, const struct timespec *timeout) 24272757b75SDavid Xu { 24372757b75SDavid Xu int ret; 24472757b75SDavid Xu 245f4213b90SDavid Xu _pthread_cancel_enter(1); 24672757b75SDavid Xu ret = __sys_kmq_timedsend(mqd->oshandle, buf, len, prio, timeout); 247f4213b90SDavid Xu _pthread_cancel_leave(ret == -1); 24872757b75SDavid Xu return (ret); 24972757b75SDavid Xu } 25072757b75SDavid Xu 25172757b75SDavid Xu ssize_t 2524acaec8fSDavid Xu __mq_send(mqd_t mqd, char *buf, size_t len, unsigned prio) 2534acaec8fSDavid Xu { 2544acaec8fSDavid Xu 2554acaec8fSDavid Xu return __sys_kmq_timedsend(mqd->oshandle, buf, len, prio, NULL); 2564acaec8fSDavid Xu } 2574acaec8fSDavid Xu 25872757b75SDavid Xu 25972757b75SDavid Xu ssize_t 26072757b75SDavid Xu __mq_send_cancel(mqd_t mqd, char *buf, size_t len, unsigned prio) 26172757b75SDavid Xu { 26272757b75SDavid Xu int ret; 26372757b75SDavid Xu 264f4213b90SDavid Xu _pthread_cancel_enter(1); 26572757b75SDavid Xu ret = __sys_kmq_timedsend(mqd->oshandle, buf, len, prio, NULL); 266f4213b90SDavid Xu _pthread_cancel_leave(ret == -1); 26772757b75SDavid Xu return (ret); 26872757b75SDavid Xu } 26972757b75SDavid Xu 2704acaec8fSDavid Xu int 2714acaec8fSDavid Xu __mq_unlink(const char *path) 2724acaec8fSDavid Xu { 2734acaec8fSDavid Xu 2744acaec8fSDavid Xu return __sys_kmq_unlink(path); 2754acaec8fSDavid Xu } 2764acaec8fSDavid Xu 277ddce1c3dSKonstantin Belousov #pragma weak mq_getfd_np 2784acaec8fSDavid Xu int 279ddce1c3dSKonstantin Belousov mq_getfd_np(mqd_t mqd) 2804acaec8fSDavid Xu { 281a620d098SDavid Xu 282a620d098SDavid Xu return (mqd->oshandle); 2834acaec8fSDavid Xu } 284