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@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
main(int ac,char ** av)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 */
check_functionality(void)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
sighandler(int sig)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 */
setup(void)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 */
cleanup(void)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