xref: /relibc/pthreads-emb/tests/condvar7.c (revision 714af18cbe52336f4ff71fe91bfb035d5efaef7d)
1 /*
2  * File: condvar7.c
3  *
4  *
5  * --------------------------------------------------------------------------
6  *
7  *      Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems
8  *      Copyright(C) 2008 Jason Schmidlapp
9  *
10  *      Contact Email: jschmidlapp@users.sourceforge.net
11  *
12  *
13  *      Based upon Pthreads-win32 - POSIX Threads Library for Win32
14  *      Copyright(C) 1998 John E. Bossom
15  *      Copyright(C) 1999,2005 Pthreads-win32 contributors
16  *
17  *      Contact Email: rpj@callisto.canberra.edu.au
18  *
19  *      The original list of contributors to the Pthreads-win32 project
20  *      is contained in the file CONTRIBUTORS.ptw32 included with the
21  *      source code distribution. The list can also be seen at the
22  *      following World Wide Web location:
23  *      http://sources.redhat.com/pthreads-win32/contributors.html
24  *
25  *      This library is free software; you can redistribute it and/or
26  *      modify it under the terms of the GNU Lesser General Public
27  *      License as published by the Free Software Foundation; either
28  *      version 2 of the License, or (at your option) any later version.
29  *
30  *      This library is distributed in the hope that it will be useful,
31  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
32  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
33  *      Lesser General Public License for more details.
34  *
35  *      You should have received a copy of the GNU Lesser General Public
36  *      License along with this library in the file COPYING.LIB;
37  *      if not, write to the Free Software Foundation, Inc.,
38  *      59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
39  *
40  * --------------------------------------------------------------------------
41  *
42  * Test Synopsis:
43  * - Test pthread_cond_broadcast with thread cancelation.
44  *
45  * Test Method (Validation or Falsification):
46  * - Validation
47  *
48  * Requirements Tested:
49  * -
50  *
51  * Features Tested:
52  * -
53  *
54  * Cases Tested:
55  * -
56  *
57  * Description:
58  * - Test broadcast with NUMTHREADS (=5) waiting CVs, one is canceled while waiting.
59  *
60  * Environment:
61  * -
62  *
63  * Input:
64  * - None.
65  *
66  * Output:
67  * - File name, Line number, and failed expression on failure.
68  * - No output on success.
69  *
70  * Assumptions:
71  * -
72  *
73  * Pass Criteria:
74  * - Process returns zero exit status.
75  *
76  * Fail Criteria:
77  * - Process returns non-zero exit status.
78  */
79 
80 #include "test.h"
81 
82 
83 /*
84  * Create NUMTHREADS threads in addition to the Main thread.
85  */
86 enum
87 {
88   NUMTHREADS = 5
89 };
90 
91 typedef struct bag_t_ bag_t;
92 struct bag_t_
93   {
94     int threadnum;
95     int started;
96     /* Add more per-thread state variables here */
97   };
98 
99 static bag_t threadbag[NUMTHREADS + 1];
100 
101 typedef struct cvthing_t_ cvthing_t;
102 
103 struct cvthing_t_
104   {
105     pthread_cond_t notbusy;
106     pthread_mutex_t lock;
107     int shared;
108   };
109 
110 static cvthing_t cvthing =
111 {
112   PTHREAD_COND_INITIALIZER,
113   PTHREAD_MUTEX_INITIALIZER,
114   0
115 };
116 
117 static pthread_mutex_t start_flag = PTHREAD_MUTEX_INITIALIZER;
118 
119 static struct timespec abstime =
120   {
121     0, 0
122   };
123 
124 static int awoken;
125 
126 static void *
127 mythread(void * arg)
128 {
129   bag_t * bag = (bag_t *) arg;
130 
131   assert(bag == &threadbag[bag->threadnum]);
132   assert(bag->started == 0);
133   bag->started = 1;
134 
135   /* Wait for the start gun */
136   assert(pthread_mutex_lock(&start_flag) == 0);
137   assert(pthread_mutex_unlock(&start_flag) == 0);
138 
139   assert(pthread_mutex_lock(&cvthing.lock) == 0);
140 
141   pthread_cleanup_push(pthread_mutex_unlock, (void *) &cvthing.lock);
142 
143   while (! (cvthing.shared > 0))
144     {
145       assert(pthread_cond_timedwait(&cvthing.notbusy, &cvthing.lock, &abstime) == 0);
146     }
147 
148   pthread_cleanup_pop(0);
149 
150   assert(cvthing.shared > 0);
151 
152   awoken++;
153 
154   assert(pthread_mutex_unlock(&cvthing.lock) == 0);
155 
156   return (void *) 0;
157 }
158 
159 int pthread_test_condvar7()
160 {
161   int failed = 0;
162   int i;
163   pthread_t t[NUMTHREADS + 1];
164 
165   struct _timeb currSysTime;
166   const unsigned int NANOSEC_PER_MILLISEC = 1000000;
167 
168   cvthing.notbusy = PTHREAD_COND_INITIALIZER;
169   cvthing.lock = PTHREAD_MUTEX_INITIALIZER;
170 
171   cvthing.shared = 0;
172 
173   assert((t[0] = pthread_self()).p != NULL);
174 
175   assert(cvthing.notbusy == PTHREAD_COND_INITIALIZER);
176 
177   assert(cvthing.lock == PTHREAD_MUTEX_INITIALIZER);
178 
179   assert(pthread_mutex_lock(&start_flag) == 0);
180 
181   _ftime(&currSysTime);
182 
183   abstime.tv_sec = currSysTime.time;
184   abstime.tv_nsec = NANOSEC_PER_MILLISEC * currSysTime.millitm;
185 
186   abstime.tv_sec += 10;
187 
188   assert((t[0] = pthread_self()).p != NULL);
189 
190   awoken = 0;
191 
192   for (i = 1; i <= NUMTHREADS; i++)
193     {
194       threadbag[i].started = 0;
195       threadbag[i].threadnum = i;
196       assert(pthread_create(&t[i], NULL, mythread, (void *) &threadbag[i]) == 0);
197     }
198 
199   /*
200    * Code to control or munipulate child threads should probably go here.
201    */
202 
203   assert(pthread_mutex_unlock(&start_flag) == 0);
204 
205   /*
206    * Give threads time to start.
207    */
208   pte_osThreadSleep(1000);
209 
210   /*
211    * Cancel one of the threads.
212    */
213   assert(pthread_cancel(t[1]) == 0);
214   assert(pthread_join(t[1], NULL) == 0);
215 
216   assert(pthread_mutex_lock(&cvthing.lock) == 0);
217   cvthing.shared++;
218   assert(pthread_mutex_unlock(&cvthing.lock) == 0);
219 
220   /*
221    * Signal all remaining waiting threads.
222    */
223   assert(pthread_cond_broadcast(&cvthing.notbusy) == 0);
224 
225   /*
226    * Wait for all threads to complete.
227    */
228   for (i = 2; i <= NUMTHREADS; i++)
229     assert(pthread_join(t[i], NULL) == 0);
230 
231   /*
232    * Cleanup the CV.
233    */
234 
235   assert(pthread_mutex_destroy(&cvthing.lock) == 0);
236 
237   assert(cvthing.lock == NULL);
238 
239   assert(pthread_cond_destroy(&cvthing.notbusy) == 0);
240 
241   assert(cvthing.notbusy == NULL);
242 
243   /*
244    * Standard check that all threads started.
245    */
246   for (i = 1; i <= NUMTHREADS; i++)
247     {
248       failed = !threadbag[i].started;
249     }
250 
251   assert(!failed);
252 
253   /*
254    * Check any results here.
255    */
256 
257   assert(awoken == (NUMTHREADS - 1));
258 
259   /*
260    * Success.
261    */
262   return 0;
263 }
264