mq_notify: block all (application) signals in the worker thread
authorRich Felker <dalias@aerifal.cx>
Sun, 12 Feb 2023 00:13:10 +0000 (19:13 -0500)
committerRich Felker <dalias@aerifal.cx>
Sun, 12 Feb 2023 20:05:39 +0000 (15:05 -0500)
until the mq notification event arrives, it is mandatory that signals
be blocked. otherwise, a signal can be received, and its handler
executed, in a thread which does not yet exist on the abstract
machine.

after the point of the event arriving, having signals blocked is not a
conformance requirement but a QoI requirement. while the application
can unblock any signals it wants unblocked in the event handler
thread, if they did not start out blocked, it could not block them
without a race window where they are momentarily unblocked, and this
would preclude controlled delivery or other forms of acceptance
(sigwait, etc.) anywhere in the application.

src/mq/mq_notify.c

index 8109dfb..0e1e6c7 100644 (file)
@@ -50,6 +50,7 @@ int mq_notify(mqd_t mqd, const struct sigevent *sev)
        pthread_t td;
        int s;
        int cs;
+       sigset_t allmask, origmask;
 
        if (!sev || sev->sigev_notify != SIGEV_THREAD)
                return syscall(SYS_mq_notify, mqd, sev);
@@ -64,11 +65,15 @@ int mq_notify(mqd_t mqd, const struct sigevent *sev)
        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
        sem_init(&args.sem, 0, 0);
 
+       sigfillset(&allmask);
+       pthread_sigmask(SIG_BLOCK, &allmask, &origmask);
        if (pthread_create(&td, &attr, start, &args)) {
                __syscall(SYS_close, s);
+               pthread_sigmask(SIG_SETMASK, &origmask, 0);
                errno = EAGAIN;
                return -1;
        }
+       pthread_sigmask(SIG_SETMASK, &origmask, 0);
 
        pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
        sem_wait(&args.sem);