• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * tsd2.c
3  *
4  * Test Thread Specific Data (TSD) key creation and destruction.
5  *
6  *
7  * --------------------------------------------------------------------------
8  *
9  *      Pthreads-win32 - POSIX Threads Library for Win32
10  *      Copyright(C) 1998 John E. Bossom
11  *      Copyright(C) 1999,2005 Pthreads-win32 contributors
12  *
13  *      Contact Email: rpj@callisto.canberra.edu.au
14  *
15  *      The current list of contributors is contained
16  *      in the file CONTRIBUTORS included with the source
17  *      code distribution. The list can also be seen at the
18  *      following World Wide Web location:
19  *      http://sources.redhat.com/pthreads-win32/contributors.html
20  *
21  *      This library is free software; you can redistribute it and/or
22  *      modify it under the terms of the GNU Lesser General Public
23  *      License as published by the Free Software Foundation; either
24  *      version 2 of the License, or (at your option) any later version.
25  *
26  *      This library is distributed in the hope that it will be useful,
27  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
28  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
29  *      Lesser General Public License for more details.
30  *
31  *      You should have received a copy of the GNU Lesser General Public
32  *      License along with this library in the file COPYING.LIB;
33  *      if not, write to the Free Software Foundation, Inc.,
34  *      59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
35  *
36  *
37  * --------------------------------------------------------------------------
38  *
39  * Description:
40  * -
41  *
42  * Test Method (validation or falsification):
43  * - validation
44  *
45  * Requirements Tested:
46  * - keys are created for each existing thread including the main thread
47  * - keys are created for newly created threads
48  * - keys are thread specific
49  * - destroy routine is called on each thread exit including the main thread
50  *
51  * Features Tested:
52  * -
53  *
54  * Cases Tested:
55  * -
56  *
57  * Environment:
58  * -
59  *
60  * Input:
61  * - none
62  *
63  * Output:
64  * - text to stdout
65  *
66  * Assumptions:
67  * - already validated:     pthread_create()
68  *                          pthread_once()
69  * - main thread also has a POSIX thread identity
70  *
71  * Pass Criteria:
72  * - stdout matches file reference/tsd1.out
73  *
74  * Fail Criteria:
75  * - fails to match file reference/tsd1.out
76  * - output identifies failed component
77  */
78 
79 //#include <sched.h>
80 #include "test.h"
81 
82 enum {
83   NUM_THREADS = 100
84 };
85 
86 static pthread_key_t key = NULL;
87 static int accesscount[NUM_THREADS];
88 static int thread_set[NUM_THREADS];
89 static int thread_destroyed[NUM_THREADS];
90 static pthread_barrier_t startBarrier;
91 
92 static void
destroy_key(void * arg)93 destroy_key(void * arg)
94 {
95   int * j = (int *) arg;
96 
97   (*j)++;
98 
99   /* Set TSD key from the destructor to test destructor iteration */
100   if (*j == 2)
101     assert(pthread_setspecific(key, arg) == 0);
102   else
103     assert(*j == 3);
104 
105   thread_destroyed[j - accesscount] = 1;
106 }
107 
108 static void
setkey(void * arg)109 setkey(void * arg)
110 {
111   int * j = (int *) arg;
112 
113   thread_set[j - accesscount] = 1;
114 
115   assert(*j == 0);
116 
117   assert(pthread_getspecific(key) == NULL);
118 
119   assert(pthread_setspecific(key, arg) == 0);
120   assert(pthread_setspecific(key, arg) == 0);
121   assert(pthread_setspecific(key, arg) == 0);
122 
123   assert(pthread_getspecific(key) == arg);
124 
125   (*j)++;
126 
127   assert(*j == 1);
128 }
129 
130 static void *
mythread(void * arg)131 mythread(void * arg)
132 {
133   (void) pthread_barrier_wait(&startBarrier);
134 
135   setkey(arg);
136 
137   return 0;
138 
139   /* Exiting the thread will call the key destructor. */
140 }
141 
142 int
main()143 main()
144 {
145   int i;
146   int fail = 0;
147   pthread_t thread[NUM_THREADS];
148 
149   assert(pthread_barrier_init(&startBarrier, NULL, NUM_THREADS/2) == 0);
150 
151   for (i = 1; i < NUM_THREADS/2; i++)
152     {
153       accesscount[i] = thread_set[i] = thread_destroyed[i] = 0;
154       assert(pthread_create(&thread[i], NULL, mythread, (void *)&accesscount[i]) == 0);
155     }
156 
157   /*
158    * Here we test that existing threads will get a key created
159    * for them.
160    */
161   assert(pthread_key_create(&key, destroy_key) == 0);
162 
163   (void) pthread_barrier_wait(&startBarrier);
164 
165   /*
166    * Test main thread key.
167    */
168   accesscount[0] = 0;
169   setkey((void *) &accesscount[0]);
170 
171   /*
172    * Here we test that new threads will get a key created
173    * for them.
174    */
175   for (i = NUM_THREADS/2; i < NUM_THREADS; i++)
176     {
177       accesscount[i] = thread_set[i] = thread_destroyed[i] = 0;
178       assert(pthread_create(&thread[i], NULL, mythread, (void *)&accesscount[i]) == 0);
179     }
180 
181   /*
182    * Wait for all threads to complete.
183    */
184   for (i = 1; i < NUM_THREADS; i++)
185     {
186 	intptr_t result = 0;
187 
188 	assert(pthread_join(thread[i], (void **) &result) == 0);
189     }
190 
191   assert(pthread_key_delete(key) == 0);
192 
193   assert(pthread_barrier_destroy(&startBarrier) == 0);
194 
195   for (i = 1; i < NUM_THREADS; i++)
196     {
197 	/*
198 	 * The counter is incremented once when the key is set to
199 	 * a value, and again when the key is destroyed. If the key
200 	 * doesn't get set for some reason then it will still be
201 	 * NULL and the destroy function will not be called, and
202 	 * hence accesscount will not equal 2.
203 	 */
204 	if (accesscount[i] != 3)
205 	  {
206 	    fail++;
207 	    fprintf(stderr, "Thread %d key, set = %d, destroyed = %d\n",
208 			i, thread_set[i], thread_destroyed[i]);
209 	  }
210     }
211 
212   fflush(stderr);
213 
214   return (fail);
215 }
216