1153838Sdfr/*- 2153838Sdfr * Copyright (c) 2006 David Xu <davidxu@freebsd.org> 3153838Sdfr * All rights reserved. 4153838Sdfr * 5153838Sdfr * Redistribution and use in source and binary forms, with or without 6153838Sdfr * modification, are permitted provided that the following conditions 7153838Sdfr * are met: 8153838Sdfr * 1. Redistributions of source code must retain the above copyright 9153838Sdfr * notice, this list of conditions and the following disclaimer. 10153838Sdfr * 2. Redistributions in binary form must reproduce the above copyright 11153838Sdfr * notice, this list of conditions and the following disclaimer in the 12153838Sdfr * documentation and/or other materials provided with the distribution. 13153838Sdfr * 14153838Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15153838Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16153838Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17153838Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18153838Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19153838Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20153838Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21153838Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22153838Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23153838Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24153838Sdfr * SUCH DAMAGE. 25153838Sdfr * 26153838Sdfr * $FreeBSD$ 27153838Sdfr */ 28153838Sdfr 29153838Sdfr#include <sys/cdefs.h> 30203027Sgavin#include <sys/types.h> 31206622Suqs#include <sys/syscall.h> 32153838Sdfr#include <sys/mqueue.h> 33153838Sdfr 34153838Sdfr#include "namespace.h" 35153838Sdfr#include <errno.h> 36153838Sdfr#include <pthread.h> 37153838Sdfr#include <stddef.h> 38153838Sdfr#include <stdlib.h> 39153838Sdfr#include <signal.h> 40153838Sdfr#include "sigev_thread.h" 41153838Sdfr#include "un-namespace.h" 42153838Sdfr#include "libc_private.h" 43153838Sdfr 44153838Sdfrextern int __sys_kmq_notify(int, const struct sigevent *); 45153838Sdfrextern int __sys_kmq_open(const char *, int, mode_t, 46153838Sdfr const struct mq_attr *); 47153838Sdfrextern int __sys_kmq_setattr(int, const struct mq_attr *__restrict, 48153838Sdfr struct mq_attr *__restrict); 49153838Sdfrextern ssize_t __sys_kmq_timedreceive(int, char *__restrict, size_t, 50153838Sdfr unsigned *__restrict, const struct timespec *__restrict); 51153838Sdfrextern int __sys_kmq_timedsend(int, const char *, size_t, unsigned, 52153838Sdfr const struct timespec *); 53153838Sdfrextern int __sys_kmq_unlink(const char *); 54153838Sdfrextern int __sys_close(int fd); 55153838Sdfr 56153838Sdfrstruct __mq { 57153838Sdfr int oshandle; 58153838Sdfr struct sigev_node *node; 59153838Sdfr}; 60153838Sdfr 61153838Sdfr__weak_reference(__mq_open, mq_open); 62153838Sdfr__weak_reference(__mq_open, _mq_open); 63153838Sdfr__weak_reference(__mq_close, mq_close); 64153838Sdfr__weak_reference(__mq_close, _mq_close); 65153838Sdfr__weak_reference(__mq_notify, mq_notify); 66153838Sdfr__weak_reference(__mq_notify, _mq_notify); 67153838Sdfr__weak_reference(__mq_getattr, mq_getattr); 68153838Sdfr__weak_reference(__mq_getattr, _mq_getattr); 69153838Sdfr__weak_reference(__mq_setattr, mq_setattr); 70153838Sdfr__weak_reference(__mq_setattr, _mq_setattr); 71153838Sdfr__weak_reference(__mq_timedreceive_cancel, mq_timedreceive); 72153838Sdfr__weak_reference(__mq_timedreceive, _mq_timedreceive); 73153838Sdfr__weak_reference(__mq_timedsend_cancel, mq_timedsend); 74153838Sdfr__weak_reference(__mq_timedsend, _mq_timedsend); 75153838Sdfr__weak_reference(__mq_unlink, mq_unlink); 76153838Sdfr__weak_reference(__mq_unlink, _mq_unlink); 77153838Sdfr__weak_reference(__mq_send_cancel, mq_send); 78153838Sdfr__weak_reference(__mq_send, _mq_send); 79153838Sdfr__weak_reference(__mq_receive_cancel, mq_receive); 80153838Sdfr__weak_reference(__mq_receive, _mq_receive); 81153838Sdfr 82153838Sdfrmqd_t 83153838Sdfr__mq_open(const char *name, int oflag, mode_t mode, 84153838Sdfr const struct mq_attr *attr) 85153838Sdfr{ 86236746Sjoel struct __mq *mq; 87153838Sdfr int err; 88153838Sdfr 89153838Sdfr mq = malloc(sizeof(struct __mq)); 90153838Sdfr if (mq == NULL) 91153838Sdfr return (NULL); 92153838Sdfr 93153838Sdfr mq->oshandle = __sys_kmq_open(name, oflag, mode, attr); 94153838Sdfr if (mq->oshandle != -1) { 95153838Sdfr mq->node = NULL; 96153838Sdfr return (mq); 97153838Sdfr } 98153838Sdfr err = errno; 99153838Sdfr free(mq); 100153838Sdfr errno = err; 101153838Sdfr return ((mqd_t)-1L); 102153838Sdfr} 103153838Sdfr 104153838Sdfrint 105153838Sdfr__mq_close(mqd_t mqd) 106153838Sdfr{ 107153838Sdfr int h; 108153838Sdfr 109153838Sdfr if (mqd->node != NULL) { 110153838Sdfr __sigev_list_lock(); 111153838Sdfr __sigev_delete_node(mqd->node); 112236746Sjoel __sigev_list_unlock(); 113153838Sdfr } 114153838Sdfr h = mqd->oshandle; 115153838Sdfr free(mqd); 116153838Sdfr return (__sys_close(h)); 117153838Sdfr} 118153838Sdfr 119153838Sdfrtypedef void (*mq_func)(union sigval val); 120153838Sdfr 121153838Sdfrstatic void 122153838Sdfrmq_dispatch(struct sigev_node *sn) 123153838Sdfr{ 124153838Sdfr mq_func f = sn->sn_func; 125236746Sjoel 126153838Sdfr /* 127153838Sdfr * Check generation before calling user function, 128153838Sdfr * this should avoid expired notification. 129153838Sdfr */ 130173187Skeramida if (sn->sn_gen == sn->sn_info.si_value.sival_int) 131153838Sdfr f(sn->sn_value); 132153838Sdfr} 133153838Sdfr 134203027Sgavinint 135153838Sdfr__mq_notify(mqd_t mqd, const struct sigevent *evp) 136153838Sdfr{ 137153838Sdfr struct sigevent ev; 138154811Sdfr struct sigev_node *sn; 139154811Sdfr int ret; 140154811Sdfr 141154811Sdfr if (evp == NULL || evp->sigev_notify != SIGEV_THREAD) { 142154811Sdfr if (mqd->node != NULL) { 143154811Sdfr __sigev_list_lock(); 144154811Sdfr __sigev_delete_node(mqd->node); 145154811Sdfr mqd->node = NULL; 146154811Sdfr __sigev_list_unlock(); 147154811Sdfr } 148154811Sdfr return __sys_kmq_notify(mqd->oshandle, evp); 149154811Sdfr } 150154811Sdfr 151154811Sdfr if (__sigev_check_init()) { 152154811Sdfr /* 153154811Sdfr * Thread library is not enabled. 154154811Sdfr */ 155154811Sdfr errno = EINVAL; 156154811Sdfr return (-1); 157154811Sdfr } 158154811Sdfr 159154811Sdfr sn = __sigev_alloc(SI_MESGQ, evp, mqd->node, 1); 160154811Sdfr if (sn == NULL) { 161154811Sdfr errno = EAGAIN; 162154811Sdfr return (-1); 163154811Sdfr } 164 165 sn->sn_id = mqd->oshandle; 166 sn->sn_dispatch = mq_dispatch; 167 __sigev_get_sigevent(sn, &ev, sn->sn_gen); 168 __sigev_list_lock(); 169 if (mqd->node != NULL) 170 __sigev_delete_node(mqd->node); 171 mqd->node = sn; 172 __sigev_register(sn); 173 ret = __sys_kmq_notify(mqd->oshandle, &ev); 174 __sigev_list_unlock(); 175 return (ret); 176} 177 178int 179__mq_getattr(mqd_t mqd, struct mq_attr *attr) 180{ 181 182 return __sys_kmq_setattr(mqd->oshandle, NULL, attr); 183} 184 185int 186__mq_setattr(mqd_t mqd, const struct mq_attr *newattr, struct mq_attr *oldattr) 187{ 188 189 return __sys_kmq_setattr(mqd->oshandle, newattr, oldattr); 190} 191 192ssize_t 193__mq_timedreceive(mqd_t mqd, char *buf, size_t len, 194 unsigned *prio, const struct timespec *timeout) 195{ 196 197 return __sys_kmq_timedreceive(mqd->oshandle, buf, len, prio, timeout); 198} 199 200ssize_t 201__mq_timedreceive_cancel(mqd_t mqd, char *buf, size_t len, 202 unsigned *prio, const struct timespec *timeout) 203{ 204 int ret; 205 206 _pthread_cancel_enter(1); 207 ret = __sys_kmq_timedreceive(mqd->oshandle, buf, len, prio, timeout); 208 _pthread_cancel_leave(ret == -1); 209 return (ret); 210} 211 212ssize_t 213__mq_receive(mqd_t mqd, char *buf, size_t len, unsigned *prio) 214{ 215 216 return __sys_kmq_timedreceive(mqd->oshandle, buf, len, prio, NULL); 217} 218 219ssize_t 220__mq_receive_cancel(mqd_t mqd, char *buf, size_t len, unsigned *prio) 221{ 222 int ret; 223 224 _pthread_cancel_enter(1); 225 ret = __sys_kmq_timedreceive(mqd->oshandle, buf, len, prio, NULL); 226 _pthread_cancel_leave(ret == -1); 227 return (ret); 228} 229ssize_t 230__mq_timedsend(mqd_t mqd, char *buf, size_t len, 231 unsigned prio, const struct timespec *timeout) 232{ 233 234 return __sys_kmq_timedsend(mqd->oshandle, buf, len, prio, timeout); 235} 236 237ssize_t 238__mq_timedsend_cancel(mqd_t mqd, char *buf, size_t len, 239 unsigned prio, const struct timespec *timeout) 240{ 241 int ret; 242 243 _pthread_cancel_enter(1); 244 ret = __sys_kmq_timedsend(mqd->oshandle, buf, len, prio, timeout); 245 _pthread_cancel_leave(ret == -1); 246 return (ret); 247} 248 249ssize_t 250__mq_send(mqd_t mqd, char *buf, size_t len, unsigned prio) 251{ 252 253 return __sys_kmq_timedsend(mqd->oshandle, buf, len, prio, NULL); 254} 255 256 257ssize_t 258__mq_send_cancel(mqd_t mqd, char *buf, size_t len, unsigned prio) 259{ 260 int ret; 261 262 _pthread_cancel_enter(1); 263 ret = __sys_kmq_timedsend(mqd->oshandle, buf, len, prio, NULL); 264 _pthread_cancel_leave(ret == -1); 265 return (ret); 266} 267 268int 269__mq_unlink(const char *path) 270{ 271 272 return __sys_kmq_unlink(path); 273} 274 275int 276__mq_oshandle(mqd_t mqd) 277{ 278 279 return (mqd->oshandle); 280} 281