Back to index

glibc  2.9
tst-mqueue8.c
Go to the documentation of this file.
00001 /* Copyright (C) 2004 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Contributed by Jakub Jelinek <jakub@redhat.com>, 2004.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <errno.h>
00021 #include <mqueue.h>
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #include <string.h>
00025 #include <unistd.h>
00026 #if _POSIX_THREADS
00027 # include <pthread.h>
00028 
00029 static pthread_barrier_t b;
00030 
00031 /* Cleanup handling test.  */
00032 static int cl_called;
00033 
00034 static void
00035 cl (void *arg)
00036 {
00037   ++cl_called;
00038 }
00039 
00040 #define TF_MQ_RECEIVE              0L
00041 #define TF_MQ_TIMEDRECEIVE  1L
00042 #define TF_MQ_SEND          2L
00043 #define TF_MQ_TIMEDSEND            3L
00044 
00045 static const char *names[]
00046   = { "mq_receive", "mq_timedreceive", "mq_send", "mq_timedsend" };
00047 
00048 static mqd_t q;
00049 static struct timespec never;
00050 
00051 static void *
00052 tf (void *arg)
00053 {
00054   int r = pthread_barrier_wait (&b);
00055   if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
00056     {
00057       puts ("tf: barrier_wait failed");
00058       exit (1);
00059     }
00060 
00061   pthread_cleanup_push (cl, NULL);
00062 
00063   char c = ' ';
00064 
00065   switch ((long) arg)
00066     {
00067     case TF_MQ_SEND:
00068       TEMP_FAILURE_RETRY (mq_send (q, &c, 1, 1));
00069       break;
00070     case TF_MQ_TIMEDSEND:
00071       TEMP_FAILURE_RETRY (mq_timedsend (q, &c, 1, 1, &never));
00072       break;
00073     case TF_MQ_RECEIVE:
00074       TEMP_FAILURE_RETRY (mq_receive (q, &c, 1, NULL));
00075       break;
00076     case TF_MQ_TIMEDRECEIVE:
00077       TEMP_FAILURE_RETRY (mq_timedreceive (q, &c, 1, NULL, &never));
00078       break;
00079     }
00080 
00081   pthread_cleanup_pop (0);
00082 
00083   printf ("tf: %s returned\n", names[(long) arg]);
00084 
00085   exit (1);
00086 }
00087 
00088 #define TEST_FUNCTION do_test ()
00089 static int
00090 do_test (void)
00091 {
00092   char name[sizeof "/tst-mqueue8-" + sizeof (pid_t) * 3];
00093   snprintf (name, sizeof (name), "/tst-mqueue8-%u", getpid ());
00094 
00095   struct mq_attr attr = { .mq_maxmsg = 1, .mq_msgsize = 1 };
00096   q = mq_open (name, O_CREAT | O_EXCL | O_RDWR, 0600, &attr);
00097 
00098   if (q == (mqd_t) -1)
00099     {
00100       printf ("mq_open failed with: %m\n");
00101       return 0;
00102     }
00103 
00104   if (mq_unlink (name) != 0)
00105     {
00106       printf ("mq_unlink failed with: %m\n");
00107       return 1;
00108     }
00109 
00110   if (pthread_barrier_init (&b, NULL, 2) != 0)
00111     {
00112       puts ("barrier_init failed");
00113       return 1;
00114     }
00115 
00116   if (clock_gettime (CLOCK_REALTIME, &never) == 0)
00117     never.tv_sec += 100;
00118   else
00119     {
00120       never.tv_sec = time (NULL) + 100;
00121       never.tv_nsec = 0;
00122     }
00123 
00124   int result = 0;
00125   for (long l = TF_MQ_RECEIVE; l <= TF_MQ_TIMEDSEND; ++l)
00126     {
00127       cl_called = 0;
00128 
00129       pthread_t th;
00130       if (pthread_create (&th, NULL, tf, (void *) l) != 0)
00131        {
00132          printf ("1st %s create failed\n", names[l]);
00133          result = 1;
00134          continue;
00135        }
00136 
00137       int r = pthread_barrier_wait (&b);
00138       if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
00139        {
00140          puts ("barrier_wait failed");
00141          result = 1;
00142          continue;
00143        }
00144 
00145       struct timespec ts = { .tv_sec = 0, .tv_nsec = 100000000 };
00146       while (nanosleep (&ts, &ts) != 0)
00147        continue;
00148 
00149       printf ("going to cancel %s in-time\n", names[l]);
00150       if (pthread_cancel (th) != 0)
00151        {
00152          printf ("1st cancel of %s failed\n", names[l]);
00153          result = 1;
00154          continue;
00155        }
00156 
00157       void *status;
00158       if (pthread_join (th, &status) != 0)
00159        {
00160          printf ("1st join of %s failed\n", names[l]);
00161          result = 1;
00162          continue;
00163        }
00164       if (status != PTHREAD_CANCELED)
00165        {
00166          printf ("1st %s thread not canceled\n", names[l]);
00167          result = 1;
00168          continue;
00169        }
00170 
00171       if (cl_called == 0)
00172        {
00173          printf ("%s cleanup handler not called\n", names[l]);
00174          result = 1;
00175          continue;
00176        }
00177       if (cl_called > 1)
00178        {
00179          printf ("%s cleanup handler called more than once\n", names[l]);
00180          result = 1;
00181          continue;
00182        }
00183 
00184       printf ("in-time %s cancellation succeeded\n", names[l]);
00185 
00186       cl_called = 0;
00187 
00188       if (pthread_create (&th, NULL, tf, (void *) l) != 0)
00189        {
00190          printf ("2nd %s create failed\n", names[l]);
00191          result = 1;
00192          continue;
00193        }
00194 
00195       printf ("going to cancel %s early\n", names[l]);
00196       if (pthread_cancel (th) != 0)
00197        {
00198          printf ("2nd cancel of %s failed\n", names[l]);
00199          result = 1;
00200          continue;
00201        }
00202 
00203       r = pthread_barrier_wait (&b);
00204       if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
00205        {
00206          puts ("barrier_wait failed");
00207          result = 1;
00208          continue;
00209        }
00210 
00211       if (pthread_join (th, &status) != 0)
00212        {
00213          printf ("2nd join of %s failed\n", names[l]);
00214          result = 1;
00215          continue;
00216        }
00217       if (status != PTHREAD_CANCELED)
00218        {
00219          printf ("2nd %s thread not canceled\n", names[l]);
00220          result = 1;
00221          continue;
00222        }
00223 
00224       if (cl_called == 0)
00225        {
00226          printf ("%s cleanup handler not called\n", names[l]);
00227          result = 1;
00228          continue;
00229        }
00230       if (cl_called > 1)
00231        {
00232          printf ("%s cleanup handler called more than once\n", names[l]);
00233          result = 1;
00234          continue;
00235        }
00236 
00237       printf ("early %s cancellation succeeded\n", names[l]);
00238 
00239       if (l == TF_MQ_TIMEDRECEIVE)
00240        {
00241          /* mq_receive and mq_timedreceive are tested on empty mq.
00242             For mq_send and mq_timedsend we need to make it full.
00243             If this fails, there is no point in doing further testing.  */
00244          char c = ' ';
00245          if (mq_send (q, &c, 1, 1) != 0)
00246            {
00247              printf ("mq_send failed: %m\n");
00248              result = 1;
00249              break;
00250            }
00251        }
00252     }
00253 
00254   if (mq_close (q) != 0)
00255     {
00256       printf ("mq_close failed: %m\n");
00257       result = 1;
00258     }
00259 
00260   return result;
00261 }
00262 #else
00263 # define TEST_FUNCTION 0
00264 #endif
00265 
00266 #include "../test-skeleton.c"