(root)/
glibc-2.38/
rt/
tst-mqueue5.c
       1  /* Test mq_notify.
       2     Copyright (C) 2004-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <errno.h>
      20  #include <fcntl.h>
      21  #include <mqueue.h>
      22  #include <limits.h>
      23  #include <signal.h>
      24  #include <stdint.h>
      25  #include <stdio.h>
      26  #include <stdlib.h>
      27  #include <string.h>
      28  #include <sys/mman.h>
      29  #include <sys/time.h>
      30  #include <sys/wait.h>
      31  #include <time.h>
      32  #include <unistd.h>
      33  #include <support/check.h>
      34  #include "tst-mqueue.h"
      35  
      36  #if _POSIX_THREADS && defined SIGRTMIN && defined SA_SIGINFO
      37  # include <pthread.h>
      38  
      39  volatile int rtmin_cnt;
      40  volatile pid_t rtmin_pid;
      41  volatile uid_t rtmin_uid;
      42  volatile int rtmin_code;
      43  volatile union sigval rtmin_sigval;
      44  
      45  static void
      46  rtmin_handler (int sig, siginfo_t *info, void *ctx)
      47  {
      48    if (sig != SIGRTMIN)
      49      abort ();
      50    ++rtmin_cnt;
      51    rtmin_pid = info->si_pid;
      52    rtmin_uid = info->si_uid;
      53    rtmin_code = info->si_code;
      54    rtmin_sigval = info->si_value;
      55  }
      56  
      57  #define mqsend(q) (mqsend) (q, __LINE__)
      58  static int
      59  (mqsend) (mqd_t q, int line)
      60  {
      61    char c = 0;
      62    if (mq_send (q, &c, 1, 1) != 0)
      63      {
      64        printf ("mq_send on line %d failed with: %m\n", line);
      65        return 1;
      66      }
      67    return 0;
      68  }
      69  
      70  #define mqrecv(q) (mqrecv) (q, __LINE__)
      71  static int
      72  (mqrecv) (mqd_t q, int line)
      73  {
      74    char c;
      75    ssize_t rets = TEMP_FAILURE_RETRY (mq_receive (q, &c, 1, NULL));
      76    if (rets != 1)
      77      {
      78        if (rets == -1)
      79  	printf ("mq_receive on line %d failed with: %m\n", line);
      80        else
      81  	printf ("mq_receive on line %d returned %zd != 1\n",
      82  		line, rets);
      83        return 1;
      84      }
      85    return 0;
      86  }
      87  
      88  struct thr_data
      89  {
      90    const char *name;
      91    pthread_barrier_t *b3;
      92    mqd_t q;
      93  };
      94  
      95  static void *
      96  thr (void *arg)
      97  {
      98    pthread_barrier_t *b3 = ((struct thr_data *)arg)->b3;
      99    mqd_t q = ((struct thr_data *)arg)->q;
     100    const char *name = ((struct thr_data *)arg)->name;
     101    int result = 0;
     102  
     103    result |= mqrecv (q);
     104  
     105    (void) pthread_barrier_wait (b3);
     106  
     107    /* Child verifies SIGRTMIN has not been sent.  */
     108  
     109    (void) pthread_barrier_wait (b3);
     110  
     111    /* Parent calls mqsend (q), which should trigger notification.  */
     112  
     113    (void) pthread_barrier_wait (b3);
     114  
     115    if (rtmin_cnt != 2)
     116      {
     117        puts ("SIGRTMIN signal in thread did not arrive");
     118        result = 1;
     119      }
     120    else if (rtmin_pid != getppid ()
     121  	   || rtmin_uid != getuid ()
     122  	   || rtmin_code != SI_MESGQ
     123  	   || rtmin_sigval.sival_int != 0xdeadbeef)
     124      {
     125        printf ("unexpected siginfo_t fields: pid %u (%u), uid %u (%u), code %d (%d), si_int %d (%d)\n",
     126  	      rtmin_pid, getppid (), rtmin_uid, getuid (),
     127  	      rtmin_code, SI_MESGQ, rtmin_sigval.sival_int, 0xdeadbeef);
     128        result = 1;
     129      }
     130  
     131    struct sigevent ev;
     132    memset (&ev, 0x82, sizeof (ev));
     133    ev.sigev_notify = SIGEV_NONE;
     134    if (mq_notify (q, &ev) != 0)
     135      {
     136        printf ("mq_notify in thread (q, { SIGEV_NONE }) failed with: %m\n");
     137        result = 1;
     138      }
     139  
     140    if (mq_notify (q, NULL) != 0)
     141      {
     142        printf ("mq_notify in thread (q, NULL) failed with: %m\n");
     143        result = 1;
     144      }
     145  
     146    result |= mqrecv (q);
     147  
     148    (void) pthread_barrier_wait (b3);
     149  
     150    /* Child calls mq_notify (q, { SIGEV_SIGNAL }).  */
     151  
     152    (void) pthread_barrier_wait (b3);
     153  
     154    if (mq_notify (q, NULL) != 0)
     155      {
     156        printf ("second mq_notify in thread (q, NULL) failed with: %m\n");
     157        result = 1;
     158      }
     159  
     160    (void) pthread_barrier_wait (b3);
     161  
     162    /* Parent calls mqsend (q), which should not trigger notification.  */
     163  
     164    (void) pthread_barrier_wait (b3);
     165  
     166    /* Child verifies SIGRTMIN has not been received.  */
     167    /* Child calls mq_notify (q, { SIGEV_SIGNAL }).  */
     168  
     169    (void) pthread_barrier_wait (b3);
     170  
     171    mqd_t q4 = mq_open (name, O_RDONLY);
     172    if (q4 == (mqd_t) -1)
     173      {
     174        printf ("mq_open in thread failed with: %m\n");
     175        result = 1;
     176      }
     177  
     178    if (mq_notify (q4, NULL) != 0)
     179      {
     180        printf ("mq_notify in thread (q4, NULL) failed with: %m\n");
     181        result = 1;
     182      }
     183  
     184    if (mq_close (q4) != 0)
     185      {
     186        printf ("mq_close in thread failed with: %m\n");
     187        result = 1;
     188      }
     189  
     190    (void) pthread_barrier_wait (b3);
     191  
     192    /* Parent calls mqsend (q), which should not trigger notification.  */
     193  
     194    (void) pthread_barrier_wait (b3);
     195  
     196    /* Child verifies SIGRTMIN has not been received.  */
     197    /* Child calls mq_notify (q, { SIGEV_SIGNAL }).  */
     198  
     199    (void) pthread_barrier_wait (b3);
     200  
     201    mqd_t q5 = mq_open (name, O_WRONLY);
     202    if (q5 == (mqd_t) -1)
     203      {
     204        printf ("mq_open O_WRONLY in thread failed with: %m\n");
     205        result = 1;
     206      }
     207  
     208    if (mq_notify (q5, NULL) != 0)
     209      {
     210        printf ("mq_notify in thread (q5, NULL) failed with: %m\n");
     211        result = 1;
     212      }
     213  
     214    if (mq_close (q5) != 0)
     215      {
     216        printf ("mq_close in thread failed with: %m\n");
     217        result = 1;
     218      }
     219  
     220    (void) pthread_barrier_wait (b3);
     221  
     222    /* Parent calls mqsend (q), which should not trigger notification.  */
     223  
     224    (void) pthread_barrier_wait (b3);
     225  
     226    /* Child verifies SIGRTMIN has not been received.  */
     227  
     228    return (void *) (long) result;
     229  }
     230  
     231  static void
     232  do_child (const char *name, pthread_barrier_t *b2, pthread_barrier_t *b3,
     233  	  mqd_t q)
     234  {
     235    int result = 0;
     236  
     237    struct sigevent ev;
     238    memset (&ev, 0x55, sizeof (ev));
     239    ev.sigev_notify = SIGEV_SIGNAL;
     240    ev.sigev_signo = SIGRTMIN;
     241    ev.sigev_value.sival_ptr = &ev;
     242    if (mq_notify (q, &ev) == 0)
     243      {
     244        puts ("first mq_notify in child (q, { SIGEV_SIGNAL }) unexpectedly succeeded");
     245        result = 1;
     246      }
     247    else if (errno != EBUSY)
     248      {
     249        printf ("first mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n");
     250        result = 1;
     251      }
     252  
     253    (void) pthread_barrier_wait (b2);
     254  
     255    /* Parent calls mqsend (q), which makes notification available.  */
     256  
     257    (void) pthread_barrier_wait (b2);
     258  
     259    rtmin_cnt = 0;
     260  
     261    if (mq_notify (q, &ev) != 0)
     262      {
     263        printf ("second mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n");
     264        result = 1;
     265      }
     266  
     267    if (rtmin_cnt != 0)
     268      {
     269        puts ("SIGRTMIN signal in child caught too early");
     270        result = 1;
     271      }
     272  
     273    (void) pthread_barrier_wait (b2);
     274  
     275    /* Parent unsuccessfully attempts to mq_notify.  */
     276    /* Parent calls mqsend (q), which makes notification available
     277       and triggers a signal in the child.  */
     278    /* Parent successfully calls mq_notify SIGEV_SIGNAL.  */
     279  
     280    (void) pthread_barrier_wait (b2);
     281  
     282    if (rtmin_cnt != 1)
     283      {
     284        puts ("SIGRTMIN signal in child did not arrive");
     285        result = 1;
     286      }
     287    else if (rtmin_pid != getppid ()
     288  	   || rtmin_uid != getuid ()
     289  	   || rtmin_code != SI_MESGQ
     290  	   || rtmin_sigval.sival_ptr != &ev)
     291      {
     292        printf ("unexpected siginfo_t fields: pid %u (%u), uid %u (%u), code %d (%d), si_ptr %p (%p)\n",
     293  	      rtmin_pid, getppid (), rtmin_uid, getuid (),
     294  	      rtmin_code, SI_MESGQ, rtmin_sigval.sival_ptr, &ev);
     295        result = 1;
     296      }
     297  
     298    result |= mqsend (q);
     299  
     300    (void) pthread_barrier_wait (b2);
     301  
     302    /* Parent verifies caught SIGRTMIN.  */
     303  
     304    mqd_t q2 = mq_open (name, O_RDWR);
     305    if (q2 == (mqd_t) -1)
     306      {
     307        printf ("mq_open in child failed with: %m\n");
     308        result = 1;
     309      }
     310  
     311    (void) pthread_barrier_wait (b2);
     312  
     313    /* Parent mq_open's another mqd_t for the same queue (q3).  */
     314  
     315    memset (&ev, 0x11, sizeof (ev));
     316    ev.sigev_notify = SIGEV_SIGNAL;
     317    ev.sigev_signo = SIGRTMIN;
     318    ev.sigev_value.sival_ptr = &ev;
     319    if (mq_notify (q2, &ev) != 0)
     320      {
     321        printf ("mq_notify in child (q2, { SIGEV_SIGNAL }) failed with: %m\n");
     322        result = 1;
     323      }
     324  
     325    (void) pthread_barrier_wait (b2);
     326  
     327    /* Parent unsuccessfully attempts to mq_notify { SIGEV_NONE } on q.  */
     328  
     329    (void) pthread_barrier_wait (b2);
     330  
     331    if (mq_close (q2) != 0)
     332      {
     333        printf ("mq_close failed: %m\n");
     334        result = 1;
     335      }
     336  
     337    (void) pthread_barrier_wait (b2);
     338  
     339    /* Parent successfully calls mq_notify { SIGEV_NONE } on q3.  */
     340  
     341    (void) pthread_barrier_wait (b2);
     342  
     343    memset (&ev, 0xbb, sizeof (ev));
     344    ev.sigev_notify = SIGEV_SIGNAL;
     345    ev.sigev_signo = SIGRTMIN;
     346    ev.sigev_value.sival_ptr = &b2;
     347    if (mq_notify (q, &ev) == 0)
     348      {
     349        puts ("third mq_notify in child (q, { SIGEV_SIGNAL }) unexpectedly succeeded");
     350        result = 1;
     351      }
     352    else if (errno != EBUSY)
     353      {
     354        printf ("third mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n");
     355        result = 1;
     356      }
     357  
     358    (void) pthread_barrier_wait (b2);
     359  
     360    /* Parent calls mq_close on q3, which makes the queue available again for
     361       notification.  */
     362  
     363    (void) pthread_barrier_wait (b2);
     364  
     365    memset (&ev, 0x13, sizeof (ev));
     366    ev.sigev_notify = SIGEV_NONE;
     367    if (mq_notify (q, &ev) != 0)
     368      {
     369        printf ("mq_notify in child (q, { SIGEV_NONE }) failed with: %m\n");
     370        result = 1;
     371      }
     372  
     373    if (mq_notify (q, NULL) != 0)
     374      {
     375        printf ("mq_notify in child (q, NULL) failed with: %m\n");
     376        result = 1;
     377      }
     378  
     379    (void) pthread_barrier_wait (b2);
     380  
     381    struct thr_data thr_data = { .name = name, .b3 = b3, .q = q };
     382    pthread_t th;
     383    int ret = pthread_create (&th, NULL, thr, &thr_data);
     384    if (ret)
     385      {
     386        errno = ret;
     387        printf ("pthread_created failed with: %m\n");
     388        result = 1;
     389      }
     390  
     391    /* Wait till thr calls mq_receive on the empty queue q and blocks on it.  */
     392    sleep (1);
     393  
     394    memset (&ev, 0x5f, sizeof (ev));
     395    ev.sigev_notify = SIGEV_SIGNAL;
     396    ev.sigev_signo = SIGRTMIN;
     397    ev.sigev_value.sival_int = 0xdeadbeef;
     398    if (mq_notify (q, &ev) != 0)
     399      {
     400        printf ("fourth mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n");
     401        result = 1;
     402      }
     403  
     404    /* Ensure the thr thread gets the signal, not us.  */
     405    sigset_t set;
     406    sigemptyset (&set);
     407    sigaddset (&set, SIGRTMIN);
     408    if (pthread_sigmask (SIG_BLOCK, &set, NULL))
     409      {
     410        printf ("Failed to block SIGRTMIN in child: %m\n");
     411        result = 1;
     412      }
     413  
     414    (void) pthread_barrier_wait (b2);
     415  
     416    /* Parent calls mqsend (q), which should wake up mqrecv (q)
     417       in the thread but no notification should be sent.  */
     418  
     419    (void) pthread_barrier_wait (b3);
     420  
     421    if (rtmin_cnt != 1)
     422      {
     423        puts ("SIGRTMIN signal caught while thr was blocked on mq_receive");
     424        result = 1;
     425      }
     426  
     427    (void) pthread_barrier_wait (b3);
     428  
     429    /* Parent calls mqsend (q), which should trigger notification.  */
     430  
     431    (void) pthread_barrier_wait (b3);
     432  
     433    /* Thread verifies SIGRTMIN has been received.  */
     434    /* Thread calls mq_notify (q, { SIGEV_NONE }) to verify notification is now
     435       available for registration.  */
     436    /* Thread calls mq_notify (q, NULL).  */
     437  
     438    (void) pthread_barrier_wait (b3);
     439  
     440    memset (&ev, 0x6a, sizeof (ev));
     441    ev.sigev_notify = SIGEV_SIGNAL;
     442    ev.sigev_signo = SIGRTMIN;
     443    ev.sigev_value.sival_ptr = do_child;
     444    if (mq_notify (q, &ev) != 0)
     445      {
     446        printf ("fifth mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n");
     447        result = 1;
     448      }
     449  
     450    (void) pthread_barrier_wait (b3);
     451  
     452    /* Thread calls mq_notify (q, NULL), which should unregister the above
     453       notification.  */
     454  
     455    (void) pthread_barrier_wait (b3);
     456  
     457    /* Parent calls mqsend (q), which should not trigger notification.  */
     458  
     459    (void) pthread_barrier_wait (b3);
     460  
     461    if (rtmin_cnt != 2)
     462      {
     463        puts ("SIGRTMIN signal caught while notification has been disabled");
     464        result = 1;
     465      }
     466  
     467    memset (&ev, 0x7b, sizeof (ev));
     468    ev.sigev_notify = SIGEV_SIGNAL;
     469    ev.sigev_signo = SIGRTMIN;
     470    ev.sigev_value.sival_ptr = thr;
     471    if (mq_notify (q, &ev) != 0)
     472      {
     473        printf ("sixth mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n");
     474        result = 1;
     475      }
     476  
     477    (void) pthread_barrier_wait (b3);
     478  
     479    /* Thread opens a new O_RDONLY mqd_t (q4).  */
     480    /* Thread calls mq_notify (q4, NULL), which should unregister the above
     481       notification.  */
     482    /* Thread calls mq_close (q4).  */
     483  
     484    (void) pthread_barrier_wait (b3);
     485  
     486    /* Parent calls mqsend (q), which should not trigger notification.  */
     487  
     488    (void) pthread_barrier_wait (b3);
     489  
     490    if (rtmin_cnt != 2)
     491      {
     492        puts ("SIGRTMIN signal caught while notification has been disabled");
     493        result = 1;
     494      }
     495  
     496    memset (&ev, 0xe1, sizeof (ev));
     497    ev.sigev_notify = SIGEV_SIGNAL;
     498    ev.sigev_signo = SIGRTMIN;
     499    ev.sigev_value.sival_int = 127;
     500    if (mq_notify (q, &ev) != 0)
     501      {
     502        printf ("seventh mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n");
     503        result = 1;
     504      }
     505  
     506    (void) pthread_barrier_wait (b3);
     507  
     508    /* Thread opens a new O_WRONLY mqd_t (q5).  */
     509    /* Thread calls mq_notify (q5, NULL), which should unregister the above
     510       notification.  */
     511    /* Thread calls mq_close (q5).  */
     512  
     513    (void) pthread_barrier_wait (b3);
     514  
     515    /* Parent calls mqsend (q), which should not trigger notification.  */
     516  
     517    (void) pthread_barrier_wait (b3);
     518  
     519    if (rtmin_cnt != 2)
     520      {
     521        puts ("SIGRTMIN signal caught while notification has been disabled");
     522        result = 1;
     523      }
     524  
     525    /* Re-enable test signals before cleaning up the thread.  */
     526    if (pthread_sigmask (SIG_UNBLOCK, &set, NULL))
     527      {
     528        printf ("Failed to unblock SIGRTMIN in child: %m\n");
     529        result = 1;
     530      }
     531  
     532    void *thr_ret;
     533    ret = pthread_join (th, &thr_ret);
     534    if (ret)
     535      {
     536        errno = ret;
     537        printf ("pthread_join failed: %m\n");
     538        result = 1;
     539      }
     540    else if (thr_ret)
     541      result = 1;
     542  
     543    if (mq_close (q) != 0)
     544      {
     545        printf ("mq_close failed: %m\n");
     546        result = 1;
     547      }
     548  
     549    exit (result);
     550  }
     551  
     552  #define TEST_FUNCTION do_test ()
     553  static int
     554  do_test (void)
     555  {
     556    int result = 0;
     557  
     558    char tmpfname[] = "/tmp/tst-mqueue5-barrier.XXXXXX";
     559    int fd = mkstemp (tmpfname);
     560    if (fd == -1)
     561      {
     562        printf ("cannot open temporary file: %m\n");
     563        return 1;
     564      }
     565  
     566    /* Make sure it is always removed.  */
     567    unlink (tmpfname);
     568  
     569    /* Create one page of data.  */
     570    size_t ps = sysconf (_SC_PAGESIZE);
     571    char data[ps];
     572    memset (data, '\0', ps);
     573  
     574    /* Write the data to the file.  */
     575    if (write (fd, data, ps) != (ssize_t) ps)
     576      {
     577        puts ("short write");
     578        return 1;
     579      }
     580  
     581    void *mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
     582    if (mem == MAP_FAILED)
     583      {
     584        printf ("mmap failed: %m\n");
     585        return 1;
     586      }
     587  
     588    pthread_barrier_t *b2;
     589    b2 = (pthread_barrier_t *) (((uintptr_t) mem + __alignof (pthread_barrier_t))
     590  			      & ~(__alignof (pthread_barrier_t) - 1));
     591  
     592    pthread_barrier_t *b3;
     593    b3 = b2 + 1;
     594  
     595    pthread_barrierattr_t a;
     596    if (pthread_barrierattr_init (&a) != 0)
     597      {
     598        puts ("barrierattr_init failed");
     599        return 1;
     600      }
     601  
     602    if (pthread_barrierattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0)
     603      {
     604        puts ("barrierattr_setpshared failed, could not test");
     605        return 0;
     606      }
     607  
     608    if (pthread_barrier_init (b2, &a, 2) != 0)
     609      {
     610        puts ("barrier_init failed");
     611        return 1;
     612      }
     613  
     614    if (pthread_barrier_init (b3, &a, 3) != 0)
     615      {
     616        puts ("barrier_init failed");
     617        return 1;
     618      }
     619  
     620    if (pthread_barrierattr_destroy (&a) != 0)
     621      {
     622        puts ("barrierattr_destroy failed");
     623        return 1;
     624      }
     625  
     626    char name[sizeof "/tst-mqueue5-" + sizeof (pid_t) * 3];
     627    snprintf (name, sizeof (name), "/tst-mqueue5-%u", getpid ());
     628  
     629    struct mq_attr attr = { .mq_maxmsg = 1, .mq_msgsize = 1 };
     630    mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr);
     631  
     632    if (q == (mqd_t) -1)
     633      {
     634        if (errno == ENOSYS)
     635  	FAIL_UNSUPPORTED ("mq_open not supported");
     636  
     637        printf ("mq_open failed with: %m\n");
     638        return 1;
     639      }
     640  
     641    add_temp_mq (name);
     642  
     643    struct sigevent ev;
     644    memset (&ev, 0xaa, sizeof (ev));
     645    ev.sigev_notify = SIGEV_NONE;
     646    if (mq_notify (q, &ev) != 0)
     647      {
     648        printf ("mq_notify (q, { SIGEV_NONE }) failed with: %m\n");
     649        result = 1;
     650      }
     651  
     652    if (mq_notify (q, &ev) == 0)
     653      {
     654        puts ("second mq_notify (q, { SIGEV_NONE }) unexpectedly succeeded");
     655        result = 1;
     656      }
     657    else if (errno != EBUSY)
     658      {
     659        printf ("second mq_notify (q, { SIGEV_NONE }) failed with: %m\n");
     660        result = 1;
     661      }
     662  
     663    result |= mqsend (q);
     664  
     665    if (mq_notify (q, &ev) != 0)
     666      {
     667        printf ("third mq_notify (q, { SIGEV_NONE }) failed with: %m\n");
     668        result = 1;
     669      }
     670  
     671    result |= mqrecv (q);
     672  
     673    if (mq_notify (q, NULL) != 0)
     674      {
     675        printf ("mq_notify (q, NULL) failed with: %m\n");
     676        result = 1;
     677      }
     678  
     679    if (mq_notify (q, NULL) != 0)
     680      {
     681        /* Implementation-defined behaviour, so don't fail,
     682  	 just inform.  */
     683        printf ("second mq_notify (q, NULL) failed with: %m\n");
     684      }
     685  
     686    struct sigaction sa = { .sa_sigaction = rtmin_handler,
     687  			  .sa_flags = SA_SIGINFO };
     688    sigemptyset (&sa.sa_mask);
     689    sigaction (SIGRTMIN, &sa, NULL);
     690  
     691    memset (&ev, 0x55, sizeof (ev));
     692    ev.sigev_notify = SIGEV_SIGNAL;
     693    ev.sigev_signo = SIGRTMIN;
     694    ev.sigev_value.sival_int = 26;
     695    if (mq_notify (q, &ev) != 0)
     696      {
     697        printf ("mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n");
     698        result = 1;
     699      }
     700  
     701    ev.sigev_value.sival_ptr = &ev;
     702    if (mq_notify (q, &ev) == 0)
     703      {
     704        puts ("second mq_notify (q, { SIGEV_SIGNAL }) unexpectedly succeeded");
     705        result = 1;
     706      }
     707    else if (errno != EBUSY)
     708      {
     709        printf ("second mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n");
     710        result = 1;
     711      }
     712  
     713    if (rtmin_cnt != 0)
     714      {
     715        puts ("SIGRTMIN signal caught too early");
     716        result = 1;
     717      }
     718  
     719    result |= mqsend (q);
     720  
     721    if (rtmin_cnt != 1)
     722      {
     723        puts ("SIGRTMIN signal did not arrive");
     724        result = 1;
     725      }
     726    else if (rtmin_pid != getpid ()
     727  	   || rtmin_uid != getuid ()
     728  	   || rtmin_code != SI_MESGQ
     729  	   || rtmin_sigval.sival_int != 26)
     730      {
     731        printf ("unexpected siginfo_t fields: pid %u (%u), uid %u (%u), code %d (%d), si_int %d (26)\n",
     732  	      rtmin_pid, getpid (), rtmin_uid, getuid (),
     733  	      rtmin_code, SI_MESGQ, rtmin_sigval.sival_int);
     734        result = 1;
     735      }
     736  
     737    ev.sigev_value.sival_int = 75;
     738    if (mq_notify (q, &ev) != 0)
     739      {
     740        printf ("third mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n");
     741        result = 1;
     742      }
     743  
     744    result |= mqrecv (q);
     745  
     746    if (mq_notify (q, NULL) != 0)
     747      {
     748        printf ("mq_notify (q, NULL) failed with: %m\n");
     749        result = 1;
     750      }
     751  
     752    memset (&ev, 0x33, sizeof (ev));
     753    ev.sigev_notify = SIGEV_NONE;
     754    if (mq_notify (q, &ev) != 0)
     755      {
     756        printf ("fourth mq_notify (q, { SIGEV_NONE }) failed with: %m\n");
     757        result = 1;
     758      }
     759  
     760    pid_t pid = fork ();
     761    if (pid == -1)
     762      {
     763        printf ("fork () failed: %m\n");
     764        mq_unlink (name);
     765        return 1;
     766      }
     767  
     768    if (pid == 0)
     769      do_child (name, b2, b3, q);
     770  
     771    /* Child unsuccessfully attempts to mq_notify.  */
     772  
     773    (void) pthread_barrier_wait (b2);
     774  
     775    result |= mqsend (q);
     776  
     777    (void) pthread_barrier_wait (b2);
     778  
     779    /* Child successfully calls mq_notify SIGEV_SIGNAL now.  */
     780  
     781    result |= mqrecv (q);
     782  
     783    (void) pthread_barrier_wait (b2);
     784  
     785    memset (&ev, 0xbb, sizeof (ev));
     786    ev.sigev_notify = SIGEV_SIGNAL;
     787    ev.sigev_signo = SIGRTMIN;
     788    ev.sigev_value.sival_int = 15;
     789    if (mq_notify (q, &ev) == 0)
     790      {
     791        puts ("fourth mq_notify (q, { SIGEV_SIGNAL }) unexpectedly succeeded");
     792        result = 1;
     793      }
     794    else if (errno != EBUSY)
     795      {
     796        printf ("fourth mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n");
     797        result = 1;
     798      }
     799  
     800    result |= mqsend (q);
     801  
     802    if (mq_notify (q, &ev) != 0)
     803      {
     804        printf ("fifth mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n");
     805        result = 1;
     806      }
     807  
     808    if (rtmin_cnt != 1)
     809      {
     810        puts ("SIGRTMIN signal caught too early");
     811        result = 1;
     812      }
     813  
     814    result |= mqrecv (q);
     815  
     816    (void) pthread_barrier_wait (b2);
     817  
     818    /* Child verifies caught SIGRTMIN signal.  */
     819    /* Child calls mq_send (q) which triggers SIGRTMIN signal here.  */
     820  
     821    (void) pthread_barrier_wait (b2);
     822  
     823    /* Child mq_open's another mqd_t for the same queue (q2).  */
     824  
     825    if (rtmin_cnt != 2)
     826      {
     827        puts ("SIGRTMIN signal did not arrive");
     828        result = 1;
     829      }
     830    else if (rtmin_pid != pid
     831  	   || rtmin_uid != getuid ()
     832  	   || rtmin_code != SI_MESGQ
     833  	   || rtmin_sigval.sival_int != 15)
     834      {
     835        printf ("unexpected siginfo_t fields: pid %u (%u), uid %u (%u), code %d (%d), si_int %d (15)\n",
     836  	      rtmin_pid, pid, rtmin_uid, getuid (),
     837  	      rtmin_code, SI_MESGQ, rtmin_sigval.sival_int);
     838        result = 1;
     839      }
     840  
     841    result |= mqrecv (q);
     842  
     843    (void) pthread_barrier_wait (b2);
     844  
     845    /* Child successfully calls mq_notify { SIGEV_SIGNAL } on q2.  */
     846  
     847    (void) pthread_barrier_wait (b2);
     848  
     849    memset (&ev, 0xbb, sizeof (ev));
     850    ev.sigev_notify = SIGEV_NONE;
     851    if (mq_notify (q, &ev) == 0)
     852      {
     853        puts ("fifth mq_notify (q, { SIGEV_NONE }) unexpectedly succeeded");
     854        result = 1;
     855      }
     856    else if (errno != EBUSY)
     857      {
     858        printf ("fifth mq_notify (q, { SIGEV_NONE }) failed with: %m\n");
     859        result = 1;
     860      }
     861  
     862    (void) pthread_barrier_wait (b2);
     863  
     864    /* Child calls mq_close on q2, which makes the queue available again for
     865       notification.  */
     866  
     867    mqd_t q3 = mq_open (name, O_RDWR);
     868    if (q3 == (mqd_t) -1)
     869      {
     870        printf ("mq_open q3 in parent failed with: %m\n");
     871        result = 1;
     872      }
     873  
     874    (void) pthread_barrier_wait (b2);
     875  
     876    memset (&ev, 0x12, sizeof (ev));
     877    ev.sigev_notify = SIGEV_NONE;
     878    if (mq_notify (q3, &ev) != 0)
     879      {
     880        printf ("mq_notify (q3, { SIGEV_NONE }) failed with: %m\n");
     881        result = 1;
     882      }
     883  
     884    (void) pthread_barrier_wait (b2);
     885  
     886    /* Child unsuccessfully attempts to mq_notify { SIGEV_SIGNAL } on q.  */
     887  
     888    (void) pthread_barrier_wait (b2);
     889  
     890    if (mq_close (q3) != 0)
     891      {
     892        printf ("mq_close failed: %m\n");
     893        result = 1;
     894      }
     895  
     896    (void) pthread_barrier_wait (b2);
     897  
     898    /* Child successfully calls mq_notify { SIGEV_NONE } on q.  */
     899    /* Child successfully calls mq_notify NULL on q.  */
     900  
     901    (void) pthread_barrier_wait (b2);
     902  
     903    /* Child creates new thread.  */
     904    /* Thread blocks on mqrecv (q).  */
     905    /* Child sleeps for 1sec so that thread has time to reach that point.  */
     906    /* Child successfully calls mq_notify { SIGEV_SIGNAL } on q.  */
     907  
     908    (void) pthread_barrier_wait (b2);
     909  
     910    result |= mqsend (q);
     911  
     912    (void) pthread_barrier_wait (b3);
     913  
     914    /* Child verifies SIGRTMIN has not been sent.  */
     915  
     916    (void) pthread_barrier_wait (b3);
     917  
     918    result |= mqsend (q);
     919  
     920    (void) pthread_barrier_wait (b3);
     921  
     922    /* Thread verifies SIGRTMIN has been caught.  */
     923    /* Thread calls mq_notify (q, { SIGEV_NONE }) to verify notification is now
     924       available for registration.  */
     925    /* Thread calls mq_notify (q, NULL).  */
     926  
     927    (void) pthread_barrier_wait (b3);
     928  
     929    /* Child calls mq_notify (q, { SIGEV_SIGNAL }).  */
     930  
     931    (void) pthread_barrier_wait (b3);
     932  
     933    /* Thread calls mq_notify (q, NULL). */
     934  
     935    (void) pthread_barrier_wait (b3);
     936  
     937    result |= mqsend (q);
     938    result |= mqrecv (q);
     939  
     940    (void) pthread_barrier_wait (b3);
     941  
     942    /* Child verifies SIGRTMIN has not been sent.  */
     943    /* Child calls mq_notify (q, { SIGEV_SIGNAL }).  */
     944  
     945    (void) pthread_barrier_wait (b3);
     946  
     947    /* Thread opens a new O_RDONLY mqd_t (q4).  */
     948    /* Thread calls mq_notify (q4, NULL). */
     949    /* Thread calls mq_close (q4).  */
     950  
     951    (void) pthread_barrier_wait (b3);
     952  
     953    result |= mqsend (q);
     954    result |= mqrecv (q);
     955  
     956    (void) pthread_barrier_wait (b3);
     957  
     958    /* Child verifies SIGRTMIN has not been sent.  */
     959    /* Child calls mq_notify (q, { SIGEV_SIGNAL }).  */
     960  
     961    (void) pthread_barrier_wait (b3);
     962  
     963    /* Thread opens a new O_WRONLY mqd_t (q5).  */
     964    /* Thread calls mq_notify (q5, NULL). */
     965    /* Thread calls mq_close (q5).  */
     966  
     967    (void) pthread_barrier_wait (b3);
     968  
     969    result |= mqsend (q);
     970    result |= mqrecv (q);
     971  
     972    (void) pthread_barrier_wait (b3);
     973  
     974    /* Child verifies SIGRTMIN has not been sent.  */
     975  
     976    int status;
     977    if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
     978      {
     979        puts ("waitpid failed");
     980        kill (pid, SIGKILL);
     981        result = 1;
     982      }
     983    else if (!WIFEXITED (status) || WEXITSTATUS (status))
     984      {
     985        printf ("child failed with status %d\n", status);
     986        result = 1;
     987      }
     988  
     989    if (mq_unlink (name) != 0)
     990      {
     991        printf ("mq_unlink failed: %m\n");
     992        result = 1;
     993      }
     994  
     995    if (mq_close (q) != 0)
     996      {
     997        printf ("mq_close failed: %m\n");
     998        result = 1;
     999      }
    1000  
    1001    if (mq_notify (q, NULL) == 0)
    1002      {
    1003        puts ("mq_notify on closed mqd_t unexpectedly succeeded");
    1004        result = 1;
    1005      }
    1006    else if (errno != EBADF)
    1007      {
    1008        printf ("mq_notify on closed mqd_t did not fail with EBADF: %m\n");
    1009        result = 1;
    1010      }
    1011  
    1012    memset (&ev, 0x55, sizeof (ev));
    1013    ev.sigev_notify = SIGEV_NONE;
    1014    if (mq_notify (q, &ev) == 0)
    1015      {
    1016        puts ("mq_notify on closed mqd_t unexpectedly succeeded");
    1017        result = 1;
    1018      }
    1019    else if (errno != EBADF)
    1020      {
    1021        printf ("mq_notify on closed mqd_t did not fail with EBADF: %m\n");
    1022        result = 1;
    1023      }
    1024  
    1025    return result;
    1026  }
    1027  #else
    1028  # define TEST_FUNCTION 0
    1029  #endif
    1030  
    1031  #include "../test-skeleton.c"