1 /* Copyright (C) 2002-2022 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3 
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8 
9    The GNU C Library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Lesser General Public License for more details.
13 
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, see
16    <https://www.gnu.org/licenses/>.  */
17 
18 #include <errno.h>
19 #include <semaphore.h>
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <sys/mman.h>
26 #include <sys/wait.h>
27 
28 
29 int
do_test(void)30 do_test (void)
31 {
32   size_t ps = sysconf (_SC_PAGESIZE);
33   char tmpfname[] = "/tmp/tst-sem3.XXXXXX";
34   char data[ps];
35   void *mem;
36   int fd;
37   sem_t *s;
38   pid_t pid;
39   char *p;
40 
41   fd = mkstemp (tmpfname);
42   if (fd == -1)
43     {
44       printf ("cannot open temporary file: %m\n");
45       return 1;
46     }
47 
48   /* Make sure it is always removed.  */
49   unlink (tmpfname);
50 
51   /* Create one page of data.  */
52   memset (data, '\0', ps);
53 
54   /* Write the data to the file.  */
55   if (write (fd, data, ps) != (ssize_t) ps)
56     {
57       puts ("short write");
58       return 1;
59     }
60 
61   mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
62   if (mem == MAP_FAILED)
63     {
64       printf ("mmap failed: %m\n");
65       return 1;
66     }
67 
68   s = (sem_t *) (((uintptr_t) mem + __alignof (sem_t))
69 		 & ~(__alignof (sem_t) - 1));
70   p = (char *) (s + 1);
71 
72   if (sem_init (s, 1, 1) == -1)
73     {
74       puts ("init failed");
75       return 1;
76     }
77 
78   if (TEMP_FAILURE_RETRY (sem_wait (s)) == -1)
79     {
80       puts ("1st wait failed");
81       return 1;
82     }
83 
84   errno = 0;
85   if (TEMP_FAILURE_RETRY (sem_trywait (s)) != -1)
86     {
87       puts ("trywait succeeded");
88       return 1;
89     }
90   else if (errno != EAGAIN)
91     {
92       puts ("trywait didn't return EAGAIN");
93       return 1;
94     }
95 
96   *p = 0;
97 
98   puts ("going to fork now");
99   pid = fork ();
100   if (pid == -1)
101     {
102       puts ("fork failed");
103       return 1;
104     }
105   else if (pid == 0)
106     {
107       /* Play some lock ping-pong.  It's our turn to unlock first.  */
108       if ((*p)++ != 0)
109 	{
110 	  puts ("child: *p != 0");
111 	  return 1;
112 	}
113 
114       if (sem_post (s) == -1)
115 	{
116 	  puts ("child: 1st post failed");
117 	  return 1;
118 	}
119 
120       puts ("child done");
121     }
122   else
123     {
124       if (TEMP_FAILURE_RETRY (sem_wait (s)) == -1)
125 	{
126 	  printf ("parent: 2nd wait failed: %m\n");
127 	  return 1;
128 	}
129 
130       if (*p != 1)
131 	{
132 	  puts ("*p != 1");
133 	  return 1;
134 	}
135 
136       puts ("parent done");
137     }
138 
139   return 0;
140 }
141 
142 #define TEST_FUNCTION do_test ()
143 #include "../test-skeleton.c"
144