1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2006 David Xu <davidxu@freebsd.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/types.h>
30 #include <sys/syscall.h>
31 #include <sys/mqueue.h>
32
33 #include "namespace.h"
34 #include <errno.h>
35 #include <pthread.h>
36 #include <stddef.h>
37 #include <stdlib.h>
38 #include <signal.h>
39 #include "sigev_thread.h"
40 #include "un-namespace.h"
41 #include "libc_private.h"
42
43 struct __mq {
44 int oshandle;
45 struct sigev_node *node;
46 };
47
48 __weak_reference(__mq_open, mq_open);
49 __weak_reference(__mq_open, _mq_open);
50 __weak_reference(__mq_close, mq_close);
51 __weak_reference(__mq_close, _mq_close);
52 __weak_reference(__mq_notify, mq_notify);
53 __weak_reference(__mq_notify, _mq_notify);
54 __weak_reference(__mq_getattr, mq_getattr);
55 __weak_reference(__mq_getattr, _mq_getattr);
56 __weak_reference(__mq_setattr, mq_setattr);
57 __weak_reference(__mq_setattr, _mq_setattr);
58 __weak_reference(__mq_timedreceive_cancel, mq_timedreceive);
59 __weak_reference(__mq_timedreceive, _mq_timedreceive);
60 __weak_reference(__mq_timedsend_cancel, mq_timedsend);
61 __weak_reference(__mq_timedsend, _mq_timedsend);
62 __weak_reference(__mq_unlink, mq_unlink);
63 __weak_reference(__mq_unlink, _mq_unlink);
64 __weak_reference(__mq_send_cancel, mq_send);
65 __weak_reference(__mq_send, _mq_send);
66 __weak_reference(__mq_receive_cancel, mq_receive);
67 __weak_reference(__mq_receive, _mq_receive);
68
69 mqd_t
__mq_open(const char * name,int oflag,mode_t mode,const struct mq_attr * attr)70 __mq_open(const char *name, int oflag, mode_t mode,
71 const struct mq_attr *attr)
72 {
73 struct __mq *mq;
74 int err;
75
76 mq = malloc(sizeof(struct __mq));
77 if (mq == NULL)
78 return (NULL);
79
80 mq->oshandle = __sys_kmq_open(name, oflag, mode, attr);
81 if (mq->oshandle != -1) {
82 mq->node = NULL;
83 return (mq);
84 }
85 err = errno;
86 free(mq);
87 errno = err;
88 return ((mqd_t)-1L);
89 }
90
91 int
__mq_close(mqd_t mqd)92 __mq_close(mqd_t mqd)
93 {
94 int h;
95
96 if (mqd->node != NULL) {
97 __sigev_list_lock();
98 __sigev_delete_node(mqd->node);
99 __sigev_list_unlock();
100 }
101 h = mqd->oshandle;
102 free(mqd);
103 return (__sys_close(h));
104 }
105
106 typedef void (*mq_func)(union sigval val);
107
108 static void
mq_dispatch(struct sigev_node * sn)109 mq_dispatch(struct sigev_node *sn)
110 {
111 mq_func f = sn->sn_func;
112
113 /*
114 * Check generation before calling user function,
115 * this should avoid expired notification.
116 */
117 if (sn->sn_gen == sn->sn_info.si_value.sival_int)
118 f(sn->sn_value);
119 }
120
121 int
__mq_notify(mqd_t mqd,const struct sigevent * evp)122 __mq_notify(mqd_t mqd, const struct sigevent *evp)
123 {
124 struct sigevent ev;
125 struct sigev_node *sn;
126 int ret;
127
128 if (evp == NULL || evp->sigev_notify != SIGEV_THREAD) {
129 if (mqd->node != NULL) {
130 __sigev_list_lock();
131 __sigev_delete_node(mqd->node);
132 mqd->node = NULL;
133 __sigev_list_unlock();
134 }
135 return __sys_kmq_notify(mqd->oshandle, evp);
136 }
137
138 if (__sigev_check_init()) {
139 /*
140 * Thread library is not enabled.
141 */
142 errno = EINVAL;
143 return (-1);
144 }
145
146 sn = __sigev_alloc(SI_MESGQ, evp, mqd->node, 1);
147 if (sn == NULL) {
148 errno = EAGAIN;
149 return (-1);
150 }
151
152 sn->sn_id = mqd->oshandle;
153 sn->sn_dispatch = mq_dispatch;
154 __sigev_get_sigevent(sn, &ev, sn->sn_gen);
155 __sigev_list_lock();
156 if (mqd->node != NULL)
157 __sigev_delete_node(mqd->node);
158 mqd->node = sn;
159 __sigev_register(sn);
160 ret = __sys_kmq_notify(mqd->oshandle, &ev);
161 __sigev_list_unlock();
162 return (ret);
163 }
164
165 int
__mq_getattr(mqd_t mqd,struct mq_attr * attr)166 __mq_getattr(mqd_t mqd, struct mq_attr *attr)
167 {
168
169 return __sys_kmq_setattr(mqd->oshandle, NULL, attr);
170 }
171
172 int
__mq_setattr(mqd_t mqd,const struct mq_attr * newattr,struct mq_attr * oldattr)173 __mq_setattr(mqd_t mqd, const struct mq_attr *newattr, struct mq_attr *oldattr)
174 {
175
176 return __sys_kmq_setattr(mqd->oshandle, newattr, oldattr);
177 }
178
179 ssize_t
__mq_timedreceive(mqd_t mqd,char * buf,size_t len,unsigned * prio,const struct timespec * timeout)180 __mq_timedreceive(mqd_t mqd, char *buf, size_t len,
181 unsigned *prio, const struct timespec *timeout)
182 {
183
184 return __sys_kmq_timedreceive(mqd->oshandle, buf, len, prio, timeout);
185 }
186
187 ssize_t
__mq_timedreceive_cancel(mqd_t mqd,char * buf,size_t len,unsigned * prio,const struct timespec * timeout)188 __mq_timedreceive_cancel(mqd_t mqd, char *buf, size_t len,
189 unsigned *prio, const struct timespec *timeout)
190 {
191 int ret;
192
193 _pthread_cancel_enter(1);
194 ret = __sys_kmq_timedreceive(mqd->oshandle, buf, len, prio, timeout);
195 _pthread_cancel_leave(ret == -1);
196 return (ret);
197 }
198
199 ssize_t
__mq_receive(mqd_t mqd,char * buf,size_t len,unsigned * prio)200 __mq_receive(mqd_t mqd, char *buf, size_t len, unsigned *prio)
201 {
202
203 return __sys_kmq_timedreceive(mqd->oshandle, buf, len, prio, NULL);
204 }
205
206 ssize_t
__mq_receive_cancel(mqd_t mqd,char * buf,size_t len,unsigned * prio)207 __mq_receive_cancel(mqd_t mqd, char *buf, size_t len, unsigned *prio)
208 {
209 int ret;
210
211 _pthread_cancel_enter(1);
212 ret = __sys_kmq_timedreceive(mqd->oshandle, buf, len, prio, NULL);
213 _pthread_cancel_leave(ret == -1);
214 return (ret);
215 }
216 ssize_t
__mq_timedsend(mqd_t mqd,char * buf,size_t len,unsigned prio,const struct timespec * timeout)217 __mq_timedsend(mqd_t mqd, char *buf, size_t len,
218 unsigned prio, const struct timespec *timeout)
219 {
220
221 return __sys_kmq_timedsend(mqd->oshandle, buf, len, prio, timeout);
222 }
223
224 ssize_t
__mq_timedsend_cancel(mqd_t mqd,char * buf,size_t len,unsigned prio,const struct timespec * timeout)225 __mq_timedsend_cancel(mqd_t mqd, char *buf, size_t len,
226 unsigned prio, const struct timespec *timeout)
227 {
228 int ret;
229
230 _pthread_cancel_enter(1);
231 ret = __sys_kmq_timedsend(mqd->oshandle, buf, len, prio, timeout);
232 _pthread_cancel_leave(ret == -1);
233 return (ret);
234 }
235
236 ssize_t
__mq_send(mqd_t mqd,char * buf,size_t len,unsigned prio)237 __mq_send(mqd_t mqd, char *buf, size_t len, unsigned prio)
238 {
239
240 return __sys_kmq_timedsend(mqd->oshandle, buf, len, prio, NULL);
241 }
242
243
244 ssize_t
__mq_send_cancel(mqd_t mqd,char * buf,size_t len,unsigned prio)245 __mq_send_cancel(mqd_t mqd, char *buf, size_t len, unsigned prio)
246 {
247 int ret;
248
249 _pthread_cancel_enter(1);
250 ret = __sys_kmq_timedsend(mqd->oshandle, buf, len, prio, NULL);
251 _pthread_cancel_leave(ret == -1);
252 return (ret);
253 }
254
255 int
__mq_unlink(const char * path)256 __mq_unlink(const char *path)
257 {
258
259 return __sys_kmq_unlink(path);
260 }
261
262 #pragma weak mq_getfd_np
263 int
mq_getfd_np(mqd_t mqd)264 mq_getfd_np(mqd_t mqd)
265 {
266
267 return (mqd->oshandle);
268 }
269