Skip to content

posix: Implement mq_notify() #67988

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 25, 2024

Conversation

awojasinski
Copy link
Collaborator

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

@zephyrbot zephyrbot added the area: POSIX POSIX API Library label Jan 23, 2024
@zephyrbot zephyrbot requested review from cfriedt and ycsin January 23, 2024 09:25
Copy link
Member

@ycsin ycsin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

try not to modify unrelated lines, with the right config I think you can format just the modified lines in vscode

@awojasinski
Copy link
Collaborator Author

try not to modify unrelated lines, with the right config I think you can format just the modified lines in vscode

@ycsin just tried to fix some formatting issues but don't need to do that

@ycsin
Copy link
Member

ycsin commented Jan 23, 2024

Looks like you need a rebase

@awojasinski awojasinski force-pushed the posix_mqnotify branch 2 times, most recently from 514134a to 579e0cd Compare January 23, 2024 13:19
@awojasinski awojasinski requested a review from ycsin January 23, 2024 15:29
Comment on lines 260 to 271
struct mq_attr attrs;
struct sigevent not;
int32_t mode = 0777;
int flags = O_RDWR | O_CREAT;

attrs.mq_msgsize = MESSAGE_SIZE;
attrs.mq_maxmsg = MESG_COUNT_PERMQ;

not.sigev_notify_function = notify_function_basic;
not.sigev_notify_attributes = NULL;
not.sigev_notify = SIGEV_SIGNAL;
not.sigev_value.sival_ptr = (void *)&notification_executed;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a blocker, but attrs and not could be initialized where they are declared (we support C11 by default, so no need to use only C89 declarations). It might be a bit less verbose, but also, there would be no need to initialize anything to 0 / NULL explicitly.

Suggested change
struct mq_attr attrs;
struct sigevent not;
int32_t mode = 0777;
int flags = O_RDWR | O_CREAT;
attrs.mq_msgsize = MESSAGE_SIZE;
attrs.mq_maxmsg = MESG_COUNT_PERMQ;
not.sigev_notify_function = notify_function_basic;
not.sigev_notify_attributes = NULL;
not.sigev_notify = SIGEV_SIGNAL;
not.sigev_value.sival_ptr = (void *)&notification_executed;
struct mq_attr attrs = {
.mq_msgsize = MESSAGE_SIZE,
.mq_maxmsg = MESG_COUNT_PERMQ,
};
struct sigevent not = {
.sigev_notify_function = notify_function_basic,
.sigev_notify = SIGEV_SIGNAL,
.sigev_value.sival_ptr = (void *)&notification_executed,
};
int32_t mode = 0777;
int flags = O_RDWR | O_CREAT;

Comment on lines 175 to 187
mqd_t mqd;
struct mq_attr attrs;
struct sigevent not;
int32_t mode = 0777;
int flags = O_RDWR | O_CREAT;

attrs.mq_msgsize = MESSAGE_SIZE;
attrs.mq_maxmsg = MESG_COUNT_PERMQ;

not.sigev_notify = SIGEV_THREAD;
not.sigev_value.sival_int = (int)pthread_self();
not.sigev_notify_function = notify_function_thread;
not.sigev_notify_attributes = NULL;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar - again, not blocking, so if this does need a respin for any reason, it might be worth it.

Suggested change
mqd_t mqd;
struct mq_attr attrs;
struct sigevent not;
int32_t mode = 0777;
int flags = O_RDWR | O_CREAT;
attrs.mq_msgsize = MESSAGE_SIZE;
attrs.mq_maxmsg = MESG_COUNT_PERMQ;
not.sigev_notify = SIGEV_THREAD;
not.sigev_value.sival_int = (int)pthread_self();
not.sigev_notify_function = notify_function_thread;
not.sigev_notify_attributes = NULL;
mqd_t mqd;
struct mq_attr attrs = {
.mq_msgsize = MESSAGE_SIZE,
.mq_maxmsg = MESG_COUNT_PERMQ,
};
struct sigevent not = {
.sigev_notify = SIGEV_THREAD,
.sigev_value.sival_int = (int)pthread_self(),
.sigev_notify_function = notify_function_thread,
};
int32_t mode = 0777;
int flags = O_RDWR | O_CREAT;

Comment on lines 120 to 132
mqd_t mqd;
struct mq_attr attrs;
struct sigevent not;
int32_t mode = 0777;
int flags = O_RDWR | O_CREAT;

attrs.mq_msgsize = MESSAGE_SIZE;
attrs.mq_maxmsg = MESG_COUNT_PERMQ;

not.sigev_notify = SIGEV_NONE;
not.sigev_value.sival_ptr = (void *)&notification_executed;
not.sigev_notify_function = notify_function_basic;
not.sigev_notify_attributes = NULL;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same - just a suggestion, not blocking, so you can ignore if there is no respin required.

Suggested change
mqd_t mqd;
struct mq_attr attrs;
struct sigevent not;
int32_t mode = 0777;
int flags = O_RDWR | O_CREAT;
attrs.mq_msgsize = MESSAGE_SIZE;
attrs.mq_maxmsg = MESG_COUNT_PERMQ;
not.sigev_notify = SIGEV_NONE;
not.sigev_value.sival_ptr = (void *)&notification_executed;
not.sigev_notify_function = notify_function_basic;
not.sigev_notify_attributes = NULL;
mqd_t mqd;
struct mq_attr attrs = {
.mq_msgsize = MESSAGE_SIZE,
.mq_maxmsg = MESG_COUNT_PERMQ,
};
struct sigevent not = {
.sigev_notify = SIGEV_NONE,
.sigev_value.sival_ptr = (void *)&notification_executed,
.sigev_notify_function = notify_function_basic,
};
int32_t mode = 0777;
int flags = O_RDWR | O_CREAT;

@@ -97,4 +96,205 @@ ZTEST(mqueue, test_mqueue)
zassert_false(mq_unlink(queue), "Not able to unlink Queue");
}

bool notification_executed;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not blocking either, so only if a respin is needed.

Suggested change
bool notification_executed;
static bool notification_executed;

mqueue_object *mqueue = (mqueue_object *)arg;
struct sigevent *sevp = &mqueue->not;

pthread_detach(pthread_self());
Copy link
Member

@cfriedt cfriedt Jan 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aside from calling pthread_detach(), I think it might be necessary to use pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL). Otherwise, calling pthread_cancel() might have no (immediate) effect. It's a bit confusing, but asynchronous (in pthreads) means with respect to cancellation points.

#67871 for reference, since there was a similar recent issue in timer.c

It's kind of tricky as well, because calling pthread_detach() on an already detached thread is undefined behaviour which might eventually result in an assertion.

To avoid that, it would be a good idea to call pthread_attr_setdetachstate() in mq_notify() when sigev_notify_attributes is not NULL. Otherwise, in mq_notify_thread(), call pthread_detach() only if sevp->sigev_notify_attributes is NULL.

Copy link
Member

@cfriedt cfriedt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to check the attr detachstate before setting it - otherwise basically done 👍

Comment on lines 385 to 391
ret = pthread_attr_getdetachstate(notification->sigev_notify_attributes,
&detachstate);
if (ret != 0) {
errno = ret;
return -1;
}
if (detachstate != PTHREAD_CREATE_DETACHED) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to check what the attr detachstate is before setting it

Suggested change
ret = pthread_attr_getdetachstate(notification->sigev_notify_attributes,
&detachstate);
if (ret != 0) {
errno = ret;
return -1;
}
if (detachstate != PTHREAD_CREATE_DETACHED) {
ret = pthread_attr_getdetachstate(notification->sigev_notify_attributes,
&detachstate);
if (ret != 0) {
errno = ret;
return -1;
}
if (detachstate != PTHREAD_CREATE_DETACHED) {

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's the way posix/timer.c do it so maybe it should be changed there as well?

errno = ret;
return -1;
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
}

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 zephyrproject-rtos#66958

Signed-off-by: Adam Wojasinski <[email protected]>
cfriedt
cfriedt previously approved these changes Jan 25, 2024
Copy link
Member

@cfriedt cfriedt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - thanks @awojasinski 👍

ycsin
ycsin previously approved these changes Jan 25, 2024
Adds test cases testing following features:
- function error handling
- basic notification type
- thread notification type
- adding notification to non-empty queue

Signed-off-by: Adam Wojasinski <[email protected]>
Updates in documentation support for `mq_notify` API
in `_POSIX_MESSAGE_PASSING` group option.

Signed-off-by: Adam Wojasinski <[email protected]>
@awojasinski awojasinski dismissed stale reviews from ycsin and cfriedt via 21bae31 January 25, 2024 14:14
Copy link
Member

@ycsin ycsin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cfriedt
Copy link
Member

cfriedt commented Jan 25, 2024

@awojasinski - if you're feeling generous, we could also use mq_timedreceive() and mq_timedsend() for the _POSIX_TIMEOUTS subprofiling option 😃

@carlescufi carlescufi merged commit 2e7a1f9 into zephyrproject-rtos:main Jan 25, 2024
@awojasinski
Copy link
Collaborator Author

@awojasinski - if you're feeling generous, we could also use mq_timedreceive() and mq_timedsend() for the _POSIX_TIMEOUTS subprofiling option 😃

@cfriedt sure I'll take a look in my spare time

@awojasinski awojasinski deleted the posix_mqnotify branch January 26, 2024 10:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: POSIX POSIX API Library
Projects
None yet
Development

Successfully merging this pull request may close these issues.

posix: implement mq_notify()
5 participants