1 /* 2 * 3 * Copyright (c) International Business Machines Corp., 2001 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 13 * the GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 /* 21 * NAME 22 * shmdt01.c 23 * 24 * DESCRIPTION 25 * shmdt01 - check that shared memory is detached correctly 26 * 27 * ALGORITHM 28 * create a shared memory resource of size sizeof(int) 29 * attach it to the current process and give it a value 30 * call shmdt() using the TEST macro 31 * check the return code 32 * if failure, issue a FAIL message. 33 * otherwise, 34 * if doing functionality testing 35 * attempt to write a value to the shared memory address 36 * this should generate a SIGSEGV which will be caught in 37 * the signal handler 38 * if correct, 39 * issue a PASS message 40 * otherwise 41 * issue a FAIL message 42 * call cleanup 43 * 44 * USAGE: <for command-line> 45 * shmdt01 [-c n] [-f] [-i n] [-I x] [-P x] [-t] 46 * where, -c n : Run n copies concurrently. 47 * -f : Turn off functionality Testing. 48 * -I x : Execute test for x seconds. 49 * -P x : Pause for x seconds between iterations. 50 * -t : Turn on syscall timing. 51 * 52 * HISTORY 53 * 03/2001 - Written by Wayne Boyer 54 * 55 * 06/03/2008 Renaud Lottiaux (Renaud.Lottiaux (at) kerlabs.com) 56 * - Fix wrong return value check on shmat system call (leading to 57 * segfault in case of error with this syscall). 58 * 59 * RESTRICTIONS 60 * none 61 */ 62 63 #include <setjmp.h> 64 #include "ipcshm.h" 65 66 char *TCID = "shmdt01"; 67 int TST_TOTAL = 1; 68 69 void sighandler(int); 70 struct shmid_ds buf; 71 72 int shm_id_1 = -1; 73 int *shared; /* variable to use for shared memory attach */ 74 int new; 75 int pass = 0; 76 sigjmp_buf env; 77 78 int main(int ac, char **av) 79 { 80 int lc; 81 void check_functionality(void); 82 83 tst_parse_opts(ac, av, NULL, NULL); 84 85 setup(); /* global setup */ 86 87 /* The following loop checks looping state if -i option given */ 88 89 for (lc = 0; TEST_LOOPING(lc); lc++) { 90 /* reset tst_count in case we are looping */ 91 tst_count = 0; 92 93 /* 94 * Use TEST macro to make the shmdt() call 95 */ 96 97 TEST(shmdt((const void *)shared)); 98 99 if (TEST_RETURN == -1) { 100 tst_resm(TFAIL, "%s call failed - errno = %d : %s", 101 TCID, TEST_ERRNO, strerror(TEST_ERRNO)); 102 } else { 103 check_functionality(); 104 } 105 106 /* reattach the shared memory segment in case we are looping */ 107 shared = shmat(shm_id_1, 0, 0); 108 109 if (shared == (void *)-1) { 110 tst_brkm(TBROK, cleanup, "memory reattach failed"); 111 } 112 113 /* also reset pass */ 114 pass = 0; 115 } 116 117 cleanup(); 118 119 tst_exit(); 120 } 121 122 /* 123 * check_functionality() - make sure the memory is detached correctly 124 */ 125 void check_functionality(void) 126 { 127 /* stat the shared memory segment */ 128 if (shmctl(shm_id_1, IPC_STAT, &buf) == -1) 129 tst_brkm(TBROK | TERRNO, cleanup, 130 "could not stat in signal handler"); 131 132 if (buf.shm_nattch != 0) { 133 tst_resm(TFAIL, "# of attaches is incorrect"); 134 return; 135 } 136 137 /* 138 * Try writing to the shared memory. This should generate a 139 * SIGSEGV which will be caught below. 140 * 141 * This is wrapped by the sigsetjmp() call that will take care of 142 * restoring the program's context in an elegant way in conjunction 143 * with the call to siglongjmp() in the signal handler. 144 * 145 * An attempt to do the assignment without using the sigsetjmp() 146 * and siglongjmp() calls will result in an infinite loop. Program 147 * control is returned to the assignment statement after the execution 148 * of the signal handler and another SIGSEGV will be generated. 149 */ 150 151 if (sigsetjmp(env, 1) == 0) { 152 *shared = 2; 153 } 154 155 if (pass) { 156 tst_resm(TPASS, "shared memory detached correctly"); 157 } else { 158 tst_resm(TFAIL, "shared memory was not detached correctly"); 159 } 160 } 161 162 void sighandler(int sig) 163 { 164 /* if we have received a SIGSEGV, we are almost done */ 165 if (sig == SIGSEGV) { 166 /* set the global variable and jump back */ 167 pass = 1; 168 siglongjmp(env, 1); 169 } else 170 tst_brkm(TBROK, cleanup, 171 "received an unexpected signal: %d", sig); 172 } 173 174 /* 175 * setup() - performs all the ONE TIME setup for this test. 176 */ 177 void setup(void) 178 { 179 180 tst_sig(NOFORK, sighandler, cleanup); 181 182 TEST_PAUSE; 183 184 /* 185 * Create a temporary directory and cd into it. 186 * This helps to ensure that a unique msgkey is created. 187 * See ../lib/libipc.c for more information. 188 */ 189 tst_tmpdir(); 190 191 /* get an IPC resource key */ 192 shmkey = getipckey(); 193 194 /* create a shared memory resource with read and write permissions */ 195 if ((shm_id_1 = shmget(shmkey, INT_SIZE, SHM_RW | IPC_CREAT | 196 IPC_EXCL)) == -1) { 197 tst_brkm(TBROK, cleanup, "Failed to create shared memory " 198 "resource in setup()"); 199 } 200 201 /* attach the shared memory segment */ 202 shared = shmat(shm_id_1, 0, 0); 203 204 if (shared == (void *)-1) { 205 tst_brkm(TBROK, cleanup, "Couldn't attach shared memory"); 206 } 207 208 /* give a value to the shared memory integer */ 209 *shared = 4; 210 } 211 212 /* 213 * cleanup() - performs all the ONE TIME cleanup for this test at completion 214 * or premature exit. 215 */ 216 void cleanup(void) 217 { 218 /* if it exists, delete the shared memory resource */ 219 rm_shm(shm_id_1); 220 221 tst_rmdir(); 222 223 } 224