/* * tsd1.c * * Test Thread Specific Data (TSD) key creation and destruction. * * * -------------------------------------------------------------------------- * * Pthreads-win32 - POSIX Threads Library for Win32 * Copyright(C) 1998 John E. Bossom * Copyright(C) 1999,2005 Pthreads-win32 contributors * * Contact Email: rpj@callisto.canberra.edu.au * * The current list of contributors is contained * in the file CONTRIBUTORS included with the source * code distribution. The list can also be seen at the * following World Wide Web location: * http://sources.redhat.com/pthreads-win32/contributors.html * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library in the file COPYING.LIB; * if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * * * -------------------------------------------------------------------------- * * Description: * - * * Test Method (validation or falsification): * - validation * * Requirements Tested: * - keys are created for each existing thread including the main thread * - keys are created for newly created threads * - keys are thread specific * - destroy routine is called on each thread exit including the main thread * * Features Tested: * - * * Cases Tested: * - * * Environment: * - * * Input: * - none * * Output: * - text to stdout * * Assumptions: * - already validated: pthread_create() * pthread_once() * - main thread also has a POSIX thread identity * * Pass Criteria: * - stdout matches file reference/tsd1.out * * Fail Criteria: * - fails to match file reference/tsd1.out * - output identifies failed component */ #include <sched.h> #include "test.h" enum { NUM_THREADS = 100 }; static pthread_key_t key = NULL; static int accesscount[NUM_THREADS]; static int thread_set[NUM_THREADS]; static int thread_destroyed[NUM_THREADS]; static pthread_barrier_t startBarrier; static void destroy_key(void * arg) { int * j = (int *) arg; (*j)++; assert(*j == 2); thread_destroyed[j - accesscount] = 1; } static void setkey(void * arg) { int * j = (int *) arg; thread_set[j - accesscount] = 1; assert(*j == 0); assert(pthread_getspecific(key) == NULL); assert(pthread_setspecific(key, arg) == 0); assert(pthread_setspecific(key, arg) == 0); assert(pthread_setspecific(key, arg) == 0); assert(pthread_getspecific(key) == arg); (*j)++; assert(*j == 1); } static void * mythread(void * arg) { (void) pthread_barrier_wait(&startBarrier); setkey(arg); return 0; /* Exiting the thread will call the key destructor. */ } int main() { int i; int fail = 0; pthread_t thread[NUM_THREADS]; assert(pthread_barrier_init(&startBarrier, NULL, NUM_THREADS/2) == 0); for (i = 1; i < NUM_THREADS/2; i++) { accesscount[i] = thread_set[i] = thread_destroyed[i] = 0; assert(pthread_create(&thread[i], NULL, mythread, (void *)&accesscount[i]) == 0); } /* * Here we test that existing threads will get a key created * for them. */ assert(pthread_key_create(&key, destroy_key) == 0); (void) pthread_barrier_wait(&startBarrier); /* * Test main thread key. */ accesscount[0] = 0; setkey((void *) &accesscount[0]); /* * Here we test that new threads will get a key created * for them. */ for (i = NUM_THREADS/2; i < NUM_THREADS; i++) { accesscount[i] = thread_set[i] = thread_destroyed[i] = 0; assert(pthread_create(&thread[i], NULL, mythread, (void *)&accesscount[i]) == 0); } /* * Wait for all threads to complete. */ for (i = 1; i < NUM_THREADS; i++) { int result = 0; assert(pthread_join(thread[i], (void **) &result) == 0); } assert(pthread_key_delete(key) == 0); assert(pthread_barrier_destroy(&startBarrier) == 0); for (i = 1; i < NUM_THREADS; i++) { /* * The counter is incremented once when the key is set to * a value, and again when the key is destroyed. If the key * doesn't get set for some reason then it will still be * NULL and the destroy function will not be called, and * hence accesscount will not equal 2. */ if (accesscount[i] != 2) { fail++; fprintf(stderr, "Thread %d key, set = %d, destroyed = %d\n", i, thread_set[i], thread_destroyed[i]); } } fflush(stderr); return (fail); }