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 * Once the thread has been created, subsequent changes to the 21 * thread attribute object don't affect the running thread. 22 23 * The steps are: 24 * -> stack grow 25 * -> create a thread with minimal stack size 26 * -> change the stack size to a bigger value 27 * -> check that the thread stack size did not change. 28 * -> stack decrease 29 * -> create a thread with a known stack size (> minimum) 30 * -> change the stack size to the min value 31 * -> check that the thread stack size did not change. 32 * -> sched policy/param change 33 * -> create a new thread with a known policy 34 * -> change the policy in the thread attribute and check the thread policy did not change 35 * -> change the schedparam in the thread attribute and check the thread priority did not change 36 * -> change the policy in the running thread and check the thread attribute did not change. 37 * -> change the priority in the running thread and check the thread attribute did not change. 38 39 * The test fails if one of the checking fails 40 41 */ 42 43 44 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */ 45 #define _POSIX_C_SOURCE 200112L 46 47 /* Some routines are part of the XSI Extensions */ 48#ifndef WITHOUT_XOPEN 49 #define _XOPEN_SOURCE 600 50#endif 51/********************************************************************************************/ 52/****************************** standard includes *****************************************/ 53/********************************************************************************************/ 54 #include <pthread.h> 55 #include <stdarg.h> 56 #include <stdio.h> 57 #include <stdlib.h> 58 #include <string.h> 59 #include <unistd.h> 60 61 #include <sched.h> 62 #include <semaphore.h> 63 #include <errno.h> 64 #include <assert.h> 65 #include <sys/wait.h> 66 67 68/********************************************************************************************/ 69/****************************** Test framework *****************************************/ 70/********************************************************************************************/ 71 #include "testfrmw.h" 72 #include "testfrmw.c" 73 /* This header is responsible for defining the following macros: 74 * UNRESOLVED(ret, descr); 75 * where descr is a description of the error and ret is an int (error code for example) 76 * FAILED(descr); 77 * where descr is a short text saying why the test has failed. 78 * PASSED(); 79 * No parameter. 80 * 81 * Both three macros shall terminate the calling process. 82 * The testcase shall not terminate in any other maneer. 83 * 84 * The other file defines the functions 85 * void output_init() 86 * void output(char * string, ...) 87 * 88 * Those may be used to output information. 89 */ 90 91/********************************************************************************************/ 92/********************************** Configuration ******************************************/ 93/********************************************************************************************/ 94#ifndef VERBOSE 95#define VERBOSE 1 96#endif 97 98/********************************************************************************************/ 99/*********************************** Test cases *****************************************/ 100/********************************************************************************************/ 101 102#include "threads_scenarii.c" 103 104/* This file will define the following objects: 105 * scenarii: array of struct __scenario type. 106 * NSCENAR : macro giving the total # of scenarii 107 * scenar_init(): function to call before use the scenarii array. 108 * scenar_fini(): function to call after end of use of the scenarii array. 109 */ 110 111 112/********************************************************************************************/ 113/*********************************** Real Test *****************************************/ 114/********************************************************************************************/ 115 116sem_t semsync[2]; /* These semaphores will only be used in child process! */ 117 118/* The overflow function is used to test the stack overflow */ 119void * overflow(void * arg) 120{ 121 void * current; 122 void * pad[50]; /* We want to consume the stack quickly */ 123 long stacksize = sysconf(_SC_THREAD_STACK_MIN); /* make sure we touch the current stack memory */ 124 125 pad[1]=NULL; /* so compiler stops complaining about unused variables */ 126 int ret = 0; 127 128 if (arg == NULL) 129 { 130 /* first call */ 131 132 /* Synchronize with the parent */ 133 do { ret = sem_wait(&semsync[0]); } 134 while ((ret == -1) && (errno == EINTR)); 135 if (ret == -1) { UNRESOLVED(errno, "Failed to wait for the semaphore"); } 136 137 138 /* Go to recursion */ 139 current = overflow(¤t); 140 141 /* Terminated */ 142 do { ret = sem_post(&semsync[1]); } 143 while ((ret == -1) && (errno == EINTR)); 144 if (ret == -1) { UNRESOLVED(errno, "Failed to post the semaphore"); } 145 146 /* Terminate the overflow thread */ 147 return current; 148 } 149 150 /* we cast the pointers into long, which might be a problem on some architectures... */ 151 if ( ((long)arg) < ((long)¤t)) 152 { 153 /* the stack is growing up */ 154 if ( ((long)¤t) - ((long)arg) >= stacksize) 155 { 156 output("Growing up stack started below %p and we are currently up to %p\n", arg, ¤t); 157 return (void *)0; 158 } 159 } 160 else 161 { 162 /* the stack is growing down */ 163 if ( ((long)arg) - ((long)¤t) >= stacksize) 164 { 165 output("Growing down stack started upon %p and we are currently down to %p\n", arg, ¤t); 166 return (void *)0; 167 } 168 } 169 170 /* We are not yet overflowing, so we loop */ 171 return overflow(arg); 172} 173 174/* The following function will return 175 0 if a thread created with the attribute ta is able to fill the stack up to {minstacksize}. 176 1 if the operation failed. 177 2 if an error prevented the test to complete 178 179 If newsize is not 0, the stack size in ta will be set to this value once the thread is created. 180 181*/ 182int test_stack(pthread_attr_t * ta, size_t newsize) 183{ 184 pid_t child, ctrl; 185 int status; 186 int ret; 187 188 child=fork(); /* We'll test the feature in another process as this test may segfault */ 189 190 if (child == -1) 191 { 192 output("Failed to fork (%s)\n", strerror(errno)); 193 return 2; 194 } 195 196 if (child != 0) /* father */ 197 { 198 /* Just wait for the child and check its return value */ 199 ctrl = waitpid(child, &status, 0); 200 if (ctrl != child) 201 { 202 output("Failed to wait for process termination (%s)\n", strerror(errno)); 203 return 2; 204 } 205 206 if (WIFEXITED(status)) /* The process exited */ 207 { 208 if (WEXITSTATUS(status) == 0) 209 { return 0; } /* We were able to fill the stack */ 210 if (WEXITSTATUS(status) == PTS_UNRESOLVED) 211 { 212 output("The child process returned unresolved status\n"); 213 return 2; 214 } 215 else 216 { 217 output("The child process returned: %i\n", WEXITSTATUS(status)); 218 return 2; 219 } 220 } 221 else 222 { 223 #if VERBOSE > 4 224 output("The child process did not return\n"); 225 if (WIFSIGNALED(status)) 226 output("It was killed with signal %i\n", WTERMSIG(status)); 227 else 228 output("neither was it killed. (status = %i)\n", status); 229 #endif 230 } 231 232 return 1; 233 } 234 235 /* else */ 236 /* this is the new process */ 237 { 238 pthread_t th; 239 void * rc; 240 int detach; 241 242 /* Semaphore to force the child to wait */ 243 ret = sem_init(&semsync[0], 0,0); 244 if (ret == -1) { UNRESOLVED(errno, "Unable to init a semaphore"); } 245 /* Semaphore to detect thread ending */ 246 ret = sem_init(&semsync[1], 0,0); 247 if (ret == -1) { UNRESOLVED(errno, "Unable to init a semaphore"); } 248 249 ret = pthread_create(&th, ta, overflow, NULL); /* Create a new thread with the same attributes */ 250 if (ret != 0) { UNRESOLVED(ret, "Unable to create a thread in the new process"); } 251 252 /* If we were asked to perform a change on ta, do it now. */ 253 if (newsize) 254 { 255 ret = pthread_attr_setstacksize(ta, newsize); 256 if (ret != 0) { UNRESOLVED(ret, "Failed to set the new stack size"); } 257 } 258 259 /* Ok the child can run now */ 260 do { ret = sem_post(&semsync[0]); } 261 while ((ret == -1) && (errno == EINTR)); 262 if (ret == -1) { UNRESOLVED(errno, "Failed to post the semaphore"); } 263 264 265 /* Wait for its termination */ 266 do { ret = sem_wait(&semsync[1]); } 267 while ((ret == -1) && (errno == EINTR)); 268 if (ret == -1) { UNRESOLVED(errno, "Failed to wait for the semaphore"); } 269 270 if (ta != NULL) 271 { 272 ret = pthread_attr_getdetachstate(ta, &detach); 273 if (ret != 0) { UNRESOLVED(ret, "Failed to get detach state from the thread attribute"); } 274 } 275 else 276 { 277 detach = PTHREAD_CREATE_JOINABLE; /* default */ 278 } 279 280 if (detach == PTHREAD_CREATE_JOINABLE) 281 { 282 ret = pthread_join(th, &rc); 283 if (ret != 0) { UNRESOLVED(ret, "Unable to join a thread"); } 284 if (rc != (void *)0) 285 { UNRESOLVED((int)(long)rc, "The overflow function returned an unexpected value"); } 286 } 287 288 289 /* Terminate the child process here */ 290 exit(0); 291 } 292} 293 294 295typedef struct 296{ 297 pthread_barrier_t bar; 298 int policy; 299 struct sched_param param; 300} testdata_t; 301 302void * schedtest(void * arg) 303{ 304 testdata_t * td = (testdata_t *)arg; 305 int newpol, ret=0; 306 struct sched_param newparam; 307 308 /* Read the current sched policy & param */ 309 ret = pthread_getschedparam(pthread_self(), &(td->policy), &(td->param)); 310 if (ret != 0) { UNRESOLVED(ret, "Failed to read current thread policy / param"); } 311 312 /* sync 1 */ 313 ret = pthread_barrier_wait(&(td->bar)); 314 if ((ret != 0) && (ret != PTHREAD_BARRIER_SERIAL_THREAD)) { UNRESOLVED(ret, "Failed to synchronize on the barrier"); } 315 316 /* sync 2 */ 317 ret = pthread_barrier_wait(&(td->bar)); 318 if ((ret != 0) && (ret != PTHREAD_BARRIER_SERIAL_THREAD)) { UNRESOLVED(ret, "Failed to synchronize on the barrier"); } 319 320 /* Read the current sched policy & param */ 321 ret = pthread_getschedparam(pthread_self(), &(td->policy), &(td->param)); 322 if (ret != 0) { UNRESOLVED(ret, "Failed to read current thread policy / param"); } 323 324 /* sync 3 */ 325 ret = pthread_barrier_wait(&(td->bar)); 326 if ((ret != 0) && (ret != PTHREAD_BARRIER_SERIAL_THREAD)) { UNRESOLVED(ret, "Failed to synchronize on the barrier"); } 327 328 /* sync 4 */ 329 ret = pthread_barrier_wait(&(td->bar)); 330 if ((ret != 0) && (ret != PTHREAD_BARRIER_SERIAL_THREAD)) { UNRESOLVED(ret, "Failed to synchronize on the barrier"); } 331 332 /* Change the current sched policy & param */ 333 if (td->policy == SCHED_RR) 334 newpol = SCHED_FIFO; 335 else 336 newpol = SCHED_RR; 337 338 newparam.sched_priority = sched_get_priority_max(newpol); 339 340 if (newparam.sched_priority == td->param.sched_priority) 341 newparam.sched_priority--; 342 343 ret = pthread_setschedparam(pthread_self(), newpol, &newparam); 344 #if VERBOSE > 0 345 if (ret != 0) 346 output("Changing the current thread sched policy failed with error: %s\n", strerror(ret)); 347 #endif 348 #if VERBOSE > 2 349 else 350 output("Executing thread scheduling policy changed\n"); 351 #endif 352 353 /* sync 5 */ 354 ret = pthread_barrier_wait(&(td->bar)); 355 if ((ret != 0) && (ret != PTHREAD_BARRIER_SERIAL_THREAD)) { UNRESOLVED(ret, "Failed to synchronize on the barrier"); } 356 357 /* Post the sem in case of a detached thread */ 358 do { ret = sem_post(&scenarii[sc].sem); } 359 while ((ret == -1) && (errno == EINTR)); 360 if (ret == -1) { UNRESOLVED(errno, "Failed to post the semaphore"); } 361 362 return NULL; 363} 364 365 366 367int main (int argc, char *argv[]) 368{ 369 int ret=0; 370 int do_stack_tests; 371 int do_sched_tests; 372 373 /* Initialize output routine */ 374 output_init(); 375 376 /* Test abilities */ 377 do_sched_tests = (sysconf(_SC_THREAD_PRIORITY_SCHEDULING)>0?1:0); 378 do_stack_tests = (test_stack(NULL,0)==0?1:0); 379 #if VERBOSE > 0 380 output("Test starting\n Stack tests %s be executed.\n Sched tests %s be executed.\n", 381 do_stack_tests?"will":"won't", 382 do_sched_tests?"will":"won't"); 383 #endif 384 385 /* Initialize thread attribute objects */ 386 scenar_init(); 387 388 for (sc=0; sc < NSCENAR; sc++) 389 { 390 #if VERBOSE > 0 391 output("-----\n"); 392 output("Starting test with scenario (%i): %s\n", sc, scenarii[sc].descr); 393 #endif 394 395 if (do_stack_tests) 396 { 397 /* stack grow test */ 398 /* We need the thread attribute to specify a minimal stack */ 399 if ((scenarii[sc].altstack == 0) && (scenarii[sc].altsize == 1)) 400 { 401 #if VERBOSE > 2 402 output("Processing stack grow test\n"); 403 #endif 404 405 ret = test_stack(&scenarii[sc].ta, 2*sysconf(_SC_THREAD_STACK_MIN)); 406 407 if (ret == 0) 408 { 409 if (scenarii[sc].guard == 2) 410 { 411 FAILED("Changing the stacksize after the thread was created changed the running thread stack size"); 412 } 413 #if VERBOSE > 2 414 else 415 output("We were able to overflow the stack, but the guard area is unknow or null\n"); 416 #endif 417 418 } 419 420 if ((ret != 2) && (scenarii[sc].result == 1)) 421 { 422 UNRESOLVED(-1, "An error was expected but the thread creation succeeded"); 423 } 424 425 #if VERBOSE > 2 426 if ((ret == 1)) 427 { 428 output("Stack grow test passed\n"); 429 } 430 431 if ((ret == 2) && (scenarii[sc].result == 2)) 432 { 433 output("Something went wrong -- we don't care in this case\n"); 434 } 435 #endif 436 437 if ((ret == 2) && (scenarii[sc].result == 0)) 438 { 439 UNRESOLVED(-1, "An unexpected error occured\n"); 440 } 441 442 /* Ok, set back the thread attribute object to a correct value */ 443 ret = pthread_attr_setstacksize(&scenarii[sc].ta, sysconf(_SC_THREAD_STACK_MIN)); 444 if (ret != 0) { UNRESOLVED(ret, "Failed to set stacksize back"); } 445 } 446 447 448 /* stack decrease test */ 449 if ((scenarii[sc].altstack == 0) && (scenarii[sc].altsize == 0)) 450 { 451 #if VERBOSE > 2 452 output("Processing stack decrease test\n"); 453 #endif 454 455 ret = test_stack(&scenarii[sc].ta, sysconf(_SC_THREAD_STACK_MIN)); 456 457 if (ret == 1) { FAILED("Decreasing the stack size after thread is created had an influence on the thread"); } 458 459 if ((ret == 0) && (scenarii[sc].result == 1)) 460 { 461 UNRESOLVED(-1, "An error was expected but the thread creation succeeded"); 462 } 463 464 if ((ret == 2) && (scenarii[sc].result == 0)) 465 { 466 UNRESOLVED(-1, "An unexpected error occured\n"); 467 } 468 469 #if VERBOSE > 2 470 if (ret == 0) 471 output("Stack decrease test passed.\n"); 472 else 473 output("Something failed but we don't care here.\n"); 474 #endif 475 } 476 477 478 } /* if do_stack_tests */ 479 480 if (do_sched_tests) 481 { 482 /* Sched policy/param change test */ 483 if (scenarii[sc].explicitsched != 0) /* We need a specified policy */ 484 { 485 pthread_t child; 486 int policy_ori, newpol_max; 487 struct sched_param param_ori, tmp; 488 489 testdata_t td; 490 491 #if VERBOSE > 2 492 output("Processing sched policy/param change test\n"); 493 #endif 494 495 /* Backup the scenario object */ 496 ret = pthread_attr_getschedpolicy(&(scenarii[sc].ta), &policy_ori); 497 if (ret != 0) { UNRESOLVED(ret, "Unable to read sched policy from thread attribute"); } 498 ret = pthread_attr_getschedparam(&(scenarii[sc].ta), ¶m_ori); 499 if (ret != 0) { UNRESOLVED(ret, "Unable to read sched param from thread attribute"); } 500 501 /* Initialize the barrier */ 502 ret = pthread_barrier_init(&(td.bar), NULL, 2); 503 if (ret != 0) { UNRESOLVED(ret, "Unable to initialize the barrier"); } 504 505 /* Create a new thread with this scenario attribute */ 506 ret = pthread_create(&child, &(scenarii[sc].ta), schedtest, &td); 507 if (ret != 0) 508 { 509 if (scenarii[sc].result == 0) 510 { UNRESOLVED(ret , "Failed to create a thread"); } 511 512 #if VERBOSE > 2 513 if (scenarii[sc].result == 2) 514 { 515 output("The thread creation failed -- we don't care\n"); 516 } 517 if (scenarii[sc].result == 1) 518 { 519 output("The thread creation failed as expected\n"); 520 } 521 #endif 522 } 523 else /* Thread created */ 524 { 525 if (scenarii[sc].result == 1) 526 { UNRESOLVED(-1, "The thread was created where an error was expected"); } 527 528 #if VERBOSE > 2 529 if (scenarii[sc].result == 2) 530 output("Thread is created\n"); 531 #endif 532 533 /* sync 1 */ 534 ret = pthread_barrier_wait(&(td.bar)); 535 if ((ret != 0) && (ret != PTHREAD_BARRIER_SERIAL_THREAD)) { UNRESOLVED(ret, "Failed to synchronize on the barrier"); } 536 537 /* Check the new thread reports the attributes */ 538 if (td.policy != policy_ori) 539 { FAILED("The new thread does not report the scheluling policy that was specified"); } 540 541 if (td.param.sched_priority != param_ori.sched_priority) 542 { FAILED("The new thread does not report the scheduling priority that was specified at creation"); } 543 544 /* Change the thread attribute object policy & param */ 545 if (policy_ori == SCHED_RR) 546 { 547 ret = pthread_attr_setschedpolicy(&(scenarii[sc].ta), SCHED_FIFO); 548 newpol_max = sched_get_priority_max(SCHED_FIFO); 549 } 550 else 551 { 552 ret = pthread_attr_setschedpolicy(&(scenarii[sc].ta), SCHED_RR); 553 newpol_max = sched_get_priority_max(SCHED_RR); 554 } 555 if (ret != 0) { UNRESOLVED(ret, "Failed to change the attribute object"); } 556 557 if (newpol_max == param_ori.sched_priority) 558 newpol_max--; 559 560 tmp.sched_priority = newpol_max; 561 562 ret = pthread_attr_setschedparam(&(scenarii[sc].ta), &tmp); 563 if (ret != 0) { UNRESOLVED(ret, "Failed to set the attribute sched param"); } 564 565 /* sync 2 */ 566 ret = pthread_barrier_wait(&(td.bar)); 567 if ((ret != 0) && (ret != PTHREAD_BARRIER_SERIAL_THREAD)) { UNRESOLVED(ret, "Failed to synchronize on the barrier"); } 568 569 /* sync 3 */ 570 ret = pthread_barrier_wait(&(td.bar)); 571 if ((ret != 0) && (ret != PTHREAD_BARRIER_SERIAL_THREAD)) { UNRESOLVED(ret, "Failed to synchronize on the barrier"); } 572 573 /* Check if the thread saw the change (should not) */ 574 if (td.policy != policy_ori) 575 { FAILED("The new thread does not report the scheluling policy that was specified"); } 576 577 if (td.param.sched_priority != param_ori.sched_priority) 578 { FAILED("The new thread does not report the scheduling priority that was specified at creation"); } 579 580 /* Check what we can see for the child thread from here */ 581 ret = pthread_getschedparam(child, &(td.policy), &(td.param)); 582 if (ret != 0) { UNRESOLVED(ret, "Failed to read child thread policy / param"); } 583 584 if (td.policy != policy_ori) 585 { FAILED("The child thread does not report the scheduling policy that was specified at creation"); } 586 587 if (td.param.sched_priority != param_ori.sched_priority) 588 { FAILED("The child thread does not report the scheduling priority that was specified at creation"); } 589 590 /* Restore the thread attribute */ 591 ret = pthread_attr_setschedpolicy(&(scenarii[sc].ta), policy_ori); 592 if (ret != 0) { UNRESOLVED(ret, "Unable to read sched policy from thread attribute"); } 593 ret = pthread_attr_setschedparam(&(scenarii[sc].ta), ¶m_ori); 594 if (ret != 0) { UNRESOLVED(ret, "Unable to read sched param from thread attribute"); } 595 596 /* sync 4*/ 597 ret = pthread_barrier_wait(&(td.bar)); 598 if ((ret != 0) && (ret != PTHREAD_BARRIER_SERIAL_THREAD)) { UNRESOLVED(ret, "Failed to synchronize on the barrier"); } 599 600 /* sync 5*/ 601 ret = pthread_barrier_wait(&(td.bar)); 602 if ((ret != 0) && (ret != PTHREAD_BARRIER_SERIAL_THREAD)) { UNRESOLVED(ret, "Failed to synchronize on the barrier"); } 603 604 /* check if the thread attribute reports a change (should not) */ 605 ret = pthread_attr_getschedpolicy(&(scenarii[sc].ta), &(td.policy)); 606 if (ret != 0) { UNRESOLVED(ret, "Unable to read sched policy from thread attribute"); } 607 ret = pthread_attr_getschedparam(&(scenarii[sc].ta), &(td.param)); 608 if (ret != 0) { UNRESOLVED(ret, "Unable to read sched param from thread attribute"); } 609 610 if (td.policy != policy_ori) 611 { FAILED("The child thread does not report the scheduling policy that was specified at creation"); } 612 613 if (td.param.sched_priority != param_ori.sched_priority) 614 { FAILED("The child thread does not report the scheduling priority that was specified at creation"); } 615 616 /* Wait for the sem and join eventually the thread */ 617 do { ret = sem_wait(&scenarii[sc].sem); } 618 while ((ret == -1) && (errno == EINTR)); 619 if (ret == -1) { UNRESOLVED(errno, "Failed to wait for the semaphore"); } 620 621 if (scenarii[sc].detached == 0) 622 { 623 ret = pthread_join(child, NULL); 624 if (ret != 0) { UNRESOLVED(ret, "Unable to join a thread"); } 625 } 626 627 #if VERBOSE > 2 628 output("Sched policy/param change test passed\n"); 629 #endif 630 } /* thread created */ 631 } 632 633 /* We could also test if the inheritsched does not influence the new thread */ 634 635 } /* if do_sched_tests */ 636 } 637 638 scenar_fini(); 639 #if VERBOSE > 0 640 output("-----\n"); 641 output("All test data destroyed\n"); 642 output("Test PASSED\n"); 643 #endif 644 645 PASSED; 646} 647 648 649 650