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