(root)/
glibc-2.38/
rt/
tst-mqueue3.c
       1  /* Test SIGEV_THREAD handling for POSIX message queues.
       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 <mqueue.h>
      21  #include <signal.h>
      22  #include <stddef.h>
      23  #include <stdint.h>
      24  #include <stdio.h>
      25  #include <stdlib.h>
      26  #include <string.h>
      27  #include <sys/mman.h>
      28  #include <sys/wait.h>
      29  #include <unistd.h>
      30  #include <support/check.h>
      31  
      32  #if _POSIX_THREADS
      33  # include <pthread.h>
      34  
      35  static pid_t pid;
      36  static mqd_t m;
      37  static const char message[] = "hello";
      38  
      39  # define MAXMSG 10
      40  # define MSGSIZE 10
      41  # define UNIQUE 42
      42  
      43  
      44  static void
      45  fct (union sigval s)
      46  {
      47    /* Put the mq in non-blocking mode.  */
      48    struct mq_attr attr;
      49    if (mq_getattr (m, &attr) != 0)
      50      {
      51        printf ("%s: mq_getattr failed: %m\n", __FUNCTION__);
      52        exit (1);
      53      }
      54    attr.mq_flags |= O_NONBLOCK;
      55    if (mq_setattr (m, &attr, NULL) != 0)
      56      {
      57        printf ("%s: mq_setattr failed: %m\n", __FUNCTION__);
      58        exit (1);
      59      }
      60  
      61    /* Check the values.  */
      62    if (attr.mq_maxmsg != MAXMSG)
      63      {
      64        printf ("%s: mq_maxmsg wrong: is %jd, expected %d\n",
      65  	      __FUNCTION__, (intmax_t) attr.mq_maxmsg, MAXMSG);
      66        exit (1);
      67      }
      68    if (attr.mq_msgsize != MAXMSG)
      69      {
      70        printf ("%s: mq_msgsize wrong: is %jd, expected %d\n",
      71  	      __FUNCTION__, (intmax_t) attr.mq_msgsize, MSGSIZE);
      72        exit (1);
      73      }
      74  
      75    /* Read the message.  */
      76    char buf[attr.mq_msgsize];
      77    ssize_t n = TEMP_FAILURE_RETRY (mq_receive (m, buf, attr.mq_msgsize, NULL));
      78    if (n != sizeof (message))
      79      {
      80        printf ("%s: length of message wrong: is %zd, expected %zu\n",
      81  	      __FUNCTION__, n, sizeof (message));
      82        exit (1);
      83      }
      84    if (memcmp (buf, message, sizeof (message)) != 0)
      85      {
      86        printf ("%s: message wrong: is \"%s\", expected \"%s\"\n",
      87  	      __FUNCTION__, buf, message);
      88        exit (1);
      89      }
      90  
      91    exit (UNIQUE);
      92  }
      93  
      94  
      95  int
      96  do_test (void)
      97  {
      98    char tmpfname[] = "/tmp/tst-mqueue3-barrier.XXXXXX";
      99    int fd = mkstemp (tmpfname);
     100    if (fd == -1)
     101      {
     102        printf ("cannot open temporary file: %m\n");
     103        return 1;
     104      }
     105  
     106    /* Make sure it is always removed.  */
     107    unlink (tmpfname);
     108  
     109    /* Create one page of data.  */
     110    size_t ps = sysconf (_SC_PAGESIZE);
     111    char data[ps];
     112    memset (data, '\0', ps);
     113  
     114    /* Write the data to the file.  */
     115    if (write (fd, data, ps) != (ssize_t) ps)
     116      {
     117        puts ("short write");
     118        return 1;
     119      }
     120  
     121    void *mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
     122    if (mem == MAP_FAILED)
     123      {
     124        printf ("mmap failed: %m\n");
     125        return 1;
     126      }
     127  
     128    pthread_barrier_t *b;
     129    b = (pthread_barrier_t *) (((uintptr_t) mem + __alignof (pthread_barrier_t))
     130                               & ~(__alignof (pthread_barrier_t) - 1));
     131  
     132    pthread_barrierattr_t a;
     133    if (pthread_barrierattr_init (&a) != 0)
     134      {
     135        puts ("barrierattr_init failed");
     136        return 1;
     137      }
     138  
     139    if (pthread_barrierattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0)
     140      {
     141        puts ("barrierattr_setpshared failed, could not test");
     142        return 0;
     143      }
     144  
     145    if (pthread_barrier_init (b, &a, 2) != 0)
     146      {
     147        puts ("barrier_init failed");
     148        return 1;
     149      }
     150  
     151    if (pthread_barrierattr_destroy (&a) != 0)
     152      {
     153        puts ("barrierattr_destroy failed");
     154        return 1;
     155      }
     156  
     157    /* Name for the message queue.  */
     158    char mqname[sizeof ("/tst-mqueue3-") + 3 * sizeof (pid_t)];
     159    snprintf (mqname, sizeof (mqname) - 1, "/tst-mqueue3-%ld",
     160  	    (long int) getpid ());
     161  
     162    /* Create the message queue.  */
     163    struct mq_attr attr = { .mq_maxmsg = MAXMSG, .mq_msgsize = MSGSIZE };
     164    m = mq_open (mqname, O_CREAT | O_EXCL | O_RDWR, 0600, &attr);
     165  
     166    if (m == -1)
     167      {
     168        if (errno == ENOSYS)
     169  	FAIL_UNSUPPORTED ("mq_open not supported");
     170  
     171        printf ("mq_open failed with: %m\n");
     172        return 1;
     173      }
     174  
     175    /* Unlink the message queue right away.  */
     176    if (mq_unlink (mqname) != 0)
     177      {
     178        puts ("mq_unlink failed");
     179        return 1;
     180      }
     181  
     182    pid = fork ();
     183    if (pid == -1)
     184      {
     185        puts ("fork failed");
     186        return 1;
     187      }
     188    if (pid == 0)
     189      {
     190        /* Request notification via thread.  */
     191        struct sigevent ev;
     192        ev.sigev_notify = SIGEV_THREAD;
     193        ev.sigev_notify_function = fct;
     194        ev.sigev_value.sival_ptr = NULL;
     195        ev.sigev_notify_attributes = NULL;
     196  
     197        /* Tell the kernel.  */
     198        if (mq_notify (m,&ev) != 0)
     199  	{
     200  	  puts ("mq_notify failed");
     201  	  exit (1);
     202  	}
     203  
     204        /* Tell the parent we are ready.  */
     205        (void) pthread_barrier_wait (b);
     206  
     207        /* Make sure the process goes away eventually.  */
     208        alarm (10);
     209  
     210        /* Do nothing forever.  */
     211        while (1)
     212  	pause ();
     213      }
     214  
     215    /* Wait for the child process to register to notification method.  */
     216    (void) pthread_barrier_wait (b);
     217  
     218    /* Send the message.  */
     219    if (mq_send (m, message, sizeof (message), 1) != 0)
     220      {
     221        kill (pid, SIGKILL);
     222        puts ("mq_send failed");
     223        return 1;
     224      }
     225  
     226    int r;
     227    if (TEMP_FAILURE_RETRY (waitpid (pid, &r, 0)) != pid)
     228      {
     229        kill (pid, SIGKILL);
     230        puts ("waitpid failed");
     231        return 1;
     232      }
     233  
     234    return WIFEXITED (r) && WEXITSTATUS (r) == UNIQUE ? 0 : 1;
     235  }
     236  # define TEST_FUNCTION do_test ()
     237  #else
     238  # define TEST_FUNCTION 0
     239  #endif
     240  
     241  #include "../test-skeleton.c"