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 19 * This sample test aims to check the following assertion: 20 * The function fails and returns ENOMEM if there is not enough memory. 21 22 23 24 * The steps are: 25 * * Fork 26 * * New process sets its memory resource limit to a minimum value, then 27 * -> Allocate all the available memory 28 * -> call pthread_cond_init() 29 * -> free the memory 30 * -> Checks that pthread_cond_init() returned 0 or ENOMEM. 31 * * Parent process waits for the child. 32 */ 33 34 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */ 35 #define _POSIX_C_SOURCE 200112L 36 37 /* We need the setrlimit() function from X/OPEN standard */ 38 #ifndef WITHOUT_XOPEN 39 #define _XOPEN_SOURCE 600 40 41/********************************************************************************************/ 42/****************************** standard includes *****************************************/ 43/********************************************************************************************/ 44 #include <pthread.h> 45 #include <stdio.h> 46 #include <unistd.h> 47 #include <stdlib.h> 48 #include <errno.h> 49 #include <signal.h> 50 #include <sys/wait.h> 51 #include <sys/resource.h> 52 #include <stdarg.h> 53 54/********************************************************************************************/ 55/****************************** Test framework *****************************************/ 56/********************************************************************************************/ 57 #include "testfrmw.h" 58 #include "testfrmw.c" 59 /* This header is responsible for defining the following macros: 60 * UNRESOLVED(ret, descr); 61 * where descr is a description of the error and ret is an int (error code for example) 62 * FAILED(descr); 63 * where descr is a short text saying why the test has failed. 64 * PASSED(); 65 * No parameter. 66 * 67 * Both three macros shall terminate the calling process. 68 * The testcase shall not terminate in any other maneer. 69 * 70 * The other file defines the functions 71 * void output_init() 72 * void output(char * string, ...) 73 * 74 * Those may be used to output information. 75 */ 76 77/********************************************************************************************/ 78/********************************** Configuration ******************************************/ 79/********************************************************************************************/ 80#ifndef VERBOSE 81#define VERBOSE 1 82#endif 83 84/********************************************************************************************/ 85/*********************************** Test case *****************************************/ 86/********************************************************************************************/ 87 88int main(int argc, char * argv[]) 89{ 90 pid_t child; 91 92 93 pthread_cond_t cnd; 94 pthread_condattr_t ca[4]; 95 pthread_condattr_t *pca[5]; 96 97 int ret=0; 98 int i; 99 int retini[5] = {-1,-1,-1,-1,-1}; 100 int retdtr[5]= {-1,-1,-1,-1,-1}; 101 102 void * ptr, *ptr_prev=NULL; 103 104 int sz = 0; 105 struct rlimit rl; 106 107 int status=0; 108 109 110 output_init(); 111 112 child = fork(); 113 114 if (child == (pid_t)-1) 115 { UNRESOLVED(errno, "Fork failed"); } 116 117 if (child != 0) /* We are the father */ 118 { 119 if (child != waitpid(child, &status, 0)) 120 { UNRESOLVED(errno, "Waitpid failed"); } 121 122 if (WIFSIGNALED(status)) 123 { UNRESOLVED(WTERMSIG(status), 124 "The child process was killed."); } 125 126 if (WIFEXITED(status)) 127 return WEXITSTATUS(status); 128 129 UNRESOLVED(0, "Child process neither returned nor was killed."); 130 } 131 132 /* Only the child goes further */ 133 134 /* We initialize the different cond attributes */ 135 for (i=0; (i<4) && (ret == 0); i++) 136 { 137 pca[i] = &ca[i]; 138 ret = pthread_condattr_init(pca[i]); 139 } 140 if (ret) 141 { UNRESOLVED(ret, "Cond attribute init failed"); } 142 pca[4] = (pthread_condattr_t *) NULL; 143 144 ret = pthread_condattr_setpshared(pca[0], PTHREAD_PROCESS_SHARED); 145 if (ret != 0) { UNRESOLVED(ret, "Cond attribute PSHARED failed"); } 146 ret = pthread_condattr_setpshared(pca[1], PTHREAD_PROCESS_SHARED); 147 if (ret != 0) { UNRESOLVED(ret, "Cond attribute PSHARED failed"); } 148 149 if (sysconf(_SC_MONOTONIC_CLOCK) > 0) 150 { 151 ret = pthread_condattr_setclock(pca[1], CLOCK_MONOTONIC); 152 if (ret != 0) { UNRESOLVED(ret, "Cond set monotonic clock failed"); } 153 ret = pthread_condattr_setclock(pca[2], CLOCK_MONOTONIC); 154 if (ret != 0) { UNRESOLVED(ret, "Cond set monotonic clock failed"); } 155 } 156 157 sz = sysconf(_SC_PAGESIZE); 158 159 160 /* Limit the process memory to a small value (64Mb for example). */ 161 rl.rlim_max=1024*1024*64; 162 rl.rlim_cur=1024*1024*64; 163 if ((ret = setrlimit(RLIMIT_AS, &rl))) 164 { UNRESOLVED(ret, "Memory limitation failed"); } 165 166 167 #if VERBOSE > 1 168 output("Ready to take over memory. Page size is %d\n", sz); 169 #endif 170 171 /* Allocate all available memory */ 172 while (1) 173 { 174 ptr = malloc( sz ); /* Allocate one page of memory */ 175 if (ptr == NULL) 176 break; 177 #if VERBOSE > 1 178 ret++; 179 #endif 180 *(void **)ptr = ptr_prev; /* Write into the allocated page */ 181 ptr_prev = ptr; 182 } 183 #if VERBOSE > 1 184 output("%d pages were allocated before failure\n", ret); 185 ret = 0; 186 #endif 187 188 while (1) 189 { 190 ptr = malloc( sizeof(void*) ); /* Allocate every remaining bits of memory */ 191 if (ptr == NULL) 192 break; 193 #if VERBOSE > 1 194 ret++; 195 #endif 196 *(void **)ptr = ptr_prev; /* Keep track of allocated memory */ 197 ptr_prev = ptr; 198 } 199 #if VERBOSE > 1 200 output("%d additional spaces were allocated before failure\n", ret); 201 ret = 0; 202 #endif 203 if (errno != ENOMEM) 204 UNRESOLVED(errno, "Memory not full"); 205 206 /* Now that memory is full, we try to initialize a cond */ 207 for (i=0; i<5; i++) 208 { 209 retini[i] = pthread_cond_init(&cnd, pca[i]); 210 if (!retini[i]) /* If cond has been initialized, we destroy it */ 211 retdtr[i] = pthread_cond_destroy(&cnd); 212 } 213 214 /* We can now free the memory */ 215 while (ptr_prev != NULL) 216 { 217 ptr = ptr_prev; 218 ptr_prev = *(void **)ptr; 219 free(ptr); 220 } 221 222 #if VERBOSE > 1 223 output("Memory is released\n"); 224 #endif 225 226 for (i=0; i<4; i++) 227 pthread_condattr_destroy(pca[i]); 228 229 230 for (i=0; i<5; i++) 231 { 232 if (retini[i] != 0 && retini[i] !=ENOMEM) 233 { FAILED("Cond init returned a wrong error code when no memory was left"); } 234 235 if (retini[i] == 0) 236 { 237 #if VERBOSE > 0 238 output("Cond (%i) initialization succeeded when memory is full\n", i); 239 #endif 240 if (retdtr[i] != 0) 241 { UNRESOLVED( retdtr[i], "Cond destroy failed for a cond inilialized under full memory"); } 242 } 243 #if VERBOSE > 0 244 else 245 { 246 output("Cond (%i) initialization failed with ENOMEM\n", i); 247 } 248 #endif 249 } 250 PASSED; 251} 252 253#else /* WITHOUT_XOPEN */ 254int main(int argc, char * argv[]) 255{ 256 output_init(); 257 UNTESTED("This test requires XSI features"); 258} 259#endif 260