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 * pthread_create creates a thread with attributes as specified in the attr parameter. 21 22 * The steps are: 23 * 24 * -> Create a new thread with known parameters. 25 * -> Check the thread behavior conforms to these parameters. 26 * This checking consists in: 27 * -> If an alternative stack has been specified, check that the new thread stack is within this specified area. 28 * -> If stack size and guard size are known, check that accessing the guard size fails. (new process) 29 * -> If we are able to run threads with high priority and known sched policy, check that a high priority thread executes before a low priority thread. 30 (This will be done in another test has it fails with Linux kernel (2.6.8 at least) 31 * -> The previous test could be extended to cross-process threads to check the scope attribute behavior (postponned for now). 32 * (*) The detachstate attribute is not tested cause this would mean a speculative test. Moreover, it is already tested elsewhere. 33 34 * The test fails if one of those tests fails. 35 36 */ 37 38 39 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */ 40 #define _POSIX_C_SOURCE 200112L 41 42 /* Some routines are part of the XSI Extensions */ 43#ifndef WITHOUT_XOPEN 44 #define _XOPEN_SOURCE 600 45#endif 46/********************************************************************************************/ 47/****************************** standard includes *****************************************/ 48/********************************************************************************************/ 49 #include <pthread.h> 50 #include <stdarg.h> 51 #include <stdio.h> 52 #include <stdlib.h> 53 #include <string.h> 54 #include <unistd.h> 55 56 #include <sched.h> 57 #include <semaphore.h> 58 #include <errno.h> 59 #include <assert.h> 60 #include <sys/wait.h> 61/********************************************************************************************/ 62/****************************** Test framework *****************************************/ 63/********************************************************************************************/ 64 #include "testfrmw.h" 65 #include "testfrmw.c" 66 /* This header is responsible for defining the following macros: 67 * UNRESOLVED(ret, descr); 68 * where descr is a description of the error and ret is an int (error code for example) 69 * FAILED(descr); 70 * where descr is a short text saying why the test has failed. 71 * PASSED(); 72 * No parameter. 73 * 74 * Both three macros shall terminate the calling process. 75 * The testcase shall not terminate in any other maneer. 76 * 77 * The other file defines the functions 78 * void output_init() 79 * void output(char * string, ...) 80 * 81 * Those may be used to output information. 82 */ 83 84/********************************************************************************************/ 85/********************************** Configuration ******************************************/ 86/********************************************************************************************/ 87#ifndef VERBOSE 88#define VERBOSE 1 89#endif 90 91/********************************************************************************************/ 92/*********************************** Test cases *****************************************/ 93/********************************************************************************************/ 94#define STD_MAIN /* This allows main() to be defined in the included file */ 95#include "threads_scenarii.c" 96 97/* This file will define the following objects: 98 * scenarii: array of struct __scenario type. 99 * NSCENAR : macro giving the total # of scenarii 100 * scenar_init(): function to call before use the scenarii array. 101 * scenar_fini(): function to call after end of use of the scenarii array. 102 */ 103 104/********************************************************************************************/ 105/*********************************** Real Test *****************************************/ 106/********************************************************************************************/ 107 108/* The overflow function is used to test the stack overflow */ 109void * overflow(void * arg) 110{ 111 void * current; 112 void * pad[50]; /* We want to consume the stack quickly */ 113 long stacksize = sysconf(_SC_THREAD_STACK_MIN); /* make sure we touch the current stack memory */ 114 int ret=0; 115 116 pad[1]=NULL; /* so compiler stops complaining about unused variables */ 117 118 if (arg == NULL) 119 { 120 /* first call */ 121 current = overflow(¤t); 122 123 /* Terminate the overflow thread */ 124 /* Post the semaphore to unlock the main thread in case of a detached thread */ 125 do { ret = sem_post(&scenarii[sc].sem); } 126 while ((ret == -1) && (errno == EINTR)); 127 if (ret == -1) { UNRESOLVED(errno, "Failed to post the semaphore"); } 128 return NULL; 129 } 130 131 132 /* we cast the pointers into long, which might be a problem on some architectures... */ 133 if ( ((long)arg) < ((long)¤t)) 134 { 135 /* the stack is growing up */ 136 if ( ((long)¤t) - ((long)arg) >= stacksize) 137 { 138 output("Growing up stack started below %p and we are currently up to %p\n", arg, ¤t); 139 return (void *)0; 140 } 141 } 142 else 143 { 144 /* the stack is growing down */ 145 if ( ((long)arg) - ((long)¤t) >= stacksize) 146 { 147 output("Growing down stack started upon %p and we are currently down to %p\n", arg, ¤t); 148 return (void *)0; 149 } 150 } 151 152 /* We are not yet overflowing, so we loop */ 153 { 154 return overflow(arg); 155 } 156} 157 158 159void * threaded (void * arg) 160{ 161 int ret = 0; 162 163 #if VERBOSE > 4 164 output("Thread %i starting...\n", sc); 165 #endif 166 167 /* Alternate stack test */ 168 if (scenarii[sc].bottom != NULL) 169 { 170 #ifdef WITHOUT_XOPEN 171 output("Unable to test the alternate stack feature; need an integer pointer cast\n"); 172 #else 173 intptr_t stack_start, stack_end, current_pos; 174 175 stack_start = (intptr_t) scenarii[sc].bottom; 176 stack_end = stack_start + (intptr_t)sysconf(_SC_THREAD_STACK_MIN); 177 current_pos = (intptr_t)&ret; 178 179 #if VERBOSE > 2 180 output("Stack bottom: %p\n", scenarii[sc].bottom); 181 output("Stack end : %p (stack is 0x%lx bytes)\n", (void *)stack_end, stack_end - stack_start); 182 output("Current pos : %p\n", &ret); 183 #endif 184 if ((stack_start > current_pos) || (current_pos > stack_end)) 185 { FAILED("The specified stack was not used.\n"); } 186 187 #endif // WITHOUT_XOPEN 188 } 189 190 191 /* Guard size test */ 192 if ((scenarii[sc].bottom == NULL) /* no alternative stack was specified */ 193 && (scenarii[sc].guard == 2) /* guard area size is 1 memory page */ 194 && (scenarii[sc].altsize == 1))/* We know the stack size */ 195 { 196 pid_t child, ctrl; 197 int status; 198 199 child=fork(); /* We'll test the feature in another process as this test may segfault */ 200 201 if (child == -1) { UNRESOLVED(errno, "Failed to fork()"); } 202 203 if (child != 0) /* father */ 204 { 205 /* Just wait for the child and check its return value */ 206 ctrl = waitpid(child, &status, 0); 207 if (ctrl != child) { UNRESOLVED(errno, "Failed to wait for process termination"); } 208 209 if (WIFEXITED(status)) /* The process exited */ 210 { 211 if (WEXITSTATUS(status) == 0) 212 { FAILED("Overflow into the guard area did not fail"); } 213 if (WEXITSTATUS(status) == PTS_UNRESOLVED) 214 { UNRESOLVED(-1, "The child process returned unresolved status"); } 215 #if VERBOSE > 4 216 else 217 { output("The child process returned: %i\n", WEXITSTATUS(status)); } 218 } 219 else 220 { 221 output("The child process did not returned\n"); 222 if (WIFSIGNALED(status)) 223 output("It was killed with signal %i\n", WTERMSIG(status)); 224 else 225 output("neither was it killed. (status = %i)\n", status); 226 #endif 227 } 228 } 229 230 if (child == 0) /* this is the new process */ 231 { 232 pthread_t th; 233 234 ret = pthread_create(&th, &scenarii[sc].ta, overflow, NULL); /* Create a new thread with the same attributes */ 235 if (ret != 0) { UNRESOLVED(ret, "Unable to create another thread with the same attributes in the new process"); } 236 237 if (scenarii[sc].detached == 0) 238 { 239 ret = pthread_join(th, NULL); 240 if (ret != 0) { UNRESOLVED(ret, "Unable to join a thread"); } 241 } 242 else 243 { 244 /* Just wait for the thread to terminate */ 245 do { ret = sem_wait(&scenarii[sc].sem); } 246 while ((ret == -1) && (errno == EINTR)); 247 if (ret == -1) { UNRESOLVED(errno, "Failed to wait for the semaphore"); } 248 } 249 250 /* Terminate the child process here */ 251 exit(0); 252 } 253 } 254 255 256 /* Post the semaphore to unlock the main thread in case of a detached thread */ 257 do { ret = sem_post(&scenarii[sc].sem); } 258 while ((ret == -1) && (errno == EINTR)); 259 if (ret == -1) { UNRESOLVED(errno, "Failed to post the semaphore"); } 260 261 return arg; 262} 263 264