1 /* Test of POSIX barriers.
2    Copyright (C) 2002-2022 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 <pthread.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 
24 #define NTHREADS 20
25 
26 #define ROUNDS 20
27 
28 static pthread_barrier_t barriers[NTHREADS];
29 
30 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
31 static int counters[NTHREADS];
32 static int serial[NTHREADS];
33 
34 static void *
worker(void * arg)35 worker (void *arg)
36 {
37   void *result = NULL;
38   int nr = (long int) arg;
39   int i;
40 
41   for (i = 0; i < ROUNDS; ++i)
42     {
43       int j;
44       int retval;
45 
46       if (nr == 0)
47 	{
48 	  memset (counters, '\0', sizeof (counters));
49 	  memset (serial, '\0', sizeof (serial));
50 	}
51 
52       retval = pthread_barrier_wait (&barriers[NTHREADS - 1]);
53       if (retval != 0 && retval != PTHREAD_BARRIER_SERIAL_THREAD)
54 	{
55 	  printf ("thread %d failed to wait for all the others\n", nr);
56 	  result = (void *) 1;
57 	}
58 
59       for (j = nr; j < NTHREADS; ++j)
60 	{
61 	  /* Increment the counter for this round.  */
62 	  pthread_mutex_lock (&lock);
63 	  ++counters[j];
64 	  pthread_mutex_unlock (&lock);
65 
66 	  /* Wait for the rest.  */
67 	  retval = pthread_barrier_wait (&barriers[j]);
68 
69 	  /* Test the result.  */
70 	  if (nr == 0 && counters[j] != j + 1)
71 	    {
72 	      printf ("barrier in round %d released but count is %d\n",
73 		      j, counters[j]);
74 	      result = (void *) 1;
75 	    }
76 
77 	  if (retval != 0)
78 	    {
79 	      if (retval != PTHREAD_BARRIER_SERIAL_THREAD)
80 		{
81 		  printf ("thread %d in round %d has nonzero return value != PTHREAD_BARRIER_SERIAL_THREAD\n",
82 			  nr, j);
83 		  result = (void *) 1;
84 		}
85 	      else
86 		{
87 		  pthread_mutex_lock (&lock);
88 		  ++serial[j];
89 		  pthread_mutex_unlock (&lock);
90 		}
91 	    }
92 
93 	  /* Wait for the rest again.  */
94 	  retval = pthread_barrier_wait (&barriers[j]);
95 
96 	  /* Now we can check whether exactly one thread was serializing.  */
97 	  if (nr == 0 && serial[j] != 1)
98 	    {
99 	      printf ("not exactly one serial thread in round %d\n", j);
100 	      result = (void *) 1;
101 	    }
102 	}
103     }
104 
105   return result;
106 }
107 
108 
109 #define TEST_FUNCTION do_test ()
110 #define TIMEOUT 60
111 static int
do_test(void)112 do_test (void)
113 {
114   pthread_t threads[NTHREADS];
115   int i;
116   void *res;
117   int result = 0;
118 
119   /* Initialized the barrier variables.  */
120   for (i = 0; i < NTHREADS; ++i)
121     if (pthread_barrier_init (&barriers[i], NULL, i + 1) != 0)
122       {
123 	printf ("Failed to initialize barrier %d\n", i);
124 	exit (1);
125       }
126 
127   /* Start the threads.  */
128   for (i = 0; i < NTHREADS; ++i)
129     if (pthread_create (&threads[i], NULL, worker, (void *) (long int) i) != 0)
130       {
131 	printf ("Failed to start thread %d\n", i);
132 	exit (1);
133       }
134 
135   /* And wait for them.  */
136   for (i = 0; i < NTHREADS; ++i)
137     if (pthread_join (threads[i], &res) != 0 || res != NULL)
138       {
139 	printf ("thread %d returned a failure\n", i);
140 	result = 1;
141       }
142     else
143       printf ("joined threads %d\n", i);
144 
145   if (result == 0)
146     puts ("all OK");
147 
148   return result;
149 }
150 
151 #include "../test-skeleton.c"
152