1156136Sdavidxu/*- 2156136Sdavidxu * Copyright (c) 2006 David Xu <davidxu@freebsd.org> 3156136Sdavidxu * All rights reserved. 4156136Sdavidxu * 5156136Sdavidxu * Redistribution and use in source and binary forms, with or without 6156136Sdavidxu * modification, are permitted provided that the following conditions 7156136Sdavidxu * are met: 8156136Sdavidxu * 1. Redistributions of source code must retain the above copyright 9156136Sdavidxu * notice, this list of conditions and the following disclaimer. 10156136Sdavidxu * 2. Redistributions in binary form must reproduce the above copyright 11156136Sdavidxu * notice, this list of conditions and the following disclaimer in the 12156136Sdavidxu * documentation and/or other materials provided with the distribution. 13156136Sdavidxu * 14156136Sdavidxu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15156136Sdavidxu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16156136Sdavidxu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17156136Sdavidxu * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18156136Sdavidxu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19156136Sdavidxu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20156136Sdavidxu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21156136Sdavidxu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22156136Sdavidxu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23156136Sdavidxu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24156136Sdavidxu * SUCH DAMAGE. 25156136Sdavidxu * 26156136Sdavidxu * $FreeBSD$ 27156136Sdavidxu */ 28156136Sdavidxu 29156136Sdavidxu#include <sys/cdefs.h> 30156136Sdavidxu#include <sys/types.h> 31156136Sdavidxu#include <sys/syscall.h> 32156136Sdavidxu#include <sys/mqueue.h> 33156136Sdavidxu 34156136Sdavidxu#include "namespace.h" 35156136Sdavidxu#include <errno.h> 36199475Sdavidxu#include <pthread.h> 37156136Sdavidxu#include <stddef.h> 38156136Sdavidxu#include <stdlib.h> 39156136Sdavidxu#include <signal.h> 40156136Sdavidxu#include "sigev_thread.h" 41156136Sdavidxu#include "un-namespace.h" 42213153Sdavidxu#include "libc_private.h" 43156136Sdavidxu 44156136Sdavidxuextern int __sys_kmq_notify(int, const struct sigevent *); 45156141Sdavidxuextern int __sys_kmq_open(const char *, int, mode_t, 46156141Sdavidxu const struct mq_attr *); 47156136Sdavidxuextern int __sys_kmq_setattr(int, const struct mq_attr *__restrict, 48156136Sdavidxu struct mq_attr *__restrict); 49156136Sdavidxuextern ssize_t __sys_kmq_timedreceive(int, char *__restrict, size_t, 50156136Sdavidxu unsigned *__restrict, const struct timespec *__restrict); 51156136Sdavidxuextern int __sys_kmq_timedsend(int, const char *, size_t, unsigned, 52156136Sdavidxu const struct timespec *); 53156136Sdavidxuextern int __sys_kmq_unlink(const char *); 54156136Sdavidxuextern int __sys_close(int fd); 55156136Sdavidxu 56156136Sdavidxustruct __mq { 57156136Sdavidxu int oshandle; 58156136Sdavidxu struct sigev_node *node; 59156136Sdavidxu}; 60156136Sdavidxu 61156136Sdavidxu__weak_reference(__mq_open, mq_open); 62156136Sdavidxu__weak_reference(__mq_open, _mq_open); 63156136Sdavidxu__weak_reference(__mq_close, mq_close); 64156136Sdavidxu__weak_reference(__mq_close, _mq_close); 65156136Sdavidxu__weak_reference(__mq_notify, mq_notify); 66156136Sdavidxu__weak_reference(__mq_notify, _mq_notify); 67156136Sdavidxu__weak_reference(__mq_getattr, mq_getattr); 68156136Sdavidxu__weak_reference(__mq_getattr, _mq_getattr); 69156136Sdavidxu__weak_reference(__mq_setattr, mq_setattr); 70156136Sdavidxu__weak_reference(__mq_setattr, _mq_setattr); 71199475Sdavidxu__weak_reference(__mq_timedreceive_cancel, mq_timedreceive); 72156136Sdavidxu__weak_reference(__mq_timedreceive, _mq_timedreceive); 73199475Sdavidxu__weak_reference(__mq_timedsend_cancel, mq_timedsend); 74156136Sdavidxu__weak_reference(__mq_timedsend, _mq_timedsend); 75156136Sdavidxu__weak_reference(__mq_unlink, mq_unlink); 76156136Sdavidxu__weak_reference(__mq_unlink, _mq_unlink); 77199475Sdavidxu__weak_reference(__mq_send_cancel, mq_send); 78156136Sdavidxu__weak_reference(__mq_send, _mq_send); 79199475Sdavidxu__weak_reference(__mq_receive_cancel, mq_receive); 80156136Sdavidxu__weak_reference(__mq_receive, _mq_receive); 81156136Sdavidxu 82156136Sdavidxumqd_t 83156141Sdavidxu__mq_open(const char *name, int oflag, mode_t mode, 84156141Sdavidxu const struct mq_attr *attr) 85156136Sdavidxu{ 86156136Sdavidxu struct __mq *mq; 87156136Sdavidxu int err; 88156136Sdavidxu 89156136Sdavidxu mq = malloc(sizeof(struct __mq)); 90156136Sdavidxu if (mq == NULL) 91156136Sdavidxu return (NULL); 92156136Sdavidxu 93156141Sdavidxu mq->oshandle = __sys_kmq_open(name, oflag, mode, attr); 94156136Sdavidxu if (mq->oshandle != -1) { 95156136Sdavidxu mq->node = NULL; 96156136Sdavidxu return (mq); 97156136Sdavidxu } 98156136Sdavidxu err = errno; 99156136Sdavidxu free(mq); 100156136Sdavidxu errno = err; 101156136Sdavidxu return ((mqd_t)-1L); 102156136Sdavidxu} 103156136Sdavidxu 104156136Sdavidxuint 105156136Sdavidxu__mq_close(mqd_t mqd) 106156136Sdavidxu{ 107156136Sdavidxu int h; 108156136Sdavidxu 109156136Sdavidxu if (mqd->node != NULL) { 110156136Sdavidxu __sigev_list_lock(); 111156136Sdavidxu __sigev_delete_node(mqd->node); 112156136Sdavidxu __sigev_list_unlock(); 113156136Sdavidxu } 114156136Sdavidxu h = mqd->oshandle; 115156136Sdavidxu free(mqd); 116156136Sdavidxu return (__sys_close(h)); 117156136Sdavidxu} 118156136Sdavidxu 119156136Sdavidxutypedef void (*mq_func)(union sigval val); 120156136Sdavidxu 121156136Sdavidxustatic void 122156267Sdavidxumq_dispatch(struct sigev_node *sn) 123156136Sdavidxu{ 124156136Sdavidxu mq_func f = sn->sn_func; 125156136Sdavidxu 126156136Sdavidxu /* 127156136Sdavidxu * Check generation before calling user function, 128156136Sdavidxu * this should avoid expired notification. 129156136Sdavidxu */ 130156267Sdavidxu if (sn->sn_gen == sn->sn_info.si_value.sival_int) 131156136Sdavidxu f(sn->sn_value); 132156136Sdavidxu} 133156136Sdavidxu 134156136Sdavidxuint 135156136Sdavidxu__mq_notify(mqd_t mqd, const struct sigevent *evp) 136156136Sdavidxu{ 137156136Sdavidxu struct sigevent ev; 138156136Sdavidxu struct sigev_node *sn; 139156136Sdavidxu int ret; 140156136Sdavidxu 141156136Sdavidxu if (evp == NULL || evp->sigev_notify != SIGEV_THREAD) { 142156136Sdavidxu if (mqd->node != NULL) { 143156136Sdavidxu __sigev_list_lock(); 144156136Sdavidxu __sigev_delete_node(mqd->node); 145156136Sdavidxu mqd->node = NULL; 146156136Sdavidxu __sigev_list_unlock(); 147156136Sdavidxu } 148156136Sdavidxu return __sys_kmq_notify(mqd->oshandle, evp); 149156136Sdavidxu } 150156136Sdavidxu 151156136Sdavidxu if (__sigev_check_init()) { 152156136Sdavidxu /* 153156136Sdavidxu * Thread library is not enabled. 154156136Sdavidxu */ 155156136Sdavidxu errno = EINVAL; 156156136Sdavidxu return (-1); 157156136Sdavidxu } 158156136Sdavidxu 159156267Sdavidxu sn = __sigev_alloc(SI_MESGQ, evp, mqd->node, 1); 160156136Sdavidxu if (sn == NULL) { 161156136Sdavidxu errno = EAGAIN; 162156136Sdavidxu return (-1); 163156136Sdavidxu } 164156136Sdavidxu 165156136Sdavidxu sn->sn_id = mqd->oshandle; 166156136Sdavidxu sn->sn_dispatch = mq_dispatch; 167156136Sdavidxu __sigev_get_sigevent(sn, &ev, sn->sn_gen); 168156136Sdavidxu __sigev_list_lock(); 169156136Sdavidxu if (mqd->node != NULL) 170156136Sdavidxu __sigev_delete_node(mqd->node); 171156136Sdavidxu mqd->node = sn; 172156136Sdavidxu __sigev_register(sn); 173156136Sdavidxu ret = __sys_kmq_notify(mqd->oshandle, &ev); 174156136Sdavidxu __sigev_list_unlock(); 175156136Sdavidxu return (ret); 176156136Sdavidxu} 177156136Sdavidxu 178156136Sdavidxuint 179156136Sdavidxu__mq_getattr(mqd_t mqd, struct mq_attr *attr) 180156136Sdavidxu{ 181156136Sdavidxu 182156136Sdavidxu return __sys_kmq_setattr(mqd->oshandle, NULL, attr); 183156136Sdavidxu} 184156136Sdavidxu 185156136Sdavidxuint 186156136Sdavidxu__mq_setattr(mqd_t mqd, const struct mq_attr *newattr, struct mq_attr *oldattr) 187156136Sdavidxu{ 188156136Sdavidxu 189156136Sdavidxu return __sys_kmq_setattr(mqd->oshandle, newattr, oldattr); 190156136Sdavidxu} 191156136Sdavidxu 192156136Sdavidxussize_t 193156136Sdavidxu__mq_timedreceive(mqd_t mqd, char *buf, size_t len, 194156136Sdavidxu unsigned *prio, const struct timespec *timeout) 195156136Sdavidxu{ 196156136Sdavidxu 197156136Sdavidxu return __sys_kmq_timedreceive(mqd->oshandle, buf, len, prio, timeout); 198156136Sdavidxu} 199156136Sdavidxu 200156136Sdavidxussize_t 201199475Sdavidxu__mq_timedreceive_cancel(mqd_t mqd, char *buf, size_t len, 202199475Sdavidxu unsigned *prio, const struct timespec *timeout) 203199475Sdavidxu{ 204199475Sdavidxu int ret; 205199475Sdavidxu 206213153Sdavidxu _pthread_cancel_enter(1); 207199475Sdavidxu ret = __sys_kmq_timedreceive(mqd->oshandle, buf, len, prio, timeout); 208213153Sdavidxu _pthread_cancel_leave(ret == -1); 209199475Sdavidxu return (ret); 210199475Sdavidxu} 211199475Sdavidxu 212199475Sdavidxussize_t 213156136Sdavidxu__mq_receive(mqd_t mqd, char *buf, size_t len, unsigned *prio) 214156136Sdavidxu{ 215156136Sdavidxu 216156136Sdavidxu return __sys_kmq_timedreceive(mqd->oshandle, buf, len, prio, NULL); 217156136Sdavidxu} 218156136Sdavidxu 219156136Sdavidxussize_t 220199475Sdavidxu__mq_receive_cancel(mqd_t mqd, char *buf, size_t len, unsigned *prio) 221199475Sdavidxu{ 222199475Sdavidxu int ret; 223199475Sdavidxu 224213153Sdavidxu _pthread_cancel_enter(1); 225199475Sdavidxu ret = __sys_kmq_timedreceive(mqd->oshandle, buf, len, prio, NULL); 226213153Sdavidxu _pthread_cancel_leave(ret == -1); 227199475Sdavidxu return (ret); 228199475Sdavidxu} 229199475Sdavidxussize_t 230156136Sdavidxu__mq_timedsend(mqd_t mqd, char *buf, size_t len, 231156136Sdavidxu unsigned prio, const struct timespec *timeout) 232156136Sdavidxu{ 233156136Sdavidxu 234156136Sdavidxu return __sys_kmq_timedsend(mqd->oshandle, buf, len, prio, timeout); 235156136Sdavidxu} 236156136Sdavidxu 237156136Sdavidxussize_t 238199475Sdavidxu__mq_timedsend_cancel(mqd_t mqd, char *buf, size_t len, 239199475Sdavidxu unsigned prio, const struct timespec *timeout) 240199475Sdavidxu{ 241199475Sdavidxu int ret; 242199475Sdavidxu 243213153Sdavidxu _pthread_cancel_enter(1); 244199475Sdavidxu ret = __sys_kmq_timedsend(mqd->oshandle, buf, len, prio, timeout); 245213153Sdavidxu _pthread_cancel_leave(ret == -1); 246199475Sdavidxu return (ret); 247199475Sdavidxu} 248199475Sdavidxu 249199475Sdavidxussize_t 250156136Sdavidxu__mq_send(mqd_t mqd, char *buf, size_t len, unsigned prio) 251156136Sdavidxu{ 252156136Sdavidxu 253156136Sdavidxu return __sys_kmq_timedsend(mqd->oshandle, buf, len, prio, NULL); 254156136Sdavidxu} 255156136Sdavidxu 256199475Sdavidxu 257199475Sdavidxussize_t 258199475Sdavidxu__mq_send_cancel(mqd_t mqd, char *buf, size_t len, unsigned prio) 259199475Sdavidxu{ 260199475Sdavidxu int ret; 261199475Sdavidxu 262213153Sdavidxu _pthread_cancel_enter(1); 263199475Sdavidxu ret = __sys_kmq_timedsend(mqd->oshandle, buf, len, prio, NULL); 264213153Sdavidxu _pthread_cancel_leave(ret == -1); 265199475Sdavidxu return (ret); 266199475Sdavidxu} 267199475Sdavidxu 268156136Sdavidxuint 269156136Sdavidxu__mq_unlink(const char *path) 270156136Sdavidxu{ 271156136Sdavidxu 272156136Sdavidxu return __sys_kmq_unlink(path); 273156136Sdavidxu} 274156136Sdavidxu 275156136Sdavidxuint 276156136Sdavidxu__mq_oshandle(mqd_t mqd) 277156136Sdavidxu{ 278156193Sdavidxu 279156193Sdavidxu return (mqd->oshandle); 280156136Sdavidxu} 281