1 #include <pthread.h>
2 #include <signal.h>
3 #include <stdint.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <unistd.h>
8 #include <sys/mman.h>
9 #include <sys/wait.h>
10 
11 #include <pthreadP.h>
12 
13 
14 
15 static void prepare (void);
16 #define PREPARE(argc, argv) prepare ()
17 static int do_test (void);
18 #define TEST_FUNCTION do_test ()
19 #include "../test-skeleton.c"
20 
21 
22 static int fd;
23 #define N 100
24 
25 static void
prepare(void)26 prepare (void)
27 {
28   fd = create_temp_file ("tst-robust8", NULL);
29   if (fd == -1)
30     exit (1);
31 }
32 
33 
34 #define THESIGNAL SIGKILL
35 #define ROUNDS 5
36 #define THREADS 9
37 
38 
39 static const struct timespec before = { 0, 0 };
40 
41 
42 static pthread_mutex_t *map;
43 
44 
45 static void *
tf(void * arg)46 tf (void *arg)
47 {
48   long int nr = (long int) arg;
49   int fct = nr % 3;
50 
51   uint8_t state[N];
52   memset (state, '\0', sizeof (state));
53 
54   while (1)
55     {
56       int r = random () % N;
57       if (state[r] == 0)
58 	{
59 	  int e;
60 
61 	  switch (fct)
62 	    {
63 	    case 0:
64 	      e = pthread_mutex_lock (&map[r]);
65 	      if (e != 0)
66 		{
67 		  printf ("mutex_lock of %d in thread %ld failed with %d\n",
68 			  r, nr, e);
69 		  exit (1);
70 		}
71 	      state[r] = 1;
72 	      break;
73 	    case 1:
74 	      e = pthread_mutex_timedlock (&map[r], &before);
75 	      if (e != 0 && e != ETIMEDOUT)
76 		{
77 		  printf ("\
78 mutex_timedlock of %d in thread %ld failed with %d\n",
79 			  r, nr, e);
80 		  exit (1);
81 		}
82 	      break;
83 	    default:
84 	      e = pthread_mutex_trylock (&map[r]);
85 	      if (e != 0 && e != EBUSY)
86 		{
87 		  printf ("mutex_trylock of %d in thread %ld failed with %d\n",
88 			  r, nr, e);
89 		  exit (1);
90 		}
91 	      break;
92 	    }
93 
94 	  if (e == EOWNERDEAD)
95 	    pthread_mutex_consistent (&map[r]);
96 
97 	  if (e == 0 || e == EOWNERDEAD)
98 	    state[r] = 1;
99 	}
100       else
101 	{
102 	  int e = pthread_mutex_unlock (&map[r]);
103 	  if (e != 0)
104 	    {
105 	      printf ("mutex_unlock of %d in thread %ld failed with %d\n",
106 		      r, nr, e);
107 	      exit (1);
108 	    }
109 
110 	  state[r] = 0;
111 	}
112     }
113 }
114 
115 
116 static void
child(int round)117 child (int round)
118 {
119   for (int thread = 1; thread <= THREADS; ++thread)
120     {
121       pthread_t th;
122       if (pthread_create (&th, NULL, tf, (void *) (long int) thread) != 0)
123 	{
124 	  printf ("cannot create thread %d in round %d\n", thread, round);
125 	  exit (1);
126 	}
127     }
128 
129   struct timespec ts;
130   ts.tv_sec = 0;
131   ts.tv_nsec = 1000000000 / ROUNDS;
132   while (nanosleep (&ts, &ts) != 0)
133     /* nothing */;
134 
135   /* Time to die.  */
136   kill (getpid (), THESIGNAL);
137 
138   /* We better never get here.  */
139   abort ();
140 }
141 
142 
143 static int
do_test(void)144 do_test (void)
145 {
146   if (ftruncate (fd, N * sizeof (pthread_mutex_t)) != 0)
147     {
148       puts ("cannot size new file");
149       return 1;
150     }
151 
152   map = mmap (NULL, N * sizeof (pthread_mutex_t), PROT_READ | PROT_WRITE,
153 	      MAP_SHARED, fd, 0);
154   if (map == MAP_FAILED)
155     {
156       puts ("mapping failed");
157       return 1;
158     }
159 
160   pthread_mutexattr_t ma;
161   if (pthread_mutexattr_init (&ma) != 0)
162     {
163       puts ("mutexattr_init failed");
164       return 0;
165     }
166   if (pthread_mutexattr_setrobust (&ma, PTHREAD_MUTEX_ROBUST_NP) != 0)
167     {
168       puts ("mutexattr_setrobust failed");
169       return 1;
170     }
171   if (pthread_mutexattr_setpshared (&ma, PTHREAD_PROCESS_SHARED) != 0)
172     {
173       puts ("mutexattr_setpshared failed");
174       return 1;
175     }
176 #ifdef ENABLE_PI
177   if (pthread_mutexattr_setprotocol (&ma, PTHREAD_PRIO_INHERIT) != 0)
178     {
179       puts ("pthread_mutexattr_setprotocol failed");
180       return 1;
181     }
182 #endif
183 
184   for (int round = 1; round <= ROUNDS; ++round)
185     {
186       for (int n = 0; n < N; ++n)
187 	{
188 	  int e = pthread_mutex_init (&map[n], &ma);
189 	  if (e == ENOTSUP)
190 	    {
191 #ifdef ENABLE_PI
192 	      puts ("cannot support pshared robust PI mutexes");
193 #else
194 	      puts ("cannot support pshared robust mutexes");
195 #endif
196 	      return 0;
197 	    }
198 	  if (e != 0)
199 	    {
200 	      printf ("mutex_init %d in round %d failed\n", n + 1, round);
201 	      return 1;
202 	    }
203 	}
204 
205       pid_t p = fork ();
206       if (p == -1)
207 	{
208 	  printf ("fork in round %d failed\n", round);
209 	  return 1;
210 	}
211       if (p == 0)
212 	child (round);
213 
214       int status;
215       if (TEMP_FAILURE_RETRY (waitpid (p, &status, 0)) != p)
216 	{
217 	  printf ("waitpid in round %d failed\n", round);
218 	  return 1;
219 	}
220       if (!WIFSIGNALED (status))
221 	{
222 	  printf ("child did not die of a signal in round %d\n", round);
223 	  return 1;
224 	}
225       if (WTERMSIG (status) != THESIGNAL)
226 	{
227 	  printf ("child did not die of signal %d in round %d\n",
228 		  THESIGNAL, round);
229 	  return 1;
230 	}
231 
232       for (int n = 0; n < N; ++n)
233 	{
234 	  int e = pthread_mutex_lock (&map[n]);
235 	  if (e != 0 && e != EOWNERDEAD)
236 	    {
237 	      printf ("mutex_lock %d failed in round %d\n", n + 1, round);
238 	      return 1;
239 	    }
240 	}
241 
242       for (int n = 0; n < N; ++n)
243 	if (pthread_mutex_unlock (&map[n]) != 0)
244 	  {
245 	    printf ("mutex_unlock %d failed in round %d\n", n + 1, round);
246 	    return 1;
247 	  }
248 
249       for (int n = 0; n < N; ++n)
250 	{
251 	  int e = pthread_mutex_destroy (&map[n]);
252 	  if (e != 0)
253 	    {
254 	      printf ("mutex_destroy %d in round %d failed with %d\n",
255 		      n + 1, round, e);
256 #ifdef __PTHREAD_NPTL
257 	      printf("nusers = %d\n", (int) map[n].__data.__nusers);
258 #endif
259 	      return 1;
260 	    }
261 	}
262     }
263 
264   if (pthread_mutexattr_destroy (&ma) != 0)
265     {
266       puts ("mutexattr_destroy failed");
267       return 1;
268     }
269 
270   if (munmap (map, N * sizeof (pthread_mutex_t)) != 0)
271     {
272       puts ("munmap failed");
273       return 1;
274     }
275 
276   return 0;
277 }
278