mq_notify(3)

πŸ’– mq_notify(3) πŸ’–

okay bestie, sit down, hydrate, because today we're learning about mq_notify β€” it lives in the Library Functions Manual and it's genuinely one of the cutest little syscalls-adjacent functions out there. no cap. it's giving "tell me when snacks arrive" energy and honestly? obsessed. 🫢


🌸 NAME 🌸

mq_notify β€” register for notification when a message is available

like. that's the whole gig. you sign up, you get pinged. iconic.


πŸ“š LIBRARY πŸ“š

Real-time library β€” link it with -lrt, bestie. Real-time library (librt, -lrt). don't forget the flag or you'll be crying in linker errors. 😭


✨ SYNOPSIS ✨

#include <mqueue.h>
#include <signal.h>           /* Definition of SIGEV_* constants */

int mq_notify(mqd_t mqdes, const struct sigevent *sevp);

she takes a message queue descriptor and a pointer to a sigevent struct. that's it. that's the whole signature. πŸ’…


πŸ’… DESCRIPTION πŸ’…

so here's the vibe. mq_notify() lets the calling process register β€” or unregister β€” for delivery of an asynchronous notification when a new message lands on the empty message queue that mqdes refers to. key word: empty. we'll get to why that matters, don't worry. πŸ¦‹

the sevp argument is a pointer to a sigevent structure. for the definition and all the general deets of that structure, go look at sigevent(3type) β€” she has her own whole page and she deserves the traffic.

if sevp is a non-null pointer, then mq_notify() registers the calling process to receive message notification. the sigev_notify field of the sigevent structure that sevp points at? that specifies how the notification gets performed. and this field has one of these values, bestie:

  • SIGEV_NONE β€” a "null" notification. the calling process is registered as the target for notification, but when a message arrives, no notification is sent. so like… you signed up for the newsletter and then set it to mute. still registered though!! the registration totally exists.
  • SIGEV_SIGNAL β€” notify the process by sending the signal specified in sigev_signo. see sigevent(3type) for general details. and here's the juicy part: the si_code field of the siginfo_t structure will be set to SI_MESGQ. in addition, si_pid will be set to the PID of the process that sent the message, and si_uid will be set to the real user ID of the sending process. so you get the receipts on who's messaging you. πŸ’Œ
  • SIGEV_THREAD β€” upon message delivery, invoke sigev_notify_function as if it were the start function of a new thread. see sigevent(3type) for details. yes, she spawns a whole thread for you. main character energy fr.

only ONE process can be registered to receive notification from a message queue. one. singular. it's giving "only one person can have the aux" and honestly that's fair. πŸ‘‘

now β€” if sevp is NULL, and the calling process is currently registered to receive notifications for this message queue, then the registration is removed. and then another process can slide in and register to receive a message notification for this queue. passing the aux. 🎀

okay here's the part everyone gets confused about so listen up: message notification occurs only when a new message arrives and the queue was previously empty. if the queue was not empty at the time mq_notify() was called, then a notification will occur only after the queue is emptied and a new message arrives. so the queue's gotta hit zero first. it's a whole journey. it's the full circle moment. 🌈

and if another process or thread is waiting to read a message from an empty queue using mq_receive(3)? then any message notification registration is ignored β€” the message gets delivered to the process or thread calling mq_receive(3), and the message notification registration remains in effect. so the catcher beat the notification to it, and your registration is still chilling there untouched. no harm no foul. πŸ“

notification occurs once. one time. after a notification is delivered, the notification registration is removed, and another process can register for message notification. so if the notified process wants the next notification, it can just use mq_notify() again to request a further one. and here's the galaxy-brain tip:

this should be done before emptying all unread messages from the queue.

and also, lowkey, placing the queue in nonblocking mode is useful for emptying the queue of messages without blocking once it's empty. (that's in the original, i'm not making it up, it's literally there. so useful though.)


πŸ”₯ RETURN VALUE πŸ”₯

  • on success, mq_notify() returns 0. slay.
  • on error, -1 is returned, with errno set to indicate the error. sad girl hours. 😭

πŸ’€ ERRORS πŸ’€

  • EBADF β€” the message queue descriptor specified in mqdes is invalid. fake queue. doesn't exist. not it.
  • EBUSY β€” another process has already registered to receive notification for this message queue. the seat's taken bestie, sorry.
  • EINVAL β€” sevp->sigev_notify is not one of the permitted values; or sevp->sigev_notify is SIGEV_SIGNAL and sevp->sigev_signo is not a valid signal number.
  • ENOMEM β€” insufficient memory. 😭

