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 * -> See test 1-5.c for details 25 * -> This one will test the scheduling behavior is correct. 26 27 */ 28 29 30 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */ 31 #define _POSIX_C_SOURCE 200112L 32 33 /* Some routines are part of the XSI Extensions */ 34#ifndef WITHOUT_XOPEN 35 #define _XOPEN_SOURCE 600 36#endif 37/********************************************************************************************/ 38/****************************** standard includes *****************************************/ 39/********************************************************************************************/ 40 #include <pthread.h> 41 #include <stdarg.h> 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <unistd.h> 46 47 #include <sched.h> 48 #include <semaphore.h> 49 #include <errno.h> 50 #include <assert.h> 51 #include <sys/wait.h> 52/********************************************************************************************/ 53/****************************** Test framework *****************************************/ 54/********************************************************************************************/ 55 #include "testfrmw.h" 56 #include "testfrmw.c" 57 /* This header is responsible for defining the following macros: 58 * UNRESOLVED(ret, descr); 59 * where descr is a description of the error and ret is an int (error code for example) 60 * FAILED(descr); 61 * where descr is a short text saying why the test has failed. 62 * PASSED(); 63 * No parameter. 64 * 65 * Both three macros shall terminate the calling process. 66 * The testcase shall not terminate in any other maneer. 67 * 68 * The other file defines the functions 69 * void output_init() 70 * void output(char * string, ...) 71 * 72 * Those may be used to output information. 73 */ 74 75/********************************************************************************************/ 76/********************************** Configuration ******************************************/ 77/********************************************************************************************/ 78#ifndef VERBOSE 79#define VERBOSE 1 80#endif 81 82/* The value below shall be >= to the # of CPU on the test architecture */ 83#define NCPU (4) 84 85/********************************************************************************************/ 86/*********************************** Test cases *****************************************/ 87/********************************************************************************************/ 88#define STD_MAIN /* This allows main() to be defined in the included file */ 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 103 104/* The 2 following functions are used for the scheduling tests */ 105void * lp_func(void * arg) 106{ 107 int * ctrl = (int *) arg; 108 *ctrl=2; 109 return NULL; 110} 111 112void * hp_func(void * arg) 113{ 114 int *ctrl = (int *) arg; 115 int dummy=0, i; 116 do 117 { 118 /* some dummy task */ 119 dummy += 3; 120 dummy %= 17; 121 dummy *= 47; 122 for (i=0; i<1000000000; i++); 123 #if VERBOSE > 6 124 output("%p\n", pthread_self()); 125 #endif 126 } 127 while (*ctrl == 0); 128 return NULL; 129} 130 131 132void * threaded (void * arg) 133{ 134 int ret = 0; 135 136 #if VERBOSE > 4 137 output("Thread %i starting...\n", sc); 138 #endif 139 140 /* Scheduling (priority) tests */ 141 if ((sysconf(_SC_THREAD_PRIORITY_SCHEDULING) > 0) 142 && (scenarii[sc].explicitsched != 0) 143 && (scenarii[sc].schedpolicy != 0) 144 && (scenarii[sc].schedparam == 1)) 145 { 146 /* We will create NCPU threads running with a high priority with the same sched policy policy 147 and one with a low-priority. 148 The low-priority thread should not run until the other threads stop running, 149 unless the machine has more than NCPU processors... */ 150 151 pthread_t hpth[NCPU]; /* High priority threads */ 152 pthread_t lpth; /* Low Priority thread */ 153 int ctrl; /* Check value */ 154 pthread_attr_t ta; 155 struct sched_param sp; 156 int policy; 157 int i=0; 158 struct timespec now, timeout; 159 160 /* Start with checking we are executing with the required parameters */ 161 ret = pthread_getschedparam(pthread_self(), &policy, &sp); 162 if (ret != 0) { UNRESOLVED(ret , "Failed to get current thread policy"); } 163 164 if (((scenarii[sc].schedpolicy == 1) && (policy != SCHED_FIFO)) 165 || ((scenarii[sc].schedpolicy == 2) && (policy != SCHED_RR))) 166 { 167 FAILED("The thread is not using the scheduling policy that was required"); 168 } 169 if (((scenarii[sc].schedparam == 1) && (sp.sched_priority != sched_get_priority_max(policy))) 170 || ((scenarii[sc].schedparam ==-1) && (sp.sched_priority != sched_get_priority_min(policy)))) 171 { 172 173 FAILED("The thread is not using the scheduling parameter that was required"); 174 } 175 176 ctrl = 0; /* Initial state */ 177 178 /* Get the policy information */ 179 ret = pthread_attr_getschedpolicy(&scenarii[sc].ta, &policy); 180 if (ret != 0) { UNRESOLVED(ret, "Failed to read sched policy"); } 181 182 /* We put a timeout cause the test might lock the machine when it runs */ 183 alarm(60); 184 185 /* Create the high priority threads */ 186 ret = pthread_attr_init(&ta); 187 if (ret != 0) { UNRESOLVED(ret, "Failed to initialize a thread attribute object"); } 188 189 ret = pthread_attr_setinheritsched(&ta, PTHREAD_EXPLICIT_SCHED); 190 if (ret != 0) { UNRESOLVED(ret, "Unable to set inheritsched attribute"); } 191 192 ret = pthread_attr_setschedpolicy(&ta, policy); 193 if (ret != 0) { UNRESOLVED(ret, "Unable to set the sched policy"); } 194 195 sp.sched_priority = sched_get_priority_max(policy) - 1; 196 197 ret = pthread_attr_setschedparam(&ta, &sp); 198 if (ret != 0) { UNRESOLVED(ret, "Failed to set the sched param"); } 199 200 #if VERBOSE > 1 201 output("Starting %i high- and 1 low-priority threads.\n", NCPU); 202 #endif 203 for (i=0; i<NCPU; i++) 204 { 205 ret = pthread_create(&hpth[i], &ta, hp_func, &ctrl); 206 if (ret != 0) { UNRESOLVED(ret, "Failed to create enough threads"); } 207 } 208 #if VERBOSE > 5 209 output("The %i high-priority threads are running\n", NCPU); 210 #endif 211 212 /* Create the low-priority thread */ 213 sp.sched_priority = sched_get_priority_min(policy); 214 215 ret = pthread_attr_setschedparam(&ta, &sp); 216 if (ret != 0) { UNRESOLVED(ret, "Failed to set the sched param"); } 217 218 ret = pthread_create(&lpth, &ta, lp_func, &ctrl); 219 if (ret != 0) { UNRESOLVED(ret, "Failed to create enough threads"); } 220 221 /* Keep going */ 222 ret = clock_gettime(CLOCK_REALTIME, &now); 223 if (ret != 0) { UNRESOLVED(errno, "Failed to read current time"); } 224 225 timeout.tv_sec = now.tv_sec; 226 timeout.tv_nsec = now.tv_nsec + 500000000; 227 while (timeout.tv_nsec >= 1000000000) 228 { 229 timeout.tv_sec++; 230 timeout.tv_nsec -= 1000000000; 231 } 232 233 do 234 { 235 if (ctrl != 0) 236 { 237 output("The low priority thread executed. This might be normal if you have more than %i CPU.\n", NCPU + 1); 238 FAILED("Low priority thread executed -- the sched parameters are ignored?"); 239 } 240 ret = clock_gettime(CLOCK_REALTIME, &now); 241 if (ret != 0) { UNRESOLVED(errno, "Failed to read current time"); } 242 #if VERBOSE > 5 243 output("Time: %d.%09d (to: %d.%09d)\n", now.tv_sec, now.tv_nsec, timeout.tv_sec, timeout.tv_nsec); 244 #endif 245 } 246 while ((now.tv_sec <= timeout.tv_sec) && (now.tv_nsec <= timeout.tv_nsec)); 247 248 /* Ok the low priority thread did not execute :) */ 249 250 /* tell the other high priority to terminate */ 251 ctrl = 1; 252 253 for (i=0; i<NCPU; i++) 254 { 255 ret = pthread_join(hpth[i], NULL); 256 if (ret != 0) { UNRESOLVED(ret, "Failed to join a thread"); } 257 } 258 259 /* Ok so now the low priority should execute when we stop this one (or earlier). */ 260 ret = pthread_join(lpth, NULL); 261 if (ret != 0) { UNRESOLVED(ret, "Failed to join the low priority thread"); } 262 263 /* We just check that it executed */ 264 if (ctrl != 2) { FAILED("Joined the low-priority thread but it did not execute."); } 265 266 #if VERBOSE > 1 267 output("The scheduling parameter was set accordingly to the thread attribute.\n"); 268 #endif 269 270 /* We're done. */ 271 ret = pthread_attr_destroy(&ta); 272 if (ret != 0) { UNRESOLVED(ret, "Failed to destroy a thread attribute object"); } 273 } 274 275 /* Post the semaphore to unlock the main thread in case of a detached thread */ 276 do { ret = sem_post(&scenarii[sc].sem); } 277 while ((ret == -1) && (errno == EINTR)); 278 if (ret == -1) { UNRESOLVED(errno, "Failed to post the semaphore"); } 279 280 return arg; 281} 282 283