]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - lib/librt/mq.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / lib / librt / mq.c
1 /*-
2  * Copyright (c) 2006 David Xu <davidxu@freebsd.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
29 #include <sys/cdefs.h>
30 #include <sys/types.h>
31 #include <sys/syscall.h>
32 #include <sys/mqueue.h>
33
34 #include "namespace.h"
35 #include <errno.h>
36 #include <pthread.h>
37 #include <stddef.h>
38 #include <stdlib.h>
39 #include <signal.h>
40 #include "sigev_thread.h"
41 #include "un-namespace.h"
42 #include "libc_private.h"
43
44 extern int      __sys_kmq_notify(int, const struct sigevent *);
45 extern int      __sys_kmq_open(const char *, int, mode_t,
46                     const struct mq_attr *);
47 extern int      __sys_kmq_setattr(int, const struct mq_attr *__restrict,
48                     struct mq_attr *__restrict);
49 extern ssize_t  __sys_kmq_timedreceive(int, char *__restrict, size_t,
50                     unsigned *__restrict, const struct timespec *__restrict);
51 extern int      __sys_kmq_timedsend(int, const char *, size_t, unsigned,
52                     const struct timespec *);
53 extern int      __sys_kmq_unlink(const char *);
54 extern int      __sys_close(int fd);
55
56 struct __mq {
57         int oshandle;
58         struct sigev_node *node;
59 };
60
61 __weak_reference(__mq_open, mq_open);
62 __weak_reference(__mq_open, _mq_open);
63 __weak_reference(__mq_close, mq_close);
64 __weak_reference(__mq_close, _mq_close);
65 __weak_reference(__mq_notify, mq_notify);
66 __weak_reference(__mq_notify, _mq_notify);
67 __weak_reference(__mq_getattr, mq_getattr);
68 __weak_reference(__mq_getattr, _mq_getattr);
69 __weak_reference(__mq_setattr, mq_setattr);
70 __weak_reference(__mq_setattr, _mq_setattr);
71 __weak_reference(__mq_timedreceive_cancel, mq_timedreceive);
72 __weak_reference(__mq_timedreceive, _mq_timedreceive);
73 __weak_reference(__mq_timedsend_cancel, mq_timedsend);
74 __weak_reference(__mq_timedsend, _mq_timedsend);
75 __weak_reference(__mq_unlink, mq_unlink);
76 __weak_reference(__mq_unlink, _mq_unlink);
77 __weak_reference(__mq_send_cancel, mq_send);
78 __weak_reference(__mq_send, _mq_send);
79 __weak_reference(__mq_receive_cancel, mq_receive);
80 __weak_reference(__mq_receive, _mq_receive);
81
82 mqd_t
83 __mq_open(const char *name, int oflag, mode_t mode,
84         const struct mq_attr *attr)
85 {
86         struct __mq *mq;
87         int err;
88
89         mq = malloc(sizeof(struct __mq));
90         if (mq == NULL)
91                 return (NULL);
92
93         mq->oshandle = __sys_kmq_open(name, oflag, mode, attr);
94         if (mq->oshandle != -1) {
95                 mq->node = NULL;
96                 return (mq);
97         }
98         err = errno;
99         free(mq);
100         errno = err;
101         return ((mqd_t)-1L);
102 }
103
104 int
105 __mq_close(mqd_t mqd)
106 {
107         int h;
108
109         if (mqd->node != NULL) {
110                 __sigev_list_lock();
111                 __sigev_delete_node(mqd->node);
112                 __sigev_list_unlock();
113         }
114         h = mqd->oshandle;
115         free(mqd);
116         return (__sys_close(h));
117 }
118
119 typedef void (*mq_func)(union sigval val);
120
121 static void
122 mq_dispatch(struct sigev_node *sn)
123 {
124         mq_func f = sn->sn_func;
125
126         /*
127          * Check generation before calling user function,
128          * this should avoid expired notification.
129          */
130         if (sn->sn_gen == sn->sn_info.si_value.sival_int)
131                 f(sn->sn_value);
132 }
133
134 int
135 __mq_notify(mqd_t mqd, const struct sigevent *evp)
136 {
137         struct sigevent ev;
138         struct sigev_node *sn;
139         int ret;
140
141         if (evp == NULL || evp->sigev_notify != SIGEV_THREAD) {
142                 if (mqd->node != NULL) {
143                         __sigev_list_lock();
144                         __sigev_delete_node(mqd->node);
145                         mqd->node = NULL;
146                         __sigev_list_unlock();
147                 }
148                 return __sys_kmq_notify(mqd->oshandle, evp);
149         }
150
151         if (__sigev_check_init()) {
152                 /*
153                  * Thread library is not enabled.
154                  */
155                 errno = EINVAL;
156                 return (-1);
157         }
158
159         sn = __sigev_alloc(SI_MESGQ, evp, mqd->node, 1);
160         if (sn == NULL) {
161                 errno = EAGAIN;
162                 return (-1);
163         }
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
178 int
179 __mq_getattr(mqd_t mqd, struct mq_attr *attr)
180 {
181
182         return __sys_kmq_setattr(mqd->oshandle, NULL, attr);
183 }
184
185 int
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
192 ssize_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
200 ssize_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
212 ssize_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
219 ssize_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 }
229 ssize_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
237 ssize_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
249 ssize_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
257 ssize_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
268 int
269 __mq_unlink(const char *path)
270 {
271
272         return __sys_kmq_unlink(path);
273 }
274
275 int
276 __mq_oshandle(mqd_t mqd)
277 {
278
279         return (mqd->oshandle);
280 }