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