Back to index

glibc  2.9
tst-mqueue5.c
Go to the documentation of this file.
00001 /* Test mq_notify.
00002    Copyright (C) 2004 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Jakub Jelinek <jakub@redhat.com>, 2004.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #include <errno.h>
00022 #include <fcntl.h>
00023 #include <mqueue.h>
00024 #include <limits.h>
00025 #include <signal.h>
00026 #include <stdint.h>
00027 #include <stdio.h>
00028 #include <stdlib.h>
00029 #include <string.h>
00030 #include <sys/mman.h>
00031 #include <sys/time.h>
00032 #include <sys/wait.h>
00033 #include <time.h>
00034 #include <unistd.h>
00035 #include "tst-mqueue.h"
00036 
00037 #define TIMEOUT 3
00038 
00039 #if _POSIX_THREADS
00040 # include <pthread.h>
00041 
00042 volatile int rtmin_cnt;
00043 volatile pid_t rtmin_pid;
00044 volatile uid_t rtmin_uid;
00045 volatile int rtmin_code;
00046 volatile union sigval rtmin_sigval;
00047 
00048 static void
00049 rtmin_handler (int sig, siginfo_t *info, void *ctx)
00050 {
00051   if (sig != SIGRTMIN)
00052     abort ();
00053   ++rtmin_cnt;
00054   rtmin_pid = info->si_pid;
00055   rtmin_uid = info->si_uid;
00056   rtmin_code = info->si_code;
00057   rtmin_sigval = info->si_value;
00058 }
00059 
00060 #define mqsend(q) (mqsend) (q, __LINE__)
00061 static int
00062 (mqsend) (mqd_t q, int line)
00063 {
00064   char c;
00065   if (mq_send (q, &c, 1, 1) != 0)
00066     {
00067       printf ("mq_send on line %d failed with: %m\n", line);
00068       return 1;
00069     }
00070   return 0;
00071 }
00072 
00073 #define mqrecv(q) (mqrecv) (q, __LINE__)
00074 static int
00075 (mqrecv) (mqd_t q, int line)
00076 {
00077   char c;
00078   ssize_t rets = TEMP_FAILURE_RETRY (mq_receive (q, &c, 1, NULL));
00079   if (rets != 1)
00080     {
00081       if (rets == -1)
00082        printf ("mq_receive on line %d failed with: %m\n", line);
00083       else
00084        printf ("mq_receive on line %d returned %zd != 1\n",
00085               line, rets);
00086       return 1;
00087     }
00088   return 0;
00089 }
00090 
00091 struct thr_data
00092 {
00093   const char *name;
00094   pthread_barrier_t *b3;
00095   mqd_t q;
00096 };
00097 
00098 static void *
00099 thr (void *arg)
00100 {
00101   pthread_barrier_t *b3 = ((struct thr_data *)arg)->b3;
00102   mqd_t q = ((struct thr_data *)arg)->q;
00103   const char *name = ((struct thr_data *)arg)->name;
00104   int result = 0;
00105 
00106   result |= mqrecv (q);
00107 
00108   (void) pthread_barrier_wait (b3);
00109 
00110   /* Child verifies SIGRTMIN has not been sent.  */
00111 
00112   (void) pthread_barrier_wait (b3);
00113 
00114   /* Parent calls mqsend (q), which should trigger notification.  */
00115 
00116   (void) pthread_barrier_wait (b3);
00117 
00118   if (rtmin_cnt != 2)
00119     {
00120       puts ("SIGRTMIN signal in child did not arrive");
00121       result = 1;
00122     }
00123   else if (rtmin_pid != getppid ()
00124           || rtmin_uid != getuid ()
00125           || rtmin_code != SI_MESGQ
00126           || rtmin_sigval.sival_int != 0xdeadbeef)
00127     {
00128       printf ("unexpected siginfo_t fields: pid %u (%u), uid %u (%u), code %d (%d), si_int %d (%d)\n",
00129              rtmin_pid, getppid (), rtmin_uid, getuid (),
00130              rtmin_code, SI_MESGQ, rtmin_sigval.sival_int, 0xdeadbeef);
00131       result = 1;
00132     }
00133 
00134   struct sigevent ev;
00135   memset (&ev, 0x82, sizeof (ev));
00136   ev.sigev_notify = SIGEV_NONE;
00137   if (mq_notify (q, &ev) != 0)
00138     {
00139       printf ("mq_notify in thread (q, { SIGEV_NONE }) failed with: %m\n");
00140       result = 1;
00141     }
00142 
00143   if (mq_notify (q, NULL) != 0)
00144     {
00145       printf ("mq_notify in thread (q, NULL) failed with: %m\n");
00146       result = 1;
00147     }
00148 
00149   result |= mqrecv (q);
00150 
00151   (void) pthread_barrier_wait (b3);
00152 
00153   /* Child calls mq_notify (q, { SIGEV_SIGNAL }).  */
00154 
00155   (void) pthread_barrier_wait (b3);
00156 
00157   if (mq_notify (q, NULL) != 0)
00158     {
00159       printf ("second mq_notify in thread (q, NULL) failed with: %m\n");
00160       result = 1;
00161     }
00162 
00163   (void) pthread_barrier_wait (b3);
00164 
00165   /* Parent calls mqsend (q), which should not trigger notification.  */
00166 
00167   (void) pthread_barrier_wait (b3);
00168 
00169   /* Child verifies SIGRTMIN has not been received.  */
00170   /* Child calls mq_notify (q, { SIGEV_SIGNAL }).  */
00171 
00172   (void) pthread_barrier_wait (b3);
00173 
00174   mqd_t q4 = mq_open (name, O_RDONLY);
00175   if (q4 == (mqd_t) -1)
00176     {
00177       printf ("mq_open in thread failed with: %m\n");
00178       result = 1;
00179     }
00180 
00181   if (mq_notify (q4, NULL) != 0)
00182     {
00183       printf ("mq_notify in thread (q4, NULL) failed with: %m\n");
00184       result = 1;
00185     }
00186 
00187   if (mq_close (q4) != 0)
00188     {
00189       printf ("mq_close in thread failed with: %m\n");
00190       result = 1;
00191     }
00192 
00193   (void) pthread_barrier_wait (b3);
00194 
00195   /* Parent calls mqsend (q), which should not trigger notification.  */
00196 
00197   (void) pthread_barrier_wait (b3);
00198 
00199   /* Child verifies SIGRTMIN has not been received.  */
00200   /* Child calls mq_notify (q, { SIGEV_SIGNAL }).  */
00201 
00202   (void) pthread_barrier_wait (b3);
00203 
00204   mqd_t q5 = mq_open (name, O_WRONLY);
00205   if (q5 == (mqd_t) -1)
00206     {
00207       printf ("mq_open O_WRONLY in thread failed with: %m\n");
00208       result = 1;
00209     }
00210 
00211   if (mq_notify (q5, NULL) != 0)
00212     {
00213       printf ("mq_notify in thread (q5, NULL) failed with: %m\n");
00214       result = 1;
00215     }
00216 
00217   if (mq_close (q5) != 0)
00218     {
00219       printf ("mq_close in thread failed with: %m\n");
00220       result = 1;
00221     }
00222 
00223   (void) pthread_barrier_wait (b3);
00224 
00225   /* Parent calls mqsend (q), which should not trigger notification.  */
00226 
00227   (void) pthread_barrier_wait (b3);
00228 
00229   /* Child verifies SIGRTMIN has not been received.  */
00230 
00231   return (void *) (long) result;
00232 }
00233 
00234 static void
00235 do_child (const char *name, pthread_barrier_t *b2, pthread_barrier_t *b3,
00236          mqd_t q)
00237 {
00238   int result = 0;
00239 
00240   struct sigevent ev;
00241   memset (&ev, 0x55, sizeof (ev));
00242   ev.sigev_notify = SIGEV_SIGNAL;
00243   ev.sigev_signo = SIGRTMIN;
00244   ev.sigev_value.sival_ptr = &ev;
00245   if (mq_notify (q, &ev) == 0)
00246     {
00247       puts ("first mq_notify in child (q, { SIGEV_SIGNAL }) unexpectedly succeeded");
00248       result = 1;
00249     }
00250   else if (errno != EBUSY)
00251     {
00252       printf ("first mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n");
00253       result = 1;
00254     }
00255 
00256   (void) pthread_barrier_wait (b2);
00257 
00258   /* Parent calls mqsend (q), which makes notification available.  */
00259 
00260   (void) pthread_barrier_wait (b2);
00261 
00262   rtmin_cnt = 0;
00263 
00264   if (mq_notify (q, &ev) != 0)
00265     {
00266       printf ("second mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n");
00267       result = 1;
00268     }
00269 
00270   if (rtmin_cnt != 0)
00271     {
00272       puts ("SIGRTMIN signal in child caught too early");
00273       result = 1;
00274     }
00275 
00276   (void) pthread_barrier_wait (b2);
00277 
00278   /* Parent unsuccessfully attempts to mq_notify.  */
00279   /* Parent calls mqsend (q), which makes notification available
00280      and triggers a signal in the child.  */
00281   /* Parent successfully calls mq_notify SIGEV_SIGNAL.  */
00282 
00283   (void) pthread_barrier_wait (b2);
00284 
00285   if (rtmin_cnt != 1)
00286     {
00287       puts ("SIGRTMIN signal in child did not arrive");
00288       result = 1;
00289     }
00290   else if (rtmin_pid != getppid ()
00291           || rtmin_uid != getuid ()
00292           || rtmin_code != SI_MESGQ
00293           || rtmin_sigval.sival_ptr != &ev)
00294     {
00295       printf ("unexpected siginfo_t fields: pid %u (%u), uid %u (%u), code %d (%d), si_ptr %p (%p)\n",
00296              rtmin_pid, getppid (), rtmin_uid, getuid (),
00297              rtmin_code, SI_MESGQ, rtmin_sigval.sival_ptr, &ev);
00298       result = 1;
00299     }
00300 
00301   result |= mqsend (q);
00302 
00303   (void) pthread_barrier_wait (b2);
00304 
00305   /* Parent verifies caught SIGRTMIN.  */
00306 
00307   mqd_t q2 = mq_open (name, O_RDWR);
00308   if (q2 == (mqd_t) -1)
00309     {
00310       printf ("mq_open in child failed with: %m\n");
00311       result = 1;
00312     }
00313 
00314   (void) pthread_barrier_wait (b2);
00315 
00316   /* Parent mq_open's another mqd_t for the same queue (q3).  */
00317 
00318   memset (&ev, 0x11, sizeof (ev));
00319   ev.sigev_notify = SIGEV_SIGNAL;
00320   ev.sigev_signo = SIGRTMIN;
00321   ev.sigev_value.sival_ptr = &ev;
00322   if (mq_notify (q2, &ev) != 0)
00323     {
00324       printf ("mq_notify in child (q2, { SIGEV_SIGNAL }) failed with: %m\n");
00325       result = 1;
00326     }
00327 
00328   (void) pthread_barrier_wait (b2);
00329 
00330   /* Parent unsuccessfully attempts to mq_notify { SIGEV_NONE } on q.  */
00331 
00332   (void) pthread_barrier_wait (b2);
00333 
00334   if (mq_close (q2) != 0)
00335     {
00336       printf ("mq_close failed: %m\n");
00337       result = 1;
00338     }
00339 
00340   (void) pthread_barrier_wait (b2);
00341 
00342   /* Parent successfully calls mq_notify { SIGEV_NONE } on q3.  */
00343 
00344   (void) pthread_barrier_wait (b2);
00345 
00346   memset (&ev, 0xbb, sizeof (ev));
00347   ev.sigev_notify = SIGEV_SIGNAL;
00348   ev.sigev_signo = SIGRTMIN;
00349   ev.sigev_value.sival_ptr = &b2;
00350   if (mq_notify (q, &ev) == 0)
00351     {
00352       puts ("third mq_notify in child (q, { SIGEV_SIGNAL }) unexpectedly succeeded");
00353       result = 1;
00354     }
00355   else if (errno != EBUSY)
00356     {
00357       printf ("third mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n");
00358       result = 1;
00359     }
00360 
00361   (void) pthread_barrier_wait (b2);
00362 
00363   /* Parent calls mq_close on q3, which makes the queue available again for
00364      notification.  */
00365 
00366   (void) pthread_barrier_wait (b2);
00367 
00368   memset (&ev, 0x13, sizeof (ev));
00369   ev.sigev_notify = SIGEV_NONE;
00370   if (mq_notify (q, &ev) != 0)
00371     {
00372       printf ("mq_notify in child (q, { SIGEV_NONE }) failed with: %m\n");
00373       result = 1;
00374     }
00375 
00376   if (mq_notify (q, NULL) != 0)
00377     {
00378       printf ("mq_notify in child (q, NULL) failed with: %m\n");
00379       result = 1;
00380     }
00381 
00382   (void) pthread_barrier_wait (b2);
00383 
00384   struct thr_data thr_data = { .name = name, .b3 = b3, .q = q };
00385   pthread_t th;
00386   int ret = pthread_create (&th, NULL, thr, &thr_data);
00387   if (ret)
00388     {
00389       errno = ret;
00390       printf ("pthread_created failed with: %m\n");
00391       result = 1;
00392     }
00393 
00394   /* Wait till thr calls mq_receive on the empty queue q and blocks on it.  */
00395   sleep (1);
00396 
00397   memset (&ev, 0x5f, sizeof (ev));
00398   ev.sigev_notify = SIGEV_SIGNAL;
00399   ev.sigev_signo = SIGRTMIN;
00400   ev.sigev_value.sival_int = 0xdeadbeef;
00401   if (mq_notify (q, &ev) != 0)
00402     {
00403       printf ("fourth mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n");
00404       result = 1;
00405     }
00406 
00407   (void) pthread_barrier_wait (b2);
00408 
00409   /* Parent calls mqsend (q), which should wake up mqrecv (q)
00410      in the thread but no notification should be sent.  */
00411 
00412   (void) pthread_barrier_wait (b3);
00413 
00414   if (rtmin_cnt != 1)
00415     {
00416       puts ("SIGRTMIN signal caught while thr was blocked on mq_receive");
00417       result = 1;
00418     }
00419 
00420   (void) pthread_barrier_wait (b3);
00421 
00422   /* Parent calls mqsend (q), which should trigger notification.  */
00423 
00424   (void) pthread_barrier_wait (b3);
00425 
00426   /* Thread verifies SIGRTMIN has been received.  */
00427   /* Thread calls mq_notify (q, { SIGEV_NONE }) to verify notification is now
00428      available for registration.  */
00429   /* Thread calls mq_notify (q, NULL).  */
00430 
00431   (void) pthread_barrier_wait (b3);
00432 
00433   memset (&ev, 0x6a, sizeof (ev));
00434   ev.sigev_notify = SIGEV_SIGNAL;
00435   ev.sigev_signo = SIGRTMIN;
00436   ev.sigev_value.sival_ptr = do_child;
00437   if (mq_notify (q, &ev) != 0)
00438     {
00439       printf ("fifth mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n");
00440       result = 1;
00441     }
00442 
00443   (void) pthread_barrier_wait (b3);
00444 
00445   /* Thread calls mq_notify (q, NULL), which should unregister the above
00446      notification.  */
00447 
00448   (void) pthread_barrier_wait (b3);
00449 
00450   /* Parent calls mqsend (q), which should not trigger notification.  */
00451 
00452   (void) pthread_barrier_wait (b3);
00453 
00454   if (rtmin_cnt != 2)
00455     {
00456       puts ("SIGRTMIN signal caught while notification has been disabled");
00457       result = 1;
00458     }
00459 
00460   memset (&ev, 0x7b, sizeof (ev));
00461   ev.sigev_notify = SIGEV_SIGNAL;
00462   ev.sigev_signo = SIGRTMIN;
00463   ev.sigev_value.sival_ptr = thr;
00464   if (mq_notify (q, &ev) != 0)
00465     {
00466       printf ("sixth mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n");
00467       result = 1;
00468     }
00469 
00470   (void) pthread_barrier_wait (b3);
00471 
00472   /* Thread opens a new O_RDONLY mqd_t (q4).  */
00473   /* Thread calls mq_notify (q4, NULL), which should unregister the above
00474      notification.  */
00475   /* Thread calls mq_close (q4).  */
00476 
00477   (void) pthread_barrier_wait (b3);
00478 
00479   /* Parent calls mqsend (q), which should not trigger notification.  */
00480 
00481   (void) pthread_barrier_wait (b3);
00482 
00483   if (rtmin_cnt != 2)
00484     {
00485       puts ("SIGRTMIN signal caught while notification has been disabled");
00486       result = 1;
00487     }
00488 
00489   memset (&ev, 0xe1, sizeof (ev));
00490   ev.sigev_notify = SIGEV_SIGNAL;
00491   ev.sigev_signo = SIGRTMIN;
00492   ev.sigev_value.sival_int = 127;
00493   if (mq_notify (q, &ev) != 0)
00494     {
00495       printf ("seventh mq_notify in child (q, { SIGEV_SIGNAL }) failed with: %m\n");
00496       result = 1;
00497     }
00498 
00499   (void) pthread_barrier_wait (b3);
00500 
00501   /* Thread opens a new O_WRONLY mqd_t (q5).  */
00502   /* Thread calls mq_notify (q5, NULL), which should unregister the above
00503      notification.  */
00504   /* Thread calls mq_close (q5).  */
00505 
00506   (void) pthread_barrier_wait (b3);
00507 
00508   /* Parent calls mqsend (q), which should not trigger notification.  */
00509 
00510   (void) pthread_barrier_wait (b3);
00511 
00512   if (rtmin_cnt != 2)
00513     {
00514       puts ("SIGRTMIN signal caught while notification has been disabled");
00515       result = 1;
00516     }
00517 
00518  void *thr_ret;
00519   ret = pthread_join (th, &thr_ret);
00520   if (ret)
00521     {
00522       errno = ret;
00523       printf ("pthread_join failed: %m\n");
00524       result = 1;
00525     }
00526   else if (thr_ret)
00527     result = 1;
00528 
00529   if (mq_close (q) != 0)
00530     {
00531       printf ("mq_close failed: %m\n");
00532       result = 1;
00533     }
00534 
00535   exit (result);
00536 }
00537 
00538 #define TEST_FUNCTION do_test ()
00539 static int
00540 do_test (void)
00541 {
00542   int result = 0;
00543 
00544   char tmpfname[] = "/tmp/tst-mqueue5-barrier.XXXXXX";
00545   int fd = mkstemp (tmpfname);
00546   if (fd == -1)
00547     {
00548       printf ("cannot open temporary file: %m\n");
00549       return 1;
00550     }
00551 
00552   /* Make sure it is always removed.  */
00553   unlink (tmpfname);
00554 
00555   /* Create one page of data.  */
00556   size_t ps = sysconf (_SC_PAGESIZE);
00557   char data[ps];
00558   memset (data, '\0', ps);
00559 
00560   /* Write the data to the file.  */
00561   if (write (fd, data, ps) != (ssize_t) ps)
00562     {
00563       puts ("short write");
00564       return 1;
00565     }
00566 
00567   void *mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
00568   if (mem == MAP_FAILED)
00569     {
00570       printf ("mmap failed: %m\n");
00571       return 1;
00572     }
00573 
00574   pthread_barrier_t *b2;
00575   b2 = (pthread_barrier_t *) (((uintptr_t) mem + __alignof (pthread_barrier_t))
00576                            & ~(__alignof (pthread_barrier_t) - 1));
00577 
00578   pthread_barrier_t *b3;
00579   b3 = b2 + 1;
00580 
00581   pthread_barrierattr_t a;
00582   if (pthread_barrierattr_init (&a) != 0)
00583     {
00584       puts ("barrierattr_init failed");
00585       return 1;
00586     }
00587 
00588   if (pthread_barrierattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0)
00589     {
00590       puts ("barrierattr_setpshared failed, could not test");
00591       return 0;
00592     }
00593 
00594   if (pthread_barrier_init (b2, &a, 2) != 0)
00595     {
00596       puts ("barrier_init failed");
00597       return 1;
00598     }
00599 
00600   if (pthread_barrier_init (b3, &a, 3) != 0)
00601     {
00602       puts ("barrier_init failed");
00603       return 1;
00604     }
00605 
00606   if (pthread_barrierattr_destroy (&a) != 0)
00607     {
00608       puts ("barrierattr_destroy failed");
00609       return 1;
00610     }
00611 
00612   char name[sizeof "/tst-mqueue5-" + sizeof (pid_t) * 3];
00613   snprintf (name, sizeof (name), "/tst-mqueue5-%u", getpid ());
00614 
00615   struct mq_attr attr = { .mq_maxmsg = 1, .mq_msgsize = 1 };
00616   mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr);
00617 
00618   if (q == (mqd_t) -1)
00619     {
00620       printf ("mq_open failed with: %m\n");
00621       return result;
00622     }
00623   else
00624     add_temp_mq (name);
00625 
00626   struct sigevent ev;
00627   memset (&ev, 0xaa, sizeof (ev));
00628   ev.sigev_notify = SIGEV_NONE;
00629   if (mq_notify (q, &ev) != 0)
00630     {
00631       printf ("mq_notify (q, { SIGEV_NONE }) failed with: %m\n");
00632       result = 1;
00633     }
00634 
00635   if (mq_notify (q, &ev) == 0)
00636     {
00637       puts ("second mq_notify (q, { SIGEV_NONE }) unexpectedly succeeded");
00638       result = 1;
00639     }
00640   else if (errno != EBUSY)
00641     {
00642       printf ("second mq_notify (q, { SIGEV_NONE }) failed with: %m\n");
00643       result = 1;
00644     }
00645 
00646   result |= mqsend (q);
00647 
00648   if (mq_notify (q, &ev) != 0)
00649     {
00650       printf ("third mq_notify (q, { SIGEV_NONE }) failed with: %m\n");
00651       result = 1;
00652     }
00653 
00654   result |= mqrecv (q);
00655 
00656   if (mq_notify (q, NULL) != 0)
00657     {
00658       printf ("mq_notify (q, NULL) failed with: %m\n");
00659       result = 1;
00660     }
00661 
00662   if (mq_notify (q, NULL) != 0)
00663     {
00664       /* Implementation-defined behaviour, so don't fail,
00665         just inform.  */
00666       printf ("second mq_notify (q, NULL) failed with: %m\n");
00667     }
00668 
00669   struct sigaction sa = { .sa_sigaction = rtmin_handler,
00670                        .sa_flags = SA_SIGINFO };
00671   sigemptyset (&sa.sa_mask);
00672   sigaction (SIGRTMIN, &sa, NULL);
00673 
00674   memset (&ev, 0x55, sizeof (ev));
00675   ev.sigev_notify = SIGEV_SIGNAL;
00676   ev.sigev_signo = SIGRTMIN;
00677   ev.sigev_value.sival_int = 26;
00678   if (mq_notify (q, &ev) != 0)
00679     {
00680       printf ("mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n");
00681       result = 1;
00682     }
00683 
00684   ev.sigev_value.sival_ptr = &ev;
00685   if (mq_notify (q, &ev) == 0)
00686     {
00687       puts ("second mq_notify (q, { SIGEV_SIGNAL }) unexpectedly succeeded");
00688       result = 1;
00689     }
00690   else if (errno != EBUSY)
00691     {
00692       printf ("second mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n");
00693       result = 1;
00694     }
00695 
00696   if (rtmin_cnt != 0)
00697     {
00698       puts ("SIGRTMIN signal caught too early");
00699       result = 1;
00700     }
00701 
00702   result |= mqsend (q);
00703 
00704   if (rtmin_cnt != 1)
00705     {
00706       puts ("SIGRTMIN signal did not arrive");
00707       result = 1;
00708     }
00709   else if (rtmin_pid != getpid ()
00710           || rtmin_uid != getuid ()
00711           || rtmin_code != SI_MESGQ
00712           || rtmin_sigval.sival_int != 26)
00713     {
00714       printf ("unexpected siginfo_t fields: pid %u (%u), uid %u (%u), code %d (%d), si_int %d (26)\n",
00715              rtmin_pid, getpid (), rtmin_uid, getuid (),
00716              rtmin_code, SI_MESGQ, rtmin_sigval.sival_int);
00717       result = 1;
00718     }
00719 
00720   ev.sigev_value.sival_int = 75;
00721   if (mq_notify (q, &ev) != 0)
00722     {
00723       printf ("third mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n");
00724       result = 1;
00725     }
00726 
00727   result |= mqrecv (q);
00728 
00729   if (mq_notify (q, NULL) != 0)
00730     {
00731       printf ("mq_notify (q, NULL) failed with: %m\n");
00732       result = 1;
00733     }
00734 
00735   memset (&ev, 0x33, sizeof (ev));
00736   ev.sigev_notify = SIGEV_NONE;
00737   if (mq_notify (q, &ev) != 0)
00738     {
00739       printf ("fourth mq_notify (q, { SIGEV_NONE }) failed with: %m\n");
00740       result = 1;
00741     }
00742 
00743   pid_t pid = fork ();
00744   if (pid == -1)
00745     {
00746       printf ("fork () failed: %m\n");
00747       mq_unlink (name);
00748       return 1;
00749     }
00750 
00751   if (pid == 0)
00752     do_child (name, b2, b3, q);
00753 
00754   /* Child unsuccessfully attempts to mq_notify.  */
00755 
00756   (void) pthread_barrier_wait (b2);
00757 
00758   result |= mqsend (q);
00759 
00760   (void) pthread_barrier_wait (b2);
00761 
00762   /* Child successfully calls mq_notify SIGEV_SIGNAL now.  */
00763 
00764   result |= mqrecv (q);
00765 
00766   (void) pthread_barrier_wait (b2);
00767 
00768   memset (&ev, 0xbb, sizeof (ev));
00769   ev.sigev_notify = SIGEV_SIGNAL;
00770   ev.sigev_signo = SIGRTMIN;
00771   ev.sigev_value.sival_int = 15;
00772   if (mq_notify (q, &ev) == 0)
00773     {
00774       puts ("fourth mq_notify (q, { SIGEV_SIGNAL }) unexpectedly succeeded");
00775       result = 1;
00776     }
00777   else if (errno != EBUSY)
00778     {
00779       printf ("fourth mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n");
00780       result = 1;
00781     }
00782 
00783   result |= mqsend (q);
00784 
00785   if (mq_notify (q, &ev) != 0)
00786     {
00787       printf ("fifth mq_notify (q, { SIGEV_SIGNAL }) failed with: %m\n");
00788       result = 1;
00789     }
00790 
00791   if (rtmin_cnt != 1)
00792     {
00793       puts ("SIGRTMIN signal caught too early");
00794       result = 1;
00795     }
00796 
00797   result |= mqrecv (q);
00798 
00799   (void) pthread_barrier_wait (b2);
00800 
00801   /* Child verifies caught SIGRTMIN signal.  */
00802   /* Child calls mq_send (q) which triggers SIGRTMIN signal here.  */
00803 
00804   (void) pthread_barrier_wait (b2);
00805 
00806   /* Child mq_open's another mqd_t for the same queue (q2).  */
00807 
00808   if (rtmin_cnt != 2)
00809     {
00810       puts ("SIGRTMIN signal did not arrive");
00811       result = 1;
00812     }
00813   else if (rtmin_pid != pid
00814           || rtmin_uid != getuid ()
00815           || rtmin_code != SI_MESGQ
00816           || rtmin_sigval.sival_int != 15)
00817     {
00818       printf ("unexpected siginfo_t fields: pid %u (%u), uid %u (%u), code %d (%d), si_int %d (15)\n",
00819              rtmin_pid, pid, rtmin_uid, getuid (),
00820              rtmin_code, SI_MESGQ, rtmin_sigval.sival_int);
00821       result = 1;
00822     }
00823 
00824   result |= mqrecv (q);
00825 
00826   (void) pthread_barrier_wait (b2);
00827 
00828   /* Child successfully calls mq_notify { SIGEV_SIGNAL } on q2.  */
00829 
00830   (void) pthread_barrier_wait (b2);
00831 
00832   memset (&ev, 0xbb, sizeof (ev));
00833   ev.sigev_notify = SIGEV_NONE;
00834   if (mq_notify (q, &ev) == 0)
00835     {
00836       puts ("fifth mq_notify (q, { SIGEV_NONE }) unexpectedly succeeded");
00837       result = 1;
00838     }
00839   else if (errno != EBUSY)
00840     {
00841       printf ("fifth mq_notify (q, { SIGEV_NONE }) failed with: %m\n");
00842       result = 1;
00843     }
00844 
00845   (void) pthread_barrier_wait (b2);
00846 
00847   /* Child calls mq_close on q2, which makes the queue available again for
00848      notification.  */
00849 
00850   mqd_t q3 = mq_open (name, O_RDWR);
00851   if (q3 == (mqd_t) -1)
00852     {
00853       printf ("mq_open q3 in parent failed with: %m\n");
00854       result = 1;
00855     }
00856 
00857   (void) pthread_barrier_wait (b2);
00858 
00859   memset (&ev, 0x12, sizeof (ev));
00860   ev.sigev_notify = SIGEV_NONE;
00861   if (mq_notify (q3, &ev) != 0)
00862     {
00863       printf ("mq_notify (q3, { SIGEV_NONE }) failed with: %m\n");
00864       result = 1;
00865     }
00866 
00867   (void) pthread_barrier_wait (b2);
00868 
00869   /* Child unsuccessfully attempts to mq_notify { SIGEV_SIGNAL } on q.  */
00870 
00871   (void) pthread_barrier_wait (b2);
00872 
00873   if (mq_close (q3) != 0)
00874     {
00875       printf ("mq_close failed: %m\n");
00876       result = 1;
00877     }
00878 
00879   (void) pthread_barrier_wait (b2);
00880 
00881   /* Child successfully calls mq_notify { SIGEV_NONE } on q.  */
00882   /* Child successfully calls mq_notify NULL on q.  */
00883 
00884   (void) pthread_barrier_wait (b2);
00885 
00886   /* Child creates new thread.  */
00887   /* Thread blocks on mqrecv (q).  */
00888   /* Child sleeps for 1sec so that thread has time to reach that point.  */
00889   /* Child successfully calls mq_notify { SIGEV_SIGNAL } on q.  */
00890 
00891   (void) pthread_barrier_wait (b2);
00892 
00893   result |= mqsend (q);
00894 
00895   (void) pthread_barrier_wait (b3);
00896 
00897   /* Child verifies SIGRTMIN has not been sent.  */
00898 
00899   (void) pthread_barrier_wait (b3);
00900 
00901   result |= mqsend (q);
00902 
00903   (void) pthread_barrier_wait (b3);
00904 
00905   /* Thread verifies SIGRTMIN has been caught.  */
00906   /* Thread calls mq_notify (q, { SIGEV_NONE }) to verify notification is now
00907      available for registration.  */
00908   /* Thread calls mq_notify (q, NULL).  */
00909 
00910   (void) pthread_barrier_wait (b3);
00911 
00912   /* Child calls mq_notify (q, { SIGEV_SIGNAL }).  */
00913 
00914   (void) pthread_barrier_wait (b3);
00915 
00916   /* Thread calls mq_notify (q, NULL). */
00917 
00918   (void) pthread_barrier_wait (b3);
00919 
00920   result |= mqsend (q);
00921   result |= mqrecv (q);
00922 
00923   (void) pthread_barrier_wait (b3);
00924 
00925   /* Child verifies SIGRTMIN has not been sent.  */
00926   /* Child calls mq_notify (q, { SIGEV_SIGNAL }).  */
00927 
00928   (void) pthread_barrier_wait (b3);
00929 
00930   /* Thread opens a new O_RDONLY mqd_t (q4).  */
00931   /* Thread calls mq_notify (q4, NULL). */
00932   /* Thread calls mq_close (q4).  */
00933 
00934   (void) pthread_barrier_wait (b3);
00935 
00936   result |= mqsend (q);
00937   result |= mqrecv (q);
00938 
00939   (void) pthread_barrier_wait (b3);
00940 
00941   /* Child verifies SIGRTMIN has not been sent.  */
00942   /* Child calls mq_notify (q, { SIGEV_SIGNAL }).  */
00943 
00944   (void) pthread_barrier_wait (b3);
00945 
00946   /* Thread opens a new O_WRONLY mqd_t (q5).  */
00947   /* Thread calls mq_notify (q5, NULL). */
00948   /* Thread calls mq_close (q5).  */
00949 
00950   (void) pthread_barrier_wait (b3);
00951 
00952   result |= mqsend (q);
00953   result |= mqrecv (q);
00954 
00955   (void) pthread_barrier_wait (b3);
00956 
00957   /* Child verifies SIGRTMIN has not been sent.  */
00958 
00959   int status;
00960   if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
00961     {
00962       puts ("waitpid failed");
00963       kill (pid, SIGKILL);
00964       result = 1;
00965     }
00966   else if (!WIFEXITED (status) || WEXITSTATUS (status))
00967     {
00968       printf ("child failed with status %d\n", status);
00969       result = 1;
00970     }
00971 
00972   if (mq_unlink (name) != 0)
00973     {
00974       printf ("mq_unlink failed: %m\n");
00975       result = 1;
00976     }
00977 
00978   if (mq_close (q) != 0)
00979     {
00980       printf ("mq_close failed: %m\n");
00981       result = 1;
00982     }
00983 
00984   if (mq_notify (q, NULL) == 0)
00985     {
00986       puts ("mq_notify on closed mqd_t unexpectedly succeeded");
00987       result = 1;
00988     }
00989   else if (errno != EBADF)
00990     {
00991       printf ("mq_notify on closed mqd_t did not fail with EBADF: %m\n");
00992       result = 1;
00993     }
00994 
00995   memset (&ev, 0x55, sizeof (ev));
00996   ev.sigev_notify = SIGEV_NONE;
00997   if (mq_notify (q, &ev) == 0)
00998     {
00999       puts ("mq_notify on closed mqd_t unexpectedly succeeded");
01000       result = 1;
01001     }
01002   else if (errno != EBADF)
01003     {
01004       printf ("mq_notify on closed mqd_t did not fail with EBADF: %m\n");
01005       result = 1;
01006     }
01007 
01008   return result;
01009 }
01010 #else
01011 # define TEST_FUNCTION 0
01012 #endif
01013 
01014 #include "../test-skeleton.c"