• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * tsd1.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   assert(*j == 2);
100 
101   thread_destroyed[j - accesscount] = 1;
102 }
103 
104 static void
setkey(void * arg)105 setkey(void * arg)
106 {
107   int * j = (int *) arg;
108 
109   thread_set[j - accesscount] = 1;
110 
111   assert(*j == 0);
112 
113   assert(pthread_getspecific(key) == NULL);
114 
115   assert(pthread_setspecific(key, arg) == 0);
116   assert(pthread_setspecific(key, arg) == 0);
117   assert(pthread_setspecific(key, arg) == 0);
118 
119   assert(pthread_getspecific(key) == arg);
120 
121   (*j)++;
122 
123   assert(*j == 1);
124 }
125 
126 static void *
mythread(void * arg)127 mythread(void * arg)
128 {
129   (void) pthread_barrier_wait(&startBarrier);
130 
131   setkey(arg);
132 
133   return 0;
134 
135   /* Exiting the thread will call the key destructor. */
136 }
137 
138 int
main()139 main()
140 {
141   int i;
142   int fail = 0;
143   pthread_t thread[NUM_THREADS];
144 
145   assert(pthread_barrier_init(&startBarrier, NULL, NUM_THREADS/2) == 0);
146 
147   for (i = 1; i < NUM_THREADS/2; i++)
148     {
149       accesscount[i] = thread_set[i] = thread_destroyed[i] = 0;
150       assert(pthread_create(&thread[i], NULL, mythread, (void *)&accesscount[i]) == 0);
151     }
152 
153   /*
154    * Here we test that existing threads will get a key created
155    * for them.
156    */
157   assert(pthread_key_create(&key, destroy_key) == 0);
158 
159   (void) pthread_barrier_wait(&startBarrier);
160 
161   /*
162    * Test main thread key.
163    */
164   accesscount[0] = 0;
165   setkey((void *) &accesscount[0]);
166 
167   /*
168    * Here we test that new threads will get a key created
169    * for them.
170    */
171   for (i = NUM_THREADS/2; i < NUM_THREADS; i++)
172     {
173       accesscount[i] = thread_set[i] = thread_destroyed[i] = 0;
174       assert(pthread_create(&thread[i], NULL, mythread, (void *)&accesscount[i]) == 0);
175     }
176 
177   /*
178    * Wait for all threads to complete.
179    */
180   for (i = 1; i < NUM_THREADS; i++)
181     {
182 	intptr_t result = 0;
183 
184 	assert(pthread_join(thread[i], (void **) &result) == 0);
185     }
186 
187   assert(pthread_key_delete(key) == 0);
188 
189   assert(pthread_barrier_destroy(&startBarrier) == 0);
190 
191   for (i = 1; i < NUM_THREADS; i++)
192     {
193 	/*
194 	 * The counter is incremented once when the key is set to
195 	 * a value, and again when the key is destroyed. If the key
196 	 * doesn't get set for some reason then it will still be
197 	 * NULL and the destroy function will not be called, and
198 	 * hence accesscount will not equal 2.
199 	 */
200 	if (accesscount[i] != 2)
201 	  {
202 	    fail++;
203 	    fprintf(stderr, "Thread %d key, set = %d, destroyed = %d\n",
204 			i, thread_set[i], thread_destroyed[i]);
205 	  }
206     }
207 
208   fflush(stderr);
209 
210   return (fail);
211 }
212