Skip to content

Commit c1643f9

Browse files
awojasinskicarlescufi
authored andcommitted
posix: Add implementation of mq_notify() function
The function was the last missing piece of the `_POSIX_MESSAGE_PASSING` option group. Due to lack of signal subsystem in the Zephyr RTOS the `sigev_notify` member of the `sigevent` structure that describes the notification cannot be set to `SIGEV_SIGNAL` - this notification type is not implemented, the function will return -1 and set `errno` to `ENOSYS`. `mq_notify` documentation: https://pubs.opengroup.org/onlinepubs/9699919799/functions/mq_notify.html Fixes #66958 Signed-off-by: Adam Wojasinski <[email protected]>
1 parent 9f1c256 commit c1643f9

File tree

2 files changed

+102
-2
lines changed

2 files changed

+102
-2
lines changed

include/zephyr/posix/mqueue.h

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <zephyr/kernel.h>
1111
#include <zephyr/posix/time.h>
1212
#include <zephyr/posix/fcntl.h>
13+
#include <zephyr/posix/signal.h>
1314
#include <zephyr/posix/sys/stat.h>
1415
#include "posix_types.h"
1516

@@ -40,6 +41,7 @@ int mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len,
4041
unsigned int *msg_prio, const struct timespec *abstime);
4142
int mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len,
4243
unsigned int msg_prio, const struct timespec *abstime);
44+
int mq_notify(mqd_t mqdes, const struct sigevent *notification);
4345

4446
#ifdef __cplusplus
4547
}

lib/posix/mqueue.c

+100-2
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
/*
22
* Copyright (c) 2018 Intel Corporation
3+
* Copyright (c) 2024 BayLibre, SAS
34
*
45
* SPDX-License-Identifier: Apache-2.0
56
*/
67
#include <zephyr/kernel.h>
78
#include <errno.h>
89
#include <string.h>
910
#include <zephyr/sys/atomic.h>
10-
#include <zephyr/posix/time.h>
1111
#include <zephyr/posix/mqueue.h>
12+
#include <zephyr/posix/pthread.h>
13+
14+
#define SIGEV_MASK (SIGEV_NONE | SIGEV_SIGNAL | SIGEV_THREAD)
1215

1316
typedef struct mqueue_object {
1417
sys_snode_t snode;
@@ -17,6 +20,7 @@ typedef struct mqueue_object {
1720
struct k_msgq queue;
1821
atomic_t ref_count;
1922
char *name;
23+
struct sigevent not;
2024
} mqueue_object;
2125

2226
typedef struct mqueue_desc {
@@ -34,9 +38,11 @@ int64_t timespec_to_timeoutms(const struct timespec *abstime);
3438
static mqueue_object *find_in_list(const char *name);
3539
static int32_t send_message(mqueue_desc *mqd, const char *msg_ptr, size_t msg_len,
3640
k_timeout_t timeout);
37-
static int receive_message(mqueue_desc *mqd, char *msg_ptr, size_t msg_len,
41+
static int32_t receive_message(mqueue_desc *mqd, char *msg_ptr, size_t msg_len,
3842
k_timeout_t timeout);
43+
static void remove_notification(mqueue_object *msg_queue);
3944
static void remove_mq(mqueue_object *msg_queue);
45+
static void *mq_notify_thread(void *arg);
4046

4147
/**
4248
* @brief Open a message queue.
@@ -341,6 +347,74 @@ int mq_setattr(mqd_t mqdes, const struct mq_attr *mqstat,
341347
return 0;
342348
}
343349

350+
/**
351+
* @brief Notify process that a message is available.
352+
*
353+
* See IEEE 1003.1
354+
*/
355+
int mq_notify(mqd_t mqdes, const struct sigevent *notification)
356+
{
357+
mqueue_desc *mqd = (mqueue_desc *)mqdes;
358+
359+
if (mqd == NULL) {
360+
errno = EBADF;
361+
return -1;
362+
}
363+
364+
mqueue_object *msg_queue = mqd->mqueue;
365+
366+
if (notification == NULL) {
367+
if ((msg_queue->not.sigev_notify & SIGEV_MASK) == 0) {
368+
errno = EINVAL;
369+
return -1;
370+
}
371+
remove_notification(msg_queue);
372+
return 0;
373+
}
374+
375+
if ((msg_queue->not.sigev_notify & SIGEV_MASK) != 0) {
376+
errno = EBUSY;
377+
return -1;
378+
}
379+
if (notification->sigev_notify == SIGEV_SIGNAL) {
380+
errno = ENOSYS;
381+
return -1;
382+
}
383+
if (notification->sigev_notify_attributes != NULL) {
384+
int ret = pthread_attr_setdetachstate(notification->sigev_notify_attributes,
385+
PTHREAD_CREATE_DETACHED);
386+
if (ret != 0) {
387+
errno = ret;
388+
return -1;
389+
}
390+
}
391+
392+
k_sem_take(&mq_sem, K_FOREVER);
393+
memcpy(&msg_queue->not, notification, sizeof(struct sigevent));
394+
k_sem_give(&mq_sem);
395+
396+
return 0;
397+
}
398+
399+
static void *mq_notify_thread(void *arg)
400+
{
401+
mqueue_object *mqueue = (mqueue_object *)arg;
402+
struct sigevent *sevp = &mqueue->not;
403+
404+
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
405+
406+
if (sevp->sigev_notify_attributes == NULL) {
407+
pthread_detach(pthread_self());
408+
}
409+
410+
sevp->sigev_notify_function(sevp->sigev_value);
411+
412+
remove_notification(mqueue);
413+
414+
pthread_exit(NULL);
415+
return NULL;
416+
}
417+
344418
/* Internal functions */
345419
static mqueue_object *find_in_list(const char *name)
346420
{
@@ -380,11 +454,28 @@ static int32_t send_message(mqueue_desc *mqd, const char *msg_ptr, size_t msg_le
380454
return ret;
381455
}
382456

457+
uint32_t msgq_num = k_msgq_num_used_get(&mqd->mqueue->queue);
458+
383459
if (k_msgq_put(&mqd->mqueue->queue, (void *)msg_ptr, timeout) != 0) {
384460
errno = K_TIMEOUT_EQ(timeout, K_NO_WAIT) ? EAGAIN : ETIMEDOUT;
385461
return ret;
386462
}
387463

464+
if (k_msgq_num_used_get(&mqd->mqueue->queue) - msgq_num > 0) {
465+
struct sigevent *sevp = &mqd->mqueue->not;
466+
467+
if (sevp->sigev_notify == SIGEV_NONE) {
468+
sevp->sigev_notify_function(sevp->sigev_value);
469+
} else if (sevp->sigev_notify == SIGEV_THREAD) {
470+
pthread_t th;
471+
472+
ret = pthread_create(&th,
473+
sevp->sigev_notify_attributes,
474+
mq_notify_thread,
475+
mqd->mqueue);
476+
}
477+
}
478+
388479
return 0;
389480
}
390481

@@ -428,3 +519,10 @@ static void remove_mq(mqueue_object *msg_queue)
428519
k_free(msg_queue->mem_obj);
429520
}
430521
}
522+
523+
static void remove_notification(mqueue_object *msg_queue)
524+
{
525+
k_sem_take(&mq_sem, K_FOREVER);
526+
memset(&msg_queue->not, 0, sizeof(struct sigevent));
527+
k_sem_give(&mq_sem);
528+
}

0 commit comments

Comments
 (0)