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