1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
|
/*
* Copyright (c) 2006-2025 RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "syscall_internal.h"
/**
* @brief Open a message queue.
*
* This function opens a message queue for communication between processes.
* It can create a new message queue or open an existing one, depending on the specified
* flags.
*
* @param[in] name The name of the message queue. The name should be a null-terminated
* string and is subject to system-specific naming conventions.
* @param[in] flags Flags that control the behavior of the message queue. Common flags include:
* - `O_CREAT`: Create the message queue if it does not exist.
* - `O_EXCL`: Fail if the message queue already exists.
* - `O_RDONLY`: Open the queue for reading.
* - `O_WRONLY`: Open the queue for writing.
* - `O_RDWR`: Open the queue for both reading and writing.
* @param[in] mode The mode to be applied when creating the message queue, which defines
* the permissions for the message queue (e.g., read, write).
* @param[in] attr A pointer to a `struct mq_attr` that defines the attributes of the
* message queue, such as the maximum number of messages and the size of
* each message. If `NULL`, default values are used.
*
* @return mqd_t Returns a non-negative file descriptor for the message queue on success.
* On failure, returns `-1` and sets `errno` to indicate the error.
*
* @note If the message queue is created, its attributes (such as the maximum number of
* messages and message size) must be defined in the `mq_attr` structure. If the
* `O_CREAT` flag is not specified and the queue does not exist, the function will
* return `-1`.
*/
mqd_t sys_mq_open(const char *name, int flags, mode_t mode, struct mq_attr *attr)
{
mqd_t mqdes;
sysret_t ret = 0;
#ifdef ARCH_MM_MMU
char *kname = RT_NULL;
rt_size_t len = 0;
struct mq_attr attr_k;
len = lwp_user_strlen(name);
if (!len)
{
return (mqd_t)-EINVAL;
}
kname = (char *)kmem_get(len + 1);
if (!kname)
{
return (mqd_t)-ENOMEM;
}
if (attr == NULL)
{
attr_k.mq_maxmsg = 10;
attr_k.mq_msgsize = 8192;
attr_k.mq_flags = 0;
attr = &attr_k;
}
else
{
if (!lwp_get_from_user(&attr_k, (void *)attr, sizeof(struct mq_attr)))
{
return -EINVAL;
}
}
lwp_get_from_user(kname, (void *)name, len + 1);
mqdes = mq_open(kname, flags, mode, &attr_k);
if (mqdes == -1)
{
ret = GET_ERRNO();
}
lwp_put_to_user(attr, &attr_k, sizeof(struct mq_attr));
kmem_put(kname);
#else
mqdes = mq_open(name, flags, mode, attr);
#endif
if (mqdes == -1)
{
return (mqd_t)ret;
}
else
{
return mqdes;
}
}
/**
* @brief Remove a message queue.
*
* This function removes a message queue identified by its name. If the message queue
* is open by any process, it will be removed only when all the processes close their
* file descriptors associated with the message queue.
*
* @param[in] name The name of the message queue to be removed. It should be a null-terminated
* string that conforms to system-specific naming conventions.
*
* @return sysret_t Returns `0` on success. On failure, returns a negative
* error code.
*
* @note After a successful call, the message queue is removed from the system. However,
* the removal will not take effect until all processes close their file descriptors
* associated with the queue. The function will fail if the message queue is still
* open by other processes.
*/
sysret_t sys_mq_unlink(const char *name)
{
int ret = 0;
#ifdef ARCH_MM_MMU
char *kname = RT_NULL;
rt_size_t len = 0;
len = lwp_user_strlen(name);
if (!len)
{
return -EINVAL;
}
kname = (char *)kmem_get(len + 1);
if (!kname)
{
return -ENOMEM;
}
lwp_get_from_user(kname, (void *)name, len + 1);
ret = mq_unlink(kname);
if (ret < 0)
{
ret = GET_ERRNO();
}
kmem_put(kname);
return ret;
#else
ret = mq_unlink(name);
return (ret < 0 ? GET_ERRNO() : ret);
#endif
}
/**
* @brief Send a message to a message queue with a timeout.
*
* This function sends a message to the specified message queue, but it allows the sender
* to specify a timeout. If the message queue is full, the function will block until either
* space becomes available or the specified timeout expires. If the timeout expires without
* space being available, the function returns an error.
*
* @param[in] mqd The message queue descriptor returned by `sys_mq_open`.
* @param[in] msg A pointer to the message to be sent.
* @param[in] len The length of the message to send.
* @param[in] prio The priority of the message (higher values indicate higher priority).
* @param[in] at A pointer to a `timespec` structure that specifies the absolute timeout.
* If the timeout expires before the message can be sent, the function returns
* an error.
*
* @return sysret_t Returns `0` on success. On failure, returns a negative error
* code.
*
* @note The function uses the `timespec` structure to specify the absolute timeout. The
* `at` parameter should indicate the time at which the operation should time out.
* If the timeout is `NULL`, the function will not apply any timeout (it will block
* indefinitely until the message is sent).
*
* @see sys_mq_send
*/
sysret_t sys_mq_timedsend(mqd_t mqd, const char *msg, size_t len, unsigned prio, const struct timespec *at)
{
int ret = 0;
#ifdef ARCH_MM_MMU
char *kmsg = RT_NULL;
struct timespec at_k;
kmsg = (char *)kmem_get(len + 1);
if (!kmsg)
{
return -ENOMEM;
}
lwp_get_from_user(&at_k, (void *)at, sizeof(struct timespec));
lwp_get_from_user(kmsg, (void *)msg, len + 1);
ret = mq_timedsend(mqd, kmsg, len, prio, &at_k);
if (ret < 0)
{
ret = GET_ERRNO();
}
kmem_put(kmsg);
return ret;
#else
ret = mq_timedsend(mqd, msg, len, prio, at);
return (ret < 0 ? GET_ERRNO() : ret);
#endif
}
/**
* @brief Receive a message from a message queue with a timeout.
*
* This function attempts to receive a message from the specified message queue, but it
* allows the receiver to specify a timeout. If the queue is empty, the function will block
* until either a message becomes available or the specified timeout expires. If the timeout
* expires without receiving a message, the function returns an error.
*
* @param[in] mqd The message queue descriptor returned by `sys_mq_open`.
* @param[out] msg A pointer to the buffer where the received message will be stored.
* @param[in] len The maximum length of the buffer to store the received message.
* @param[out] prio A pointer to an unsigned integer that will be set to the priority
* of the received message.
* @param[in] at A pointer to a `timespec` structure that specifies the absolute timeout.
* If the timeout expires before a message is received, the function will
* return an error.
*
* @return sysret_t Returns `0` on success. On failure, returns a negative error code.
*
* @note The function uses the `timespec` structure to specify the absolute timeout. The
* `at` parameter should indicate the time at which the operation should time out.
* If the timeout is `NULL`, the function will block indefinitely until a message is
* received.
*
* @see sys_mq_receive
*/
sysret_t sys_mq_timedreceive(mqd_t mqd, char * restrict msg, size_t len, unsigned * restrict prio, const struct timespec * restrict at)
{
int ret = 0;
#ifdef ARCH_MM_MMU
char * restrict kmsg = RT_NULL;
struct timespec at_k;
kmsg = (char * restrict)kmem_get(len + 1);
if (!kmsg)
{
return -ENOMEM;
}
lwp_get_from_user(kmsg, (void *)msg, len + 1);
if (at == RT_NULL)
{
ret = mq_timedreceive(mqd, kmsg, len, prio, RT_NULL);
}
else
{
if (!lwp_get_from_user(&at_k, (void *)at, sizeof(struct timespec)))
{
return -EINVAL;
}
ret = mq_timedreceive(mqd, kmsg, len, prio, &at_k);
}
if (ret > 0)
{
lwp_put_to_user(msg, kmsg, len + 1);
}
if (ret < 0)
{
ret = GET_ERRNO();
}
kmem_put(kmsg);
return ret;
#else
ret = mq_timedreceive(mqd, msg, len, prio, at);
return (ret < 0 ? GET_ERRNO() : ret);
#endif
}
/**
* @brief Set up asynchronous notification for a message queue.
*
* This function configures asynchronous notification for a message queue. When a message
* is available in the queue, the system can notify the calling process through a signal
* or another method specified in the `sigevent` structure. This is typically used to allow
* a process to be notified when a message arrives without having to block in the receive call.
*
* @param[in] mqd The message queue descriptor returned by `sys_mq_open`.
* @param[in] sev A pointer to a `sigevent` structure that specifies the notification
* mechanism to be used when a message is received. It could include
* signals or other notification types such as event flags or message passing.
*
* @return sysret_t Returns `0` on success. On failure, returns a negative error code.
*
* @note This function enables asynchronous notification, but the specific behavior depends
* on the configuration specified in the `sev` parameter, which could involve signals
* or other forms of notification.
*
* @see sys_mq_send, sys_mq_timedreceive
*/
sysret_t sys_mq_notify(mqd_t mqd, const struct sigevent *sev)
{
int ret = 0;
#ifdef ARCH_MM_MMU
struct sigevent sev_k;
lwp_get_from_user(&sev_k, (void *)sev, sizeof(struct timespec));
ret = mq_notify(mqd, &sev_k);
#else
ret = mq_notify(mqd, sev);
#endif
return (ret < 0 ? GET_ERRNO() : ret);
}
/**
* @brief Get or set attributes of a message queue.
*
* This function allows you to get or set the attributes of an existing message queue.
* If the `new` attribute structure is non-NULL, it updates the message queue with the new
* attributes. Otherwise, If the `old` attribute structure is non-NULL, it will return the current
* attributes of the message queue.
*
* @param[in] mqd The message queue descriptor returned by `sys_mq_open`.
* @param[in] new A pointer to a `mq_attr` structure containing the new attributes to set.
* If `NULL`, the function will not modify the message queue attributes.
* @param[out] old A pointer to a `mq_attr` structure where the current message queue
* attributes will be returned. If `NULL`, the current attributes will not
* be returned.
*
* @return sysret_t Returns `0` on success. On failure, returns a negative error code.
*
* @note The `mq_attr` structure contains parameters like the maximum number of messages,
* the maximum message size, and other attributes that control the behavior of the
* message queue.
*
* @see sys_mq_open, sys_mq_notify
*/
sysret_t sys_mq_getsetattr(mqd_t mqd, const struct mq_attr * restrict new, struct mq_attr * restrict old)
{
int ret = 0;
#ifdef ARCH_MM_MMU
size_t size = sizeof(struct mq_attr);
struct mq_attr * restrict knew = NULL;
struct mq_attr * restrict kold = NULL;
if (new != RT_NULL)
{
if (!lwp_user_accessable((void *)new, size))
{
return -EFAULT;
}
knew = kmem_get(size);
if (!knew)
{
return -ENOMEM;
}
lwp_get_from_user(knew, (void *)new, size);
}
if (!lwp_user_accessable((void *)old, size))
{
return -EFAULT;
}
kold = kmem_get(size);
if (!kold)
{
return -ENOMEM;
}
lwp_get_from_user(kold, (void *)old, size);
ret = mq_setattr(mqd, knew, kold);
if (ret != -1)
{
lwp_put_to_user(old, kold, size);
}
if (ret < 0)
{
ret = GET_ERRNO();
}
kmem_put(kold);
if (new != RT_NULL)
{
kmem_put(knew);
}
return ret;
#else
ret = mq_setattr(mqd, new, old);
return (ret < 0 ? GET_ERRNO() : ret);
#endif
}
/**
* @brief Close a message queue descriptor.
*
* This function closes a message queue descriptor. After calling this function, the
* descriptor can no longer be used to interact with the message queue. Any resources
* associated with the descriptor are released. If the message queue was opened with the
* `O_CLOEXEC` flag, it will be automatically closed when the calling process executes
* an `exec` system call.
*
* @param[in] mqd The message queue descriptor to be closed. It was previously returned
* by `sys_mq_open`.
*
* @return sysret_t Returns `0` on success. On failure, returns a negative error code.
*
* @see sys_mq_open, sys_mq_unlink
*/
sysret_t sys_mq_close(mqd_t mqd)
{
int ret = 0;
#ifdef ARCH_MM_MMU
ret = mq_close(mqd);
#else
ret = mq_close(mqd);
#endif
return (ret < 0 ? GET_ERRNO() : ret);
}
|