OSDN Git Service

Replace FSF snail mail address with URLs
[uclinux-h8/uClibc.git] / test / nptl / tst-mqueue3.c
1 /* Test SIGEV_THREAD handling for POSIX message queues.
2    Copyright (C) 2004 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
5
6    The GNU C Library is free software; you can redistribute it and/or
7    modify it under the terms of the GNU Lesser General Public
8    License as published by the Free Software Foundation; either
9    version 2.1 of the License, or (at your option) any later version.
10
11    The GNU C Library is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public
17    License along with the GNU C Library; if not, see
18    <http://www.gnu.org/licenses/>.  */
19
20 #include <errno.h>
21 #include <mqueue.h>
22 #include <signal.h>
23 #include <stddef.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/wait.h>
30 #include <unistd.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 %ld, expecte %d\n",
65               __FUNCTION__, attr.mq_maxmsg, MAXMSG);
66       exit (1);
67     }
68   if (attr.mq_msgsize != MAXMSG)
69     {
70       printf ("%s: mq_msgsize wrong: is %ld, expecte %d\n",
71               __FUNCTION__, 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   if (m == -1)
166     {
167       if (errno == ENOSYS)
168         {
169           puts ("not implemented");
170           return 0;
171         }
172
173       puts ("mq_open failed");
174       return 1;
175     }
176
177   /* Unlink the message queue right away.  */
178   if (mq_unlink (mqname) != 0)
179     {
180       puts ("mq_unlink failed");
181       return 1;
182     }
183
184   pid = fork ();
185   if (pid == -1)
186     {
187       puts ("fork failed");
188       return 1;
189     }
190   if (pid == 0)
191     {
192       /* Request notification via thread.  */
193       struct sigevent ev;
194       ev.sigev_notify = SIGEV_THREAD;
195       ev.sigev_notify_function = fct;
196       ev.sigev_value.sival_ptr = NULL;
197       ev.sigev_notify_attributes = NULL;
198
199       /* Tell the kernel.  */
200       if (mq_notify (m,&ev) != 0)
201         {
202           puts ("mq_notify failed");
203           exit (1);
204         }
205
206       /* Tell the parent we are ready.  */
207       (void) pthread_barrier_wait (b);
208
209       /* Make sure the process goes away eventually.  */
210       alarm (10);
211
212       /* Do nothing forever.  */
213       while (1)
214         pause ();
215     }
216
217   /* Wait for the child process to register to notification method.  */
218   (void) pthread_barrier_wait (b);
219
220   /* Send the message.  */
221   if (mq_send (m, message, sizeof (message), 1) != 0)
222     {
223       kill (pid, SIGKILL);
224       puts ("mq_send failed");
225       return 1;
226     }
227
228   int r;
229   if (TEMP_FAILURE_RETRY (waitpid (pid, &r, 0)) != pid)
230     {
231       kill (pid, SIGKILL);
232       puts ("waitpid failed");
233       return 1;
234     }
235
236   return WIFEXITED (r) && WEXITSTATUS (r) == UNIQUE ? 0 : 1;
237 }
238 # define TEST_FUNCTION do_test ()
239 #else
240 # define TEST_FUNCTION 0
241 #endif
242
243 #include "../test-skeleton.c"