1/* 2 * Copyright (c) 2004, Bull S.A.. All rights reserved. 3 * Created by: Sebastien Decugis 4 5 * This program is free software; you can redistribute it and/or modify it 6 * under the terms of version 2 of the GNU General Public License as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it would be useful, but 10 * WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 * 13 * You should have received a copy of the GNU General Public License along 14 * with this program; if not, write the Free Software Foundation, Inc., 59 15 * Temple Place - Suite 330, Boston MA 02111-1307, USA. 16 17 18 * This sample test aims to check the following assertion: 19 * 20 * The TLD destructors (if any) are executed after the cancelation cleanup handlers, 21 * in unspecified order. 22 23 * The steps are: 24 * 25 * -> Create threads with different attributes (but all must be joinable) 26 * -> inside the thread, 27 * -> register three cancelation handlers 28 * -> call pthread_exit. 29 * -> In the main thread, we join the thread and check the cleanups were executed in order. 30 31 */ 32 33 34 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */ 35 #define _POSIX_C_SOURCE 200112L 36 37 /* Some routines are part of the XSI Extensions */ 38#ifndef WITHOUT_XOPEN 39 #define _XOPEN_SOURCE 600 40#endif 41 42/********************************************************************************************/ 43/****************************** standard includes *****************************************/ 44/********************************************************************************************/ 45 #include <pthread.h> 46 #include <stdarg.h> 47 #include <stdio.h> 48 #include <stdlib.h> 49 #include <string.h> 50 #include <unistd.h> 51 52 #include <sched.h> 53 #include <semaphore.h> 54 #include <errno.h> 55 #include <assert.h> 56/********************************************************************************************/ 57/****************************** Test framework *****************************************/ 58/********************************************************************************************/ 59 #include "testfrmw.h" 60 #include "testfrmw.c" 61 /* This header is responsible for defining the following macros: 62 * UNRESOLVED(ret, descr); 63 * where descr is a description of the error and ret is an int (error code for example) 64 * FAILED(descr); 65 * where descr is a short text saying why the test has failed. 66 * PASSED(); 67 * No parameter. 68 * 69 * Both three macros shall terminate the calling process. 70 * The testcase shall not terminate in any other maneer. 71 * 72 * The other file defines the functions 73 * void output_init() 74 * void output(char * string, ...) 75 * 76 * Those may be used to output information. 77 */ 78 79/********************************************************************************************/ 80/********************************** Configuration ******************************************/ 81/********************************************************************************************/ 82#ifndef VERBOSE 83#define VERBOSE 1 84#endif 85 86/********************************************************************************************/ 87/*********************************** Test cases *****************************************/ 88/********************************************************************************************/ 89 90#include "threads_scenarii.c" 91 92/* This file will define the following objects: 93 * scenarii: array of struct __scenario type. 94 * NSCENAR : macro giving the total # of scenarii 95 * scenar_init(): function to call before use the scenarii array. 96 * scenar_fini(): function to call after end of use of the scenarii array. 97 */ 98 99/********************************************************************************************/ 100/*********************************** Real Test *****************************************/ 101/********************************************************************************************/ 102 103int global=0; 104int tab[4]; 105pthread_key_t tld[3]; 106 107#define CLEANUP(n) void clnp##n(void * arg)\ 108{\ 109 tab[global]=n; \ 110 global++; \ 111} 112 113/* Cancelation cleanup handlers */ 114CLEANUP(1) 115CLEANUP(2) 116CLEANUP(3) 117 118/* TLD destructor */ 119void destructor(void * arg) 120{ 121 *(int *) arg += global; 122} 123 124/* Thread routine */ 125void * threaded (void * arg) 126{ 127 int ret = 0; 128 129 ret = pthread_setspecific(tld[0], (void *)&tab[3]); 130 if (ret != 0) { UNRESOLVED(ret, "Failed to set TLD data"); } 131 132 pthread_cleanup_push(clnp3, NULL); 133 pthread_cleanup_push(clnp2, NULL); 134 ret = pthread_setspecific(tld[1], (void *)&tab[3]); 135 if (ret != 0) { UNRESOLVED(ret, "Failed to set TLD data"); } 136 137 pthread_cleanup_push(clnp1, NULL); 138 ret = pthread_setspecific(tld[2], (void *)&tab[3]); 139 if (ret != 0) { UNRESOLVED(ret, "Failed to set TLD data"); } 140 141 pthread_exit(NULL + 1); 142 143 pthread_cleanup_pop(0); 144 pthread_cleanup_pop(0); 145 pthread_cleanup_pop(0); 146 147 FAILED("pthread_exit() did not terminate the thread"); 148 return NULL; 149} 150 151 152int main (int argc, char *argv[]) 153{ 154 int ret=0; 155 void * rval; 156 pthread_t child; 157 int i,j; 158 159 output_init(); 160 161 scenar_init(); 162 163 for (j=0; j<3; j++) 164 { 165 ret = pthread_key_create(&tld[j], destructor); 166 if (ret != 0) { UNRESOLVED(ret, "Failed to create a TLD key"); } 167 } 168 169 for (i=0; i < NSCENAR; i++) 170 { 171 if (scenarii[i].detached == 0) 172 { 173 #if VERBOSE > 0 174 output("-----\n"); 175 output("Starting test with scenario (%i): %s\n", i, scenarii[i].descr); 176 #endif 177 178 for (j=0; j<4; j++) 179 tab[j]=0; 180 global=0; 181 182 ret = pthread_create(&child, &scenarii[i].ta, threaded, NULL); 183 switch (scenarii[i].result) 184 { 185 case 0: /* Operation was expected to succeed */ 186 if (ret != 0) { UNRESOLVED(ret, "Failed to create this thread"); } 187 break; 188 189 case 1: /* Operation was expected to fail */ 190 if (ret == 0) { UNRESOLVED(-1, "An error was expected but the thread creation succeeded"); } 191 break; 192 193 case 2: /* We did not know the expected result */ 194 default: 195 #if VERBOSE > 0 196 if (ret == 0) 197 { output("Thread has been created successfully for this scenario\n"); } 198 else 199 { output("Thread creation failed with the error: %s\n", strerror(ret)); } 200 #endif 201 } 202 if (ret == 0) /* The new thread is running */ 203 { 204 ret = pthread_join(child, &rval); 205 if (ret != 0) { UNRESOLVED(ret, "Unable to join a thread"); } 206 207 if (rval != (NULL+1)) 208 { 209 FAILED("pthread_join() did not retrieve the pthread_exit() param"); 210 } 211 212 for (j=0; j<3; j++) 213 { 214 if ((tab[j] != j+1) || (tab[3] != 9)) 215 { 216 output("dump:\ntab[0]=%i\ntab[1]=%i\ntab[2]=%i\ntab[3]=%i\n", tab[0], tab[1], tab[2], tab[3]); 217 FAILED("The cleanup handlers were not called as expected"); 218 } 219 } 220 } 221 } 222 } 223 224 for (j=0; j<3; j++) 225 { 226 ret = pthread_key_delete(tld[j]); 227 if (ret != 0) { UNRESOLVED(ret, "Failed to delete a TLD key"); } 228 } 229 230 scenar_fini(); 231 #if VERBOSE > 0 232 output("-----\n"); 233 output("All test data destroyed\n"); 234 output("Test PASSED\n"); 235 #endif 236 237 PASSED; 238} 239 240