1/* 2* Copyright (c) 2005, 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* If there is not enough memory to store handler adresses, 21* the function returns ENOMEM. 22 23* The steps are: 24* -> Register up to 10000 handlers. 25* -> In case of failure, check the error code is ENOMEM. 26* -> Otherwise, check the handlers are all executed.. 27 28*/ 29 30 31/* We are testing conformance to IEEE Std 1003.1, 2003 Edition */ 32#define _POSIX_C_SOURCE 200112L 33 34/******************************************************************************/ 35/*************************** standard includes ********************************/ 36/******************************************************************************/ 37#include <pthread.h> 38#include <stdarg.h> 39#include <stdio.h> 40#include <stdlib.h> 41#include <string.h> 42#include <unistd.h> 43 44#include <sys/wait.h> 45#include <errno.h> 46 47 48/******************************************************************************/ 49/*************************** Test framework *******************************/ 50/******************************************************************************/ 51#include "testfrmw.h" 52#include "testfrmw.c" 53/* This header is responsible for defining the following macros: 54 * UNRESOLVED(ret, descr); 55 * where descr is a description of the error and ret is an int 56 * (error code for example) 57 * FAILED(descr); 58 * where descr is a short text saying why the test has failed. 59 * PASSED(); 60 * No parameter. 61 * 62 * Both three macros shall terminate the calling process. 63 * The testcase shall not terminate in any other maneer. 64 * 65 * The other file defines the functions 66 * void output_init() 67 * void output(char * string, ...) 68 * 69 * Those may be used to output information. 70 */ 71 72/******************************************************************************/ 73/**************************** Configuration ***********************************/ 74/******************************************************************************/ 75#ifndef VERBOSE 76#define VERBOSE 1 77#endif 78 79/******************************************************************************/ 80/*************************** Test case ***********************************/ 81/******************************************************************************/ 82 83pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; 84 85int controls[ 3 ] = {0, 0, 0}; 86/* pthread_atfork handlers */ 87void prepare( void ) 88{ 89 controls[ 0 ] ++; 90} 91 92void parent( void ) 93{ 94 controls[ 1 ] ++; 95} 96 97void child( void ) 98{ 99 controls[ 2 ] ++; 100} 101 102 103/* Thread function */ 104void * threaded( void * arg ) 105{ 106 int ret, status; 107 pid_t child, ctl; 108 109 /* Wait main thread has registered the handler */ 110 ret = pthread_mutex_lock( &mtx ); 111 112 if ( ret != 0 ) 113 { 114 UNRESOLVED( ret, "Failed to lock mutex" ); 115 } 116 117 ret = pthread_mutex_unlock( &mtx ); 118 119 if ( ret != 0 ) 120 { 121 UNRESOLVED( ret, "Failed to unlock mutex" ); 122 } 123 124 /* fork */ 125 child = fork(); 126 127 if ( child == ( pid_t ) - 1 ) 128 { 129 UNRESOLVED( errno, "Failed to fork" ); 130 } 131 132 /* child */ 133 if ( child == ( pid_t ) 0 ) 134 { 135 if ( controls[ 0 ] != 10000 ) 136 { 137 FAILED( "prepare handler skipped some rounds" ); 138 } 139 140 if ( controls[ 2 ] != 10000 ) 141 { 142 FAILED( "child handler skipped some rounds" ); 143 } 144 145 /* We're done */ 146 exit( PTS_PASS ); 147 } 148 149 if ( controls[ 0 ] != 10000 ) 150 { 151 FAILED( "prepare handler skipped some rounds" ); 152 } 153 154 if ( controls[ 1 ] != 10000 ) 155 { 156 FAILED( "parent handler skipped some rounds" ); 157 } 158 159 /* Parent joins the child */ 160 ctl = waitpid( child, &status, 0 ); 161 162 if ( ctl != child ) 163 { 164 UNRESOLVED( errno, "Waitpid returned the wrong PID" ); 165 } 166 167 if ( ( !WIFEXITED( status ) ) || ( WEXITSTATUS( status ) != PTS_PASS ) ) 168 { 169 FAILED( "Child exited abnormally" ); 170 } 171 172 173 /* quit */ 174 return NULL; 175} 176 177/* The main test function. */ 178int main( int argc, char * argv[] ) 179{ 180 int ret, i; 181 pthread_t ch; 182 183 /* Initialize output */ 184 output_init(); 185 186 ret = pthread_mutex_lock( &mtx ); 187 188 if ( ret != 0 ) 189 { 190 UNRESOLVED( ret, "Failed to lock mutex" ); 191 } 192 193 ret = pthread_create( &ch, NULL, threaded, NULL ); 194 195 if ( ret != 0 ) 196 { 197 UNRESOLVED( ret, "Failed to create a thread" ); 198 } 199 200 /* Register the handlers */ 201 for ( i = 0; i < 10000; i++ ) 202 { 203 ret = pthread_atfork( prepare, parent, child ); 204 205 if ( ret == ENOMEM ) 206 { 207 output( "ENOMEM returned after %i iterations\n", i ); 208 break; 209 } 210 211 if ( ret != 0 ) 212 { 213 UNRESOLVED( ret, "Failed to register the atfork handlers" ); 214 } 215 } 216 217 if ( ret == 0 ) 218 { 219 220 /* Let the child go on */ 221 ret = pthread_mutex_unlock( &mtx ); 222 223 if ( ret != 0 ) 224 { 225 UNRESOLVED( ret, "Failed to unlock mutex" ); 226 } 227 228 ret = pthread_join( ch, NULL ); 229 230 if ( ret != 0 ) 231 { 232 UNRESOLVED( ret, "Failed to join the thread" ); 233 } 234 } 235 236 /* Test passed */ 237#if VERBOSE > 0 238 239 output( "Test passed\n" ); 240 241#endif 242 243 PASSED; 244} 245 246 247