(root)/
glibc-2.38/
rt/
tst-mqueue6.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
      37  # include <pthread.h>
      38  
      39  # define mqsend(q) (mqsend) (q, __LINE__)
      40  static int
      41  (mqsend) (mqd_t q, int line)
      42  {
      43    char c = 0;
      44    if (mq_send (q, &c, 1, 1) != 0)
      45      {
      46        printf ("mq_send on line %d failed with: %m\n", line);
      47        return 1;
      48      }
      49    return 0;
      50  }
      51  
      52  # define mqrecv(q) (mqrecv) (q, __LINE__)
      53  static int
      54  (mqrecv) (mqd_t q, int line)
      55  {
      56    char c;
      57    ssize_t rets = TEMP_FAILURE_RETRY (mq_receive (q, &c, 1, NULL));
      58    if (rets != 1)
      59      {
      60        if (rets == -1)
      61  	printf ("mq_receive on line %d failed with: %m\n", line);
      62        else
      63  	printf ("mq_receive on line %d returned %zd != 1\n",
      64  		line, rets);
      65        return 1;
      66      }
      67    return 0;
      68  }
      69  
      70  volatile int fct_cnt, fct_err;
      71  size_t fct_guardsize;
      72  
      73  static void
      74  fct (union sigval s)
      75  {
      76    mqd_t q = *(mqd_t *) s.sival_ptr;
      77  
      78    pthread_attr_t nattr;
      79    int ret = pthread_getattr_np (pthread_self (), &nattr);
      80    if (ret)
      81      {
      82        errno = ret;
      83        printf ("pthread_getattr_np failed: %m\n");
      84        fct_err = 1;
      85      }
      86    else
      87      {
      88        ret = pthread_attr_getguardsize (&nattr, &fct_guardsize);
      89        if (ret)
      90  	{
      91  	  errno = ret;
      92  	  printf ("pthread_attr_getguardsize failed: %m\n");
      93  	  fct_err = 1;
      94  	}
      95        if (pthread_attr_destroy (&nattr) != 0)
      96  	{
      97  	  puts ("pthread_attr_destroy failed");
      98  	  fct_err = 1;
      99  	}
     100      }
     101  
     102    ++fct_cnt;
     103    fct_err |= mqsend (q);
     104  }
     105  
     106  # define TEST_FUNCTION do_test ()
     107  static int
     108  do_test (void)
     109  {
     110    int result = 0;
     111  
     112    char name[sizeof "/tst-mqueue6-" + sizeof (pid_t) * 3];
     113    snprintf (name, sizeof (name), "/tst-mqueue6-%u", getpid ());
     114  
     115    struct mq_attr attr = { .mq_maxmsg = 1, .mq_msgsize = 1 };
     116    mqd_t q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr);
     117  
     118    if (q == (mqd_t) -1)
     119      {
     120        if (errno == ENOSYS)
     121  	FAIL_UNSUPPORTED ("mq_open not supported");
     122  
     123        printf ("mq_open failed with: %m\n");
     124        return 1;
     125      }
     126  
     127    add_temp_mq (name);
     128  
     129    pthread_attr_t nattr;
     130    if (pthread_attr_init (&nattr)
     131        || pthread_attr_setguardsize (&nattr, 0))
     132      {
     133        puts ("pthread_attr_t setup failed");
     134        result = 1;
     135      }
     136  
     137    fct_guardsize = 1;
     138  
     139    struct sigevent ev;
     140    memset (&ev, 0xaa, sizeof (ev));
     141    ev.sigev_notify = SIGEV_THREAD;
     142    ev.sigev_notify_function = fct;
     143    ev.sigev_notify_attributes = &nattr;
     144    ev.sigev_value.sival_ptr = &q;
     145    if (mq_notify (q, &ev) != 0)
     146      {
     147        printf ("mq_notify (q, { SIGEV_THREAD }) failed with: %m\n");
     148        result = 1;
     149      }
     150  
     151    size_t ps = sysconf (_SC_PAGESIZE);
     152    if (pthread_attr_setguardsize (&nattr, 32 * ps))
     153      {
     154        puts ("pthread_attr_t setup failed");
     155        result = 1;
     156      }
     157  
     158    if (mq_notify (q, &ev) == 0)
     159      {
     160        puts ("second mq_notify (q, { SIGEV_NONE }) unexpectedly succeeded");
     161        result = 1;
     162      }
     163    else if (errno != EBUSY)
     164      {
     165        printf ("second mq_notify (q, { SIGEV_NONE }) failed with: %m\n");
     166        result = 1;
     167      }
     168  
     169    if (fct_cnt != 0)
     170      {
     171        printf ("fct called too early (%d on %d)\n", fct_cnt, __LINE__);
     172        result = 1;
     173      }
     174  
     175    result |= mqsend (q);
     176  
     177    result |= mqrecv (q);
     178    result |= mqrecv (q);
     179  
     180    if (fct_cnt != 1)
     181      {
     182        printf ("fct not called (%d on %d)\n", fct_cnt, __LINE__);
     183        result = 1;
     184      }
     185    else if (fct_guardsize != 0)
     186      {
     187        printf ("fct_guardsize %zd != 0\n", fct_guardsize);
     188        result = 1;
     189      }
     190  
     191    if (mq_notify (q, &ev) != 0)
     192      {
     193        printf ("third mq_notify (q, { SIGEV_NONE }) failed with: %m\n");
     194        result = 1;
     195      }
     196  
     197    if (mq_notify (q, NULL) != 0)
     198      {
     199        printf ("mq_notify (q, NULL) failed with: %m\n");
     200        result = 1;
     201      }
     202  
     203    memset (&ev, 0x11, sizeof (ev));
     204    ev.sigev_notify = SIGEV_THREAD;
     205    ev.sigev_notify_function = fct;
     206    ev.sigev_notify_attributes = &nattr;
     207    ev.sigev_value.sival_ptr = &q;
     208    if (mq_notify (q, &ev) != 0)
     209      {
     210        printf ("mq_notify (q, { SIGEV_THREAD }) failed with: %m\n");
     211        result = 1;
     212      }
     213  
     214    if (pthread_attr_setguardsize (&nattr, 0))
     215      {
     216        puts ("pthread_attr_t setup failed");
     217        result = 1;
     218      }
     219  
     220    if (mq_notify (q, &ev) == 0)
     221      {
     222        puts ("second mq_notify (q, { SIGEV_NONE }) unexpectedly succeeded");
     223        result = 1;
     224      }
     225    else if (errno != EBUSY)
     226      {
     227        printf ("second mq_notify (q, { SIGEV_NONE }) failed with: %m\n");
     228        result = 1;
     229      }
     230  
     231    if (fct_cnt != 1)
     232      {
     233        printf ("fct called too early (%d on %d)\n", fct_cnt, __LINE__);
     234        result = 1;
     235      }
     236  
     237    result |= mqsend (q);
     238  
     239    result |= mqrecv (q);
     240    result |= mqrecv (q);
     241  
     242    if (fct_cnt != 2)
     243      {
     244        printf ("fct not called (%d on %d)\n", fct_cnt, __LINE__);
     245        result = 1;
     246      }
     247    else if (fct_guardsize != 32 * ps)
     248      {
     249        printf ("fct_guardsize %zd != %zd\n", fct_guardsize, 32 * ps);
     250        result = 1;
     251      }
     252  
     253    if (mq_notify (q, &ev) != 0)
     254      {
     255        printf ("third mq_notify (q, { SIGEV_NONE }) failed with: %m\n");
     256        result = 1;
     257      }
     258  
     259    if (mq_notify (q, NULL) != 0)
     260      {
     261        printf ("mq_notify (q, NULL) failed with: %m\n");
     262        result = 1;
     263      }
     264  
     265    if (pthread_attr_destroy (&nattr) != 0)
     266      {
     267        puts ("pthread_attr_destroy failed");
     268        result = 1;
     269      }
     270  
     271    if (mq_unlink (name) != 0)
     272      {
     273        printf ("mq_unlink failed: %m\n");
     274        result = 1;
     275      }
     276  
     277    if (mq_close (q) != 0)
     278      {
     279        printf ("mq_close failed: %m\n");
     280        result = 1;
     281      }
     282  
     283    memset (&ev, 0x55, sizeof (ev));
     284    ev.sigev_notify = SIGEV_THREAD;
     285    ev.sigev_notify_function = fct;
     286    ev.sigev_notify_attributes = NULL;
     287    ev.sigev_value.sival_int = 0;
     288    if (mq_notify (q, &ev) == 0)
     289      {
     290        puts ("mq_notify on closed mqd_t unexpectedly succeeded");
     291        result = 1;
     292      }
     293    else if (errno != EBADF)
     294      {
     295        printf ("mq_notify on closed mqd_t did not fail with EBADF: %m\n");
     296        result = 1;
     297      }
     298  
     299    if (fct_err)
     300      result = 1;
     301    return result;
     302  }
     303  #else
     304  # define TEST_FUNCTION 0
     305  #endif
     306  
     307  #include "../test-skeleton.c"