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_mutex_init() 29 * -> free the memory 30 * -> Checks that pthread_mutex_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_mutex_t mtx; 94 pthread_mutexattr_t ma[4]; 95 pthread_mutexattr_t *pma[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 output_init(); 110 111 child = fork(); 112 113 if (child == (pid_t)-1) 114 { UNRESOLVED(errno, "Fork failed"); } 115 116 if (child != 0) /* We are the father */ 117 { 118 if (child != waitpid(child, &status, 0)) 119 { UNRESOLVED(errno, "Waitpid failed"); } 120 121 if (WIFSIGNALED(status)) 122 { UNRESOLVED(WTERMSIG(status), 123 "The child process was killed."); } 124 125 if (WIFEXITED(status)) 126 return WEXITSTATUS(status); 127 128 UNRESOLVED(0, "Child process neither returned nor was killed."); 129 } 130 131 /* Only the child goes further */ 132 133 /* We initialize the different mutex attributes */ 134 for (i=0; (i<4) && (ret == 0); i++) 135 { 136 pma[i] = &ma[i]; 137 ret = pthread_mutexattr_init(pma[i]); 138 } 139 if (ret) 140 { UNRESOLVED(ret, "Mutex attribute init failed"); } 141 pma[4] = (pthread_mutexattr_t *) NULL; 142 143 if ((ret = pthread_mutexattr_settype(pma[0], PTHREAD_MUTEX_NORMAL))) 144 { UNRESOLVED(ret, "Mutex attribute NORMAL failed"); } 145 if ((ret = pthread_mutexattr_settype(pma[0], PTHREAD_MUTEX_DEFAULT))) 146 { UNRESOLVED(ret, "Mutex attribute DEFAULT failed"); } 147 if ((ret = pthread_mutexattr_settype(pma[0], PTHREAD_MUTEX_RECURSIVE))) 148 { UNRESOLVED(ret, "Mutex attribute RECURSIVE failed"); } 149 if ((ret = pthread_mutexattr_settype(pma[0], PTHREAD_MUTEX_ERRORCHECK))) 150 { UNRESOLVED(ret, "Mutex attribute ERRORCHECK failed"); } 151 152 sz = sysconf(_SC_PAGESIZE); 153 154 155 /* Limit the process memory to a small value (64Mb for example). */ 156 rl.rlim_max=1024*1024*64; 157 rl.rlim_cur=1024*1024*64; 158 if ((ret = setrlimit(RLIMIT_AS, &rl))) 159 { UNRESOLVED(ret, "Memory limitation failed"); } 160 161 162 #if VERBOSE > 1 163 output("Ready to take over memory. Page size is %d\n", sz); 164 #endif 165 166 /* Allocate all available memory */ 167 while (1) 168 { 169 ptr = malloc( sz ); /* Allocate one page of memory */ 170 if (ptr == NULL) 171 break; 172 #if VERBOSE > 1 173 ret++; 174 #endif 175 *(void **)ptr = ptr_prev; /* Write into the allocated page */ 176 ptr_prev = ptr; 177 } 178 #if VERBOSE > 1 179 output("%d pages were allocated before failure\n", ret); 180 ret = 0; 181 #endif 182 183 while (1) 184 { 185 ptr = malloc( sizeof(void*) ); /* Allocate every remaining bits of memory */ 186 if (ptr == NULL) 187 break; 188 #if VERBOSE > 1 189 ret++; 190 #endif 191 *(void **)ptr = ptr_prev; /* Keep track of allocated memory */ 192 ptr_prev = ptr; 193 } 194 #if VERBOSE > 1 195 output("%d additional spaces were allocated before failure\n", ret); 196 ret = 0; 197 #endif 198 if (errno != ENOMEM) 199 UNRESOLVED(errno, "Memory not full"); 200 201 /* Now that memory is full, we try to initialize a mutex */ 202 for (i=0; i<5; i++) 203 { 204 retini[i] = pthread_mutex_init(&mtx, pma[i]); 205 if (!retini[i]) /* If mutex has been initialized, we destroy it */ 206 retdtr[i] = pthread_mutex_destroy(&mtx); 207 } 208 209 /* We can now free the memory */ 210 while (ptr_prev != NULL) 211 { 212 ptr = ptr_prev; 213 ptr_prev = *(void **)ptr; 214 free(ptr); 215 } 216 217 #if VERBOSE > 1 218 output("Memory is released\n"); 219 #endif 220 221 for (i=0; i<4; i++) 222 pthread_mutexattr_destroy(pma[i]); 223 224 225 for (i=0; i<5; i++) 226 { 227 if (retini[i] != 0 && retini[i] !=ENOMEM) 228 { FAILED("Mutex init returned a wrong error code when no memory was left"); } 229 230 if (retini[i] == 0) 231 { 232 #if VERBOSE > 0 233 output("Mutex initialization for attribute %d succeeds when memory is full\n", i); 234 #endif 235 if (retdtr[i] != 0) 236 { UNRESOLVED( retdtr[i], "Mutex destroy failed on mutex inilialized under heavy loaded memory"); } 237 } 238 #if VERBOSE > 0 239 else 240 { 241 output("Mutex initialization for attribute %d fails with ENOMEM when memory is full\n", i); 242 } 243 #endif 244 } 245 PASSED; 246} 247 248#else /* WITHOUT_XOPEN */ 249int main(int argc, char * argv[]) 250{ 251 output_init(); 252 UNTESTED("This test requires XSI features"); 253} 254#endif 255