also, some lore from the standards: POSIX.1-2008 says that an implementation may generate an EINVAL error if sevp is NULL, and the caller is not currently registered to receive notifications for the queue mqdes. so that's a thing that can happen. noted. 🫑


πŸŽ€ ATTRIBUTES πŸŽ€

for an explanation of the terms used in this section, see attributes(7).

  • Interface: mq_notify()
  • Attribute: Thread safety
  • Value: MT-Safe

MT-Safe! she's thread safe! she can hang with all your threads and not cause drama! ✨


🌟 VERSIONS 🌟

🐧 C library/kernel differences 🐧

in the glibc implementation, the mq_notify() library function is implemented on top of the system call of the same name. so there's a syscall underneath her. when sevp is NULL, or specifies a notification mechanism other than SIGEV_THREAD, the library function directly invokes the system call.

but for SIGEV_THREAD? much of the implementation lives within the library, rather than the kernel. (this is necessarily so, since the thread involved in handling the notification is one that must be managed by the C library POSIX threads implementation.) and get this β€” the implementation involves the use of a raw netlink(7) socket and creates a new thread for each notification that is delivered to the process. raw netlink socket?? new thread every time?? she's doing the absolute most and we respect it fr fr. πŸ”₯


πŸ“œ STANDARDS πŸ“œ

POSIX.1-2008. periodt.


πŸ›οΈ HISTORY πŸ›οΈ

POSIX.1-2001. she's been around. a legend since 2001. vintage but make it functional. πŸ‘‘


πŸ’– EXAMPLES πŸ’–

the following program registers a notification request for the message queue named in its command-line argument. notification is performed by creating a thread. the thread executes a function which reads one message from the queue and then terminates the process. so: one message, then everyone goes home. πŸ’…

πŸ¦‹ Program source πŸ¦‹

#include <err.h>
#include <mqueue.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

static void                     /* Thread start function */
tfunc(union sigval sv)
{
    struct mq_attr attr;
    ssize_t nr;
    void *buf;
    mqd_t mqdes = *((mqd_t *) sv.sival_ptr);

    /* Determine max. msg size; allocate buffer to receive msg */

    if (mq_getattr(mqdes, &attr) == -1)
        err(EXIT_FAILURE, "mq_getattr");
    buf = malloc(attr.mq_msgsize);
    if (buf == NULL)
        err(EXIT_FAILURE, "malloc");

    nr = mq_receive(mqdes, buf, attr.mq_msgsize, NULL);
    if (nr == -1)
        err(EXIT_FAILURE, "mq_receive");

    printf("Read %zd bytes from MQ\n", nr);
    free(buf);
    exit(EXIT_SUCCESS);         /* Terminate the process */
}

int
main(int argc, char *argv[])
{
    mqd_t mqdes;
    struct sigevent sev;

    if (argc != 2) {
        fprintf(stderr, "Usage: %s <mq-name>\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    mqdes = mq_open(argv[1], O_RDONLY);
    if (mqdes == (mqd_t) -1)
        err(EXIT_FAILURE, "mq_open");

    sev.sigev_notify = SIGEV_THREAD;
    sev.sigev_notify_function = tfunc;
    sev.sigev_notify_attributes = NULL;
    sev.sigev_value.sival_ptr = &mqdes;   /* Arg. to thread func.  */
    if (mq_notify(mqdes, &sev) == -1)
        err(EXIT_FAILURE, "mq_notify");

    pause();    /* Process will be terminated by thread function */
}

look at her. she's beautiful. she opens the MQ with O_RDONLY, sets up a SIGEV_THREAD notification, passes &mqdes as the argument to the thread function, calls pause() and just vibes until the thread reads one message and takes the whole process out. immaculate. πŸ˜­πŸ’–


πŸ‘€ SEE ALSO πŸ‘€

mq_close(3), mq_getattr(3), mq_open(3), mq_receive(3), mq_send(3), mq_unlink(3), mq_overview(7), sigevent(3type)

go read them, they're all part of the same little friend group and they all ate. πŸ₯°


and that's the page bestie!! this one's from Linux man-pages 6.20, dated 2026-02-08, and it's mq_notify(3) β€” go register your notifications and text me back when the message arrives. byeeee πŸ’œπŸ¦‹βœ¨

πŸ“¦ where this page comes from
  • arch rolling: man-pages 6.20-1 Β· BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-or-later AND LGPL-3.0-linking-exception AND LGPL-3.0-or-later AND LicenseRef-Public-Domain AND LicenseRef-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
  • nixpkgs unstable: man-pages 6.20
  • πŸ“œ the page's license: Linux-man-pages-copyleft
  • πŸ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms