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., 15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 17 * This sample test aims to check the following assertion: 18 * 19 * pthread_detach() does not force a thread to terminate. 20 21 * The steps are: 22 * 23 * -> Create a thread 24 * -> detach the thread 25 * -> wait for the thread to post a semaphore. 26 27 * The test fails if the semaphore is not posted within a certain duration. 28 29 */ 30 31 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */ 32#define _POSIX_C_SOURCE 200112L 33 34 /* Some routines are part of the XSI Extensions */ 35#ifndef WITHOUT_XOPEN 36#define _XOPEN_SOURCE 600 37#endif 38/********************************************************************************************/ 39/****************************** standard includes *****************************************/ 40/********************************************************************************************/ 41#include <pthread.h> 42#include <stdarg.h> 43#include <stdio.h> 44#include <stdlib.h> 45#include <string.h> 46#include <unistd.h> 47 48#include <sched.h> 49#include <semaphore.h> 50#include <time.h> 51#include <errno.h> 52#include <assert.h> 53/********************************************************************************************/ 54/****************************** Test framework *****************************************/ 55/********************************************************************************************/ 56#include "../testfrmw/testfrmw.h" 57#include "../testfrmw/testfrmw.c" 58 /* This header is responsible for defining the following macros: 59 * UNRESOLVED(ret, descr); 60 * where descr is a description of the error and ret is an int (error code for example) 61 * FAILED(descr); 62 * where descr is a short text saying why the test has failed. 63 * PASSED(); 64 * No parameter. 65 * 66 * Both three macros shall terminate the calling process. 67 * The testcase shall not terminate in any other maneer. 68 * 69 * The other file defines the functions 70 * void output_init() 71 * void output(char * string, ...) 72 * 73 * Those may be used to output information. 74 */ 75 76/********************************************************************************************/ 77/********************************** Configuration ******************************************/ 78/********************************************************************************************/ 79#ifndef VERBOSE 80#define VERBOSE 1 81#endif 82 83#define TIMEOUT 5 84 85/********************************************************************************************/ 86/*********************************** Test cases *****************************************/ 87/********************************************************************************************/ 88 89#include "../testfrmw/threads_scenarii.c" 90 91/* This file will define the following objects: 92 * scenarii: array of struct __scenario type. 93 * NSCENAR : macro giving the total # of scenarii 94 * scenar_init(): function to call before use the scenarii array. 95 * scenar_fini(): function to call after end of use of the scenarii array. 96 */ 97 98/********************************************************************************************/ 99/*********************************** Real Test *****************************************/ 100/********************************************************************************************/ 101 102sem_t sem_sync; 103 104void *threaded(void *arg) 105{ 106 int ret = 0; 107 108 if (arg != NULL) { 109 ret = pthread_detach(pthread_self()); 110 if (ret != 0) { 111 UNRESOLVED(ret, "Failed to detach the thread"); 112 } 113 } 114 /* Wait for this semaphore which indicates that pthread_detach has been called */ 115 do { 116 ret = sem_wait(&sem_sync); 117 } 118 while ((ret == -1) && (errno == EINTR)); 119 if (ret == -1) { 120 UNRESOLVED(errno, "Failed to wait for the semaphore"); 121 } 122 123 /* Post the semaphore to indicate the main thread we're alive */ 124 do { 125 ret = sem_post(&(scenarii[sc].sem)); 126 } 127 while ((ret == -1) && (errno == EINTR)); 128 if (ret == -1) { 129 UNRESOLVED(errno, "Failed to post the semaphore"); 130 } 131 132 return arg; 133} 134 135int main(void) 136{ 137 int ret = 0; 138 pthread_t child; 139 struct timespec ts; 140 141 output_init(); 142 143 scenar_init(); 144 145 ret = sem_init(&sem_sync, 0, 0); 146 if (ret != 0) { 147 UNRESOLVED(ret, "Failed to initialize a semaphore"); 148 } 149 150 for (sc = 0; sc < NSCENAR; sc++) { 151#if VERBOSE > 0 152 output("-----\n"); 153 output("Starting test with scenario (%i): %s\n", sc, 154 scenarii[sc].descr); 155#endif 156 157 if (scenarii[sc].detached != 0) { /* only joinable threads can be detached */ 158 ret = 159 pthread_attr_setdetachstate(&scenarii[sc].ta, 160 PTHREAD_CREATE_JOINABLE); 161 if (ret != 0) { 162 UNRESOLVED(ret, 163 "Unable to set detachstate back to joinable"); 164 } 165 } 166 167 /* for detached scenarii, we will call pthread_detach from inside the thread. 168 for joinable scenarii, we'll call pthread_detach from this thread. */ 169 170 ret = 171 pthread_create(&child, &scenarii[sc].ta, threaded, 172 (scenarii[sc].detached != 0) ? &ret : NULL); 173 switch (scenarii[sc].result) { 174 case 0: /* Operation was expected to succeed */ 175 if (ret != 0) { 176 UNRESOLVED(ret, "Failed to create this thread"); 177 } 178 break; 179 180 case 1: /* Operation was expected to fail */ 181 if (ret == 0) { 182 UNRESOLVED(-1, 183 "An error was expected but the thread creation succeeded"); 184 } 185#if VERBOSE > 0 186 break; 187 188 case 2: /* We did not know the expected result */ 189 default: 190 if (ret == 0) { 191 output 192 ("Thread has been created successfully for this scenario\n"); 193 } else { 194 output 195 ("Thread creation failed with the error: %s\n", 196 strerror(ret)); 197 } 198#endif 199 } 200 if (ret == 0) { /* The new thread is running */ 201 /* If we must detach from here, we do it now. */ 202 if (scenarii[sc].detached == 0) { 203 ret = pthread_detach(child); 204 if (ret != 0) { 205 UNRESOLVED(ret, 206 "Failed to detach the child thread."); 207 } 208 } 209 210 /* Now, allow the thread to terminate */ 211 do { 212 ret = sem_post(&sem_sync); 213 } 214 while ((ret == -1) && (errno == EINTR)); 215 if (ret == -1) { 216 UNRESOLVED(errno, 217 "Failed to post the semaphore"); 218 } 219 220 /* Just wait for the thread to terminate */ 221 ret = clock_gettime(CLOCK_REALTIME, &ts); 222 if (ret != 0) { 223 UNRESOLVED(ret, "Failed to get time"); 224 } 225 226 ts.tv_sec += TIMEOUT; 227 228 do { 229 ret = sem_timedwait(&(scenarii[sc].sem), &ts); 230 } 231 while ((ret == -1) && (errno == EINTR)); 232 if (ret == -1) { 233 if (errno == ETIMEDOUT) { 234 FAILED 235 ("pthread_detach made the thread terminate"); 236 } 237 /* else */ 238 UNRESOLVED(errno, 239 "Failed to wait for the semaphore"); 240 } 241 242 /* Let the thread an additionnal row to cleanup */ 243 sched_yield(); 244 } 245 } 246 247 ret = sem_destroy(&sem_sync); 248 if (ret != 0) { 249 UNRESOLVED(ret, "Failed to destroy the semaphore"); 250 } 251 252 scenar_fini(); 253#if VERBOSE > 0 254 output("-----\n"); 255 output("All test data destroyed\n"); 256 output("Test PASSED\n"); 257#endif 258 259 PASSED; 260} 261