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 <pthread.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <time.h>
23 
24 /* This test is a template for other tests to use.  Other tests define
25    the following macros to change the behaviour of the template test.
26    The test is very simple, it configures N threads given the parameters
27    below and then proceeds to go through mutex lock and unlock
28    operations in each thread as described before for the thread
29    function.  */
30 #ifndef TYPE
31 # define TYPE PTHREAD_MUTEX_DEFAULT
32 #endif
33 #ifndef ROBUST
34 # define ROBUST PTHREAD_MUTEX_STALLED
35 #endif
36 #ifndef DELAY_NSEC
37 # define DELAY_NSEC 11000
38 #endif
39 #ifndef ROUNDS
40 # define ROUNDS 1000
41 #endif
42 #ifndef N
43 # define N 100
44 #endif
45 
46 static pthread_mutex_t lock;
47 
48 /* Each thread locks and the subsequently unlocks the lock, yielding
49    the smallest critical section possible.  After the unlock the thread
50    waits DELAY_NSEC nanoseconds before doing the lock and unlock again.
51    Every thread does this ROUNDS times.  The lock and unlock are
52    checked for errors.  */
53 static void *
tf(void * arg)54 tf (void *arg)
55 {
56   int nr = (long int) arg;
57   int cnt;
58   struct timespec ts = { .tv_sec = 0, .tv_nsec = DELAY_NSEC };
59 
60   for (cnt = 0; cnt < ROUNDS; ++cnt)
61     {
62       if (pthread_mutex_lock (&lock) != 0)
63 	{
64 	  printf ("thread %d: failed to get the lock\n", nr);
65 	  return (void *) 1l;
66 	}
67 
68       if (pthread_mutex_unlock (&lock) != 0)
69 	{
70 	  printf ("thread %d: failed to release the lock\n", nr);
71 	  return (void *) 1l;
72 	}
73 
74       if ((ts.tv_sec > 0) || (ts.tv_nsec > 0))
75 	nanosleep (&ts, NULL);
76     }
77 
78   return NULL;
79 }
80 
81 /* Setup and run N threads, where each thread does as described
82    in the above thread function.  The threads are given a minimal 1MiB
83    stack since they don't do anything between the lock and unlock.  */
84 static int
do_test(void)85 do_test (void)
86 {
87   pthread_mutexattr_t a;
88 
89   if (pthread_mutexattr_init (&a) != 0)
90     {
91       puts ("mutexattr_init failed");
92       exit (1);
93     }
94 
95   if (pthread_mutexattr_settype (&a, TYPE) != 0)
96     {
97       puts ("mutexattr_settype failed");
98       exit (1);
99     }
100 
101   if (pthread_mutexattr_setrobust (&a, ROBUST) != 0)
102     {
103       puts ("mutexattr_setrobust failed");
104       exit (1);
105     }
106 
107 #ifdef ENABLE_PI
108   if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0)
109     {
110       puts ("pthread_mutexattr_setprotocol failed");
111       return 1;
112     }
113 #endif
114 
115   int e = pthread_mutex_init (&lock, &a);
116   if (e != 0)
117     {
118 #ifdef ENABLE_PI
119       if (e == ENOTSUP)
120 	{
121 	  puts ("PI mutexes unsupported");
122 	  return 0;
123 	}
124 #endif
125       puts ("mutex_init failed");
126       return 1;
127     }
128 
129   if (pthread_mutexattr_destroy (&a) != 0)
130     {
131       puts ("mutexattr_destroy failed");
132       return 1;
133     }
134 
135   pthread_attr_t at;
136   pthread_t th[N];
137   int cnt;
138 
139   if (pthread_attr_init (&at) != 0)
140     {
141       puts ("attr_init failed");
142       return 1;
143     }
144 
145   if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0)
146     {
147       puts ("attr_setstacksize failed");
148       return 1;
149     }
150 
151   if (pthread_mutex_lock (&lock) != 0)
152     {
153       puts ("locking in parent failed");
154       return 1;
155     }
156 
157   for (cnt = 0; cnt < N; ++cnt)
158     if (pthread_create (&th[cnt], &at, tf, (void *) (long int) cnt) != 0)
159       {
160 	printf ("creating thread %d failed\n", cnt);
161 	return 1;
162       }
163 
164   if (pthread_attr_destroy (&at) != 0)
165     {
166       puts ("attr_destroy failed");
167       return 1;
168     }
169 
170   if (pthread_mutex_unlock (&lock) != 0)
171     {
172       puts ("unlocking in parent failed");
173       return 1;
174     }
175 
176   for (cnt = 0; cnt < N; ++cnt)
177     if (pthread_join (th[cnt], NULL) != 0)
178       {
179 	printf ("joining thread %d failed\n", cnt);
180 	return 1;
181       }
182 
183   return 0;
184 }
185 
186 #define TIMEOUT 60
187 #define TEST_FUNCTION do_test ()
188 #include "../test-skeleton.c"
189