14acaec8fSDavid Xu /*- 2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 35e53a4f9SPedro 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 294acaec8fSDavid Xu #include <sys/types.h> 304acaec8fSDavid Xu #include <sys/syscall.h> 314acaec8fSDavid Xu #include <sys/mqueue.h> 324acaec8fSDavid Xu 334acaec8fSDavid Xu #include "namespace.h" 344acaec8fSDavid Xu #include <errno.h> 3572757b75SDavid Xu #include <pthread.h> 364acaec8fSDavid Xu #include <stddef.h> 374acaec8fSDavid Xu #include <stdlib.h> 384acaec8fSDavid Xu #include <signal.h> 394acaec8fSDavid Xu #include "sigev_thread.h" 404acaec8fSDavid Xu #include "un-namespace.h" 41f4213b90SDavid Xu #include "libc_private.h" 424acaec8fSDavid Xu 434acaec8fSDavid Xu struct __mq { 444acaec8fSDavid Xu int oshandle; 454acaec8fSDavid Xu struct sigev_node *node; 464acaec8fSDavid Xu }; 474acaec8fSDavid Xu 484acaec8fSDavid Xu __weak_reference(__mq_open, mq_open); 494acaec8fSDavid Xu __weak_reference(__mq_open, _mq_open); 504acaec8fSDavid Xu __weak_reference(__mq_close, mq_close); 514acaec8fSDavid Xu __weak_reference(__mq_close, _mq_close); 524acaec8fSDavid Xu __weak_reference(__mq_notify, mq_notify); 534acaec8fSDavid Xu __weak_reference(__mq_notify, _mq_notify); 544acaec8fSDavid Xu __weak_reference(__mq_getattr, mq_getattr); 554acaec8fSDavid Xu __weak_reference(__mq_getattr, _mq_getattr); 564acaec8fSDavid Xu __weak_reference(__mq_setattr, mq_setattr); 574acaec8fSDavid Xu __weak_reference(__mq_setattr, _mq_setattr); 5872757b75SDavid Xu __weak_reference(__mq_timedreceive_cancel, mq_timedreceive); 594acaec8fSDavid Xu __weak_reference(__mq_timedreceive, _mq_timedreceive); 6072757b75SDavid Xu __weak_reference(__mq_timedsend_cancel, mq_timedsend); 614acaec8fSDavid Xu __weak_reference(__mq_timedsend, _mq_timedsend); 624acaec8fSDavid Xu __weak_reference(__mq_unlink, mq_unlink); 634acaec8fSDavid Xu __weak_reference(__mq_unlink, _mq_unlink); 6472757b75SDavid Xu __weak_reference(__mq_send_cancel, mq_send); 654acaec8fSDavid Xu __weak_reference(__mq_send, _mq_send); 6672757b75SDavid Xu __weak_reference(__mq_receive_cancel, mq_receive); 674acaec8fSDavid Xu __weak_reference(__mq_receive, _mq_receive); 684acaec8fSDavid Xu 694acaec8fSDavid Xu mqd_t 703171d99dSDavid Xu __mq_open(const char *name, int oflag, mode_t mode, 713171d99dSDavid Xu const struct mq_attr *attr) 724acaec8fSDavid Xu { 734acaec8fSDavid Xu struct __mq *mq; 744acaec8fSDavid Xu int err; 754acaec8fSDavid Xu 764acaec8fSDavid Xu mq = malloc(sizeof(struct __mq)); 774acaec8fSDavid Xu if (mq == NULL) 784acaec8fSDavid Xu return (NULL); 794acaec8fSDavid Xu 803171d99dSDavid Xu mq->oshandle = __sys_kmq_open(name, oflag, mode, attr); 814acaec8fSDavid Xu if (mq->oshandle != -1) { 824acaec8fSDavid Xu mq->node = NULL; 834acaec8fSDavid Xu return (mq); 844acaec8fSDavid Xu } 854acaec8fSDavid Xu err = errno; 864acaec8fSDavid Xu free(mq); 874acaec8fSDavid Xu errno = err; 884acaec8fSDavid Xu return ((mqd_t)-1L); 894acaec8fSDavid Xu } 904acaec8fSDavid Xu 914acaec8fSDavid Xu int 924acaec8fSDavid Xu __mq_close(mqd_t mqd) 934acaec8fSDavid Xu { 944acaec8fSDavid Xu int h; 954acaec8fSDavid Xu 964acaec8fSDavid Xu if (mqd->node != NULL) { 974acaec8fSDavid Xu __sigev_list_lock(); 984acaec8fSDavid Xu __sigev_delete_node(mqd->node); 994acaec8fSDavid Xu __sigev_list_unlock(); 1004acaec8fSDavid Xu } 1014acaec8fSDavid Xu h = mqd->oshandle; 1024acaec8fSDavid Xu free(mqd); 1034acaec8fSDavid Xu return (__sys_close(h)); 1044acaec8fSDavid Xu } 1054acaec8fSDavid Xu 1064acaec8fSDavid Xu typedef void (*mq_func)(union sigval val); 1074acaec8fSDavid Xu 1084acaec8fSDavid Xu static void 1096348ace8SDavid Xu mq_dispatch(struct sigev_node *sn) 1104acaec8fSDavid Xu { 1114acaec8fSDavid Xu mq_func f = sn->sn_func; 1124acaec8fSDavid Xu 1134acaec8fSDavid Xu /* 1144acaec8fSDavid Xu * Check generation before calling user function, 1154acaec8fSDavid Xu * this should avoid expired notification. 1164acaec8fSDavid Xu */ 1176348ace8SDavid Xu if (sn->sn_gen == sn->sn_info.si_value.sival_int) 1184acaec8fSDavid Xu f(sn->sn_value); 1194acaec8fSDavid Xu } 1204acaec8fSDavid Xu 1214acaec8fSDavid Xu int 1224acaec8fSDavid Xu __mq_notify(mqd_t mqd, const struct sigevent *evp) 1234acaec8fSDavid Xu { 1244acaec8fSDavid Xu struct sigevent ev; 1254acaec8fSDavid Xu struct sigev_node *sn; 1264acaec8fSDavid Xu int ret; 1274acaec8fSDavid Xu 1284acaec8fSDavid Xu if (evp == NULL || evp->sigev_notify != SIGEV_THREAD) { 1294acaec8fSDavid Xu if (mqd->node != NULL) { 1304acaec8fSDavid Xu __sigev_list_lock(); 1314acaec8fSDavid Xu __sigev_delete_node(mqd->node); 1324acaec8fSDavid Xu mqd->node = NULL; 1334acaec8fSDavid Xu __sigev_list_unlock(); 1344acaec8fSDavid Xu } 1354acaec8fSDavid Xu return __sys_kmq_notify(mqd->oshandle, evp); 1364acaec8fSDavid Xu } 1374acaec8fSDavid Xu 1384acaec8fSDavid Xu if (__sigev_check_init()) { 1394acaec8fSDavid Xu /* 1404acaec8fSDavid Xu * Thread library is not enabled. 1414acaec8fSDavid Xu */ 1424acaec8fSDavid Xu errno = EINVAL; 1434acaec8fSDavid Xu return (-1); 1444acaec8fSDavid Xu } 1454acaec8fSDavid Xu 1466348ace8SDavid Xu sn = __sigev_alloc(SI_MESGQ, evp, mqd->node, 1); 1474acaec8fSDavid Xu if (sn == NULL) { 1484acaec8fSDavid Xu errno = EAGAIN; 1494acaec8fSDavid Xu return (-1); 1504acaec8fSDavid Xu } 1514acaec8fSDavid Xu 1524acaec8fSDavid Xu sn->sn_id = mqd->oshandle; 1534acaec8fSDavid Xu sn->sn_dispatch = mq_dispatch; 1544acaec8fSDavid Xu __sigev_get_sigevent(sn, &ev, sn->sn_gen); 1554acaec8fSDavid Xu __sigev_list_lock(); 1564acaec8fSDavid Xu if (mqd->node != NULL) 1574acaec8fSDavid Xu __sigev_delete_node(mqd->node); 1584acaec8fSDavid Xu mqd->node = sn; 1594acaec8fSDavid Xu __sigev_register(sn); 1604acaec8fSDavid Xu ret = __sys_kmq_notify(mqd->oshandle, &ev); 1614acaec8fSDavid Xu __sigev_list_unlock(); 1624acaec8fSDavid Xu return (ret); 1634acaec8fSDavid Xu } 1644acaec8fSDavid Xu 1654acaec8fSDavid Xu int 1664acaec8fSDavid Xu __mq_getattr(mqd_t mqd, struct mq_attr *attr) 1674acaec8fSDavid Xu { 1684acaec8fSDavid Xu 1694acaec8fSDavid Xu return __sys_kmq_setattr(mqd->oshandle, NULL, attr); 1704acaec8fSDavid Xu } 1714acaec8fSDavid Xu 1724acaec8fSDavid Xu int 1734acaec8fSDavid Xu __mq_setattr(mqd_t mqd, const struct mq_attr *newattr, struct mq_attr *oldattr) 1744acaec8fSDavid Xu { 1754acaec8fSDavid Xu 1764acaec8fSDavid Xu return __sys_kmq_setattr(mqd->oshandle, newattr, oldattr); 1774acaec8fSDavid Xu } 1784acaec8fSDavid Xu 1794acaec8fSDavid Xu ssize_t 1804acaec8fSDavid Xu __mq_timedreceive(mqd_t mqd, char *buf, size_t len, 1814acaec8fSDavid Xu unsigned *prio, const struct timespec *timeout) 1824acaec8fSDavid Xu { 1834acaec8fSDavid Xu 1844acaec8fSDavid Xu return __sys_kmq_timedreceive(mqd->oshandle, buf, len, prio, timeout); 1854acaec8fSDavid Xu } 1864acaec8fSDavid Xu 1874acaec8fSDavid Xu ssize_t 18872757b75SDavid Xu __mq_timedreceive_cancel(mqd_t mqd, char *buf, size_t len, 18972757b75SDavid Xu unsigned *prio, const struct timespec *timeout) 19072757b75SDavid Xu { 19172757b75SDavid Xu int ret; 19272757b75SDavid Xu 193f4213b90SDavid Xu _pthread_cancel_enter(1); 19472757b75SDavid Xu ret = __sys_kmq_timedreceive(mqd->oshandle, buf, len, prio, timeout); 195f4213b90SDavid Xu _pthread_cancel_leave(ret == -1); 19672757b75SDavid Xu return (ret); 19772757b75SDavid Xu } 19872757b75SDavid Xu 19972757b75SDavid Xu ssize_t 2004acaec8fSDavid Xu __mq_receive(mqd_t mqd, char *buf, size_t len, unsigned *prio) 2014acaec8fSDavid Xu { 2024acaec8fSDavid Xu 2034acaec8fSDavid Xu return __sys_kmq_timedreceive(mqd->oshandle, buf, len, prio, NULL); 2044acaec8fSDavid Xu } 2054acaec8fSDavid Xu 2064acaec8fSDavid Xu ssize_t 20772757b75SDavid Xu __mq_receive_cancel(mqd_t mqd, char *buf, size_t len, unsigned *prio) 20872757b75SDavid Xu { 20972757b75SDavid Xu int ret; 21072757b75SDavid Xu 211f4213b90SDavid Xu _pthread_cancel_enter(1); 21272757b75SDavid Xu ret = __sys_kmq_timedreceive(mqd->oshandle, buf, len, prio, NULL); 213f4213b90SDavid Xu _pthread_cancel_leave(ret == -1); 21472757b75SDavid Xu return (ret); 21572757b75SDavid Xu } 21672757b75SDavid Xu ssize_t 2174acaec8fSDavid Xu __mq_timedsend(mqd_t mqd, char *buf, size_t len, 2184acaec8fSDavid Xu unsigned prio, const struct timespec *timeout) 2194acaec8fSDavid Xu { 2204acaec8fSDavid Xu 2214acaec8fSDavid Xu return __sys_kmq_timedsend(mqd->oshandle, buf, len, prio, timeout); 2224acaec8fSDavid Xu } 2234acaec8fSDavid Xu 2244acaec8fSDavid Xu ssize_t 22572757b75SDavid Xu __mq_timedsend_cancel(mqd_t mqd, char *buf, size_t len, 22672757b75SDavid Xu unsigned prio, const struct timespec *timeout) 22772757b75SDavid Xu { 22872757b75SDavid Xu int ret; 22972757b75SDavid Xu 230f4213b90SDavid Xu _pthread_cancel_enter(1); 23172757b75SDavid Xu ret = __sys_kmq_timedsend(mqd->oshandle, buf, len, prio, timeout); 232f4213b90SDavid Xu _pthread_cancel_leave(ret == -1); 23372757b75SDavid Xu return (ret); 23472757b75SDavid Xu } 23572757b75SDavid Xu 23672757b75SDavid Xu ssize_t 2374acaec8fSDavid Xu __mq_send(mqd_t mqd, char *buf, size_t len, unsigned prio) 2384acaec8fSDavid Xu { 2394acaec8fSDavid Xu 2404acaec8fSDavid Xu return __sys_kmq_timedsend(mqd->oshandle, buf, len, prio, NULL); 2414acaec8fSDavid Xu } 2424acaec8fSDavid Xu 24372757b75SDavid Xu 24472757b75SDavid Xu ssize_t 24572757b75SDavid Xu __mq_send_cancel(mqd_t mqd, char *buf, size_t len, unsigned prio) 24672757b75SDavid Xu { 24772757b75SDavid Xu int ret; 24872757b75SDavid Xu 249f4213b90SDavid Xu _pthread_cancel_enter(1); 25072757b75SDavid Xu ret = __sys_kmq_timedsend(mqd->oshandle, buf, len, prio, NULL); 251f4213b90SDavid Xu _pthread_cancel_leave(ret == -1); 25272757b75SDavid Xu return (ret); 25372757b75SDavid Xu } 25472757b75SDavid Xu 2554acaec8fSDavid Xu int 2564acaec8fSDavid Xu __mq_unlink(const char *path) 2574acaec8fSDavid Xu { 2584acaec8fSDavid Xu 2594acaec8fSDavid Xu return __sys_kmq_unlink(path); 2604acaec8fSDavid Xu } 2614acaec8fSDavid Xu 262ddce1c3dSKonstantin Belousov #pragma weak mq_getfd_np 2634acaec8fSDavid Xu int 264ddce1c3dSKonstantin Belousov mq_getfd_np(mqd_t mqd) 2654acaec8fSDavid Xu { 266a620d098SDavid Xu 267a620d098SDavid Xu return (mqd->oshandle); 2684acaec8fSDavid Xu } 269