1 /*
2 *
3 * Copyright (c) International Business Machines Corp., 2004
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 * hugeshmdt01.c
23 *
24 * DESCRIPTION
25 * hugeshmdt01 - check that largr shared memory is detached correctly
26 *
27 * ALGORITHM
28 * create a large shared memory resource
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 large 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 * hugeshmdt01 [-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 * 04/2004 - Updated by Robbie Williamson
55 *
56 * RESTRICTIONS
57 * none
58 */
59
60 #include <setjmp.h>
61 #include "hugetlb.h"
62 #include "safe_macros.h"
63 #include "mem.h"
64
65 char *TCID = "hugeshmdt01";
66 int TST_TOTAL = 1;
67
68 static size_t shm_size;
69 static int shm_id_1 = -1;
70 struct shmid_ds buf;
71 static int *shared;
72 static int pass;
73 static sigjmp_buf env;
74
75 static long hugepages = 128;
76 static option_t options[] = {
77 {"s:", &sflag, &nr_opt},
78 {NULL, NULL, NULL}
79 };
80
81 static void check_functionality(void);
82 static void sighandler(int sig);
83
main(int ac,char ** av)84 int main(int ac, char **av)
85 {
86 int lc;
87
88 tst_parse_opts(ac, av, options, NULL);
89
90 if (sflag)
91 hugepages = SAFE_STRTOL(NULL, nr_opt, 0, LONG_MAX);
92
93 setup();
94
95 for (lc = 0; TEST_LOOPING(lc); lc++) {
96 tst_count = 0;
97
98 if (shmdt(shared) == -1) {
99 tst_resm(TFAIL | TERRNO, "shmdt");
100 } else {
101 check_functionality();
102 }
103
104 /* reattach the shared memory segment in case we are looping */
105 shared = shmat(shm_id_1, 0, 0);
106 if (shared == (void *)-1)
107 tst_brkm(TBROK | TERRNO, cleanup, "shmat #2: reattach");
108
109 /* also reset pass */
110 pass = 0;
111 }
112 cleanup();
113 tst_exit();
114 }
115
check_functionality(void)116 static void check_functionality(void)
117 {
118 /* stat the shared memory segment */
119 if (shmctl(shm_id_1, IPC_STAT, &buf) == -1)
120 tst_brkm(TBROK | TERRNO, cleanup, "shmctl");
121
122 if (buf.shm_nattch != 0) {
123 tst_resm(TFAIL, "# of attaches is incorrect");
124 return;
125 }
126
127 /*
128 * Try writing to the shared memory. This should generate a
129 * SIGSEGV which will be caught below.
130 *
131 * This is wrapped by the sigsetjmp() call that will take care of
132 * restoring the program's context in an elegant way in conjunction
133 * with the call to siglongjmp() in the signal handler.
134 *
135 * An attempt to do the assignment without using the sigsetjmp()
136 * and siglongjmp() calls will result in an infinite loop. Program
137 * control is returned to the assignment statement after the execution
138 * of the signal handler and another SIGSEGV will be generated.
139 */
140
141 if (sigsetjmp(env, 1) == 0)
142 *shared = 2;
143
144 if (pass)
145 tst_resm(TPASS, "huge shared memory detached correctly");
146 else
147 tst_resm(TFAIL, "huge shared memory was not detached "
148 "correctly");
149 }
150
sighandler(int sig)151 static void sighandler(int sig)
152 {
153 /* if we have received a SIGSEGV, we are almost done */
154 if (sig == SIGSEGV) {
155 /* set the global variable and jump back */
156 pass = 1;
157 siglongjmp(env, 1);
158 } else {
159 tst_brkm(TBROK, cleanup, "unexpected signal received: %d", sig);
160 }
161 }
162
setup(void)163 void setup(void)
164 {
165 long hpage_size;
166
167 tst_require_root();
168 check_hugepage();
169 tst_sig(NOFORK, sighandler, cleanup);
170 tst_tmpdir();
171
172 orig_hugepages = get_sys_tune("nr_hugepages");
173 set_sys_tune("nr_hugepages", hugepages, 1);
174 hpage_size = read_meminfo("Hugepagesize:") * 1024;
175
176 shm_size = hpage_size * hugepages / 2;
177 update_shm_size(&shm_size);
178 shmkey = getipckey(cleanup);
179
180 /* create a shared memory resource with read and write permissions */
181 shm_id_1 = shmget(shmkey, shm_size,
182 SHM_HUGETLB | SHM_RW | IPC_CREAT | IPC_EXCL);
183 if (shm_id_1 == -1)
184 tst_brkm(TBROK | TERRNO, cleanup, "shmget");
185
186 /* attach the shared memory segment */
187 shared = shmat(shm_id_1, 0, 0);
188 if (shared == (void *)-1)
189 tst_brkm(TBROK | TERRNO, cleanup, "shmat #1");
190
191 /* give a value to the shared memory integer */
192 *shared = 4;
193
194 TEST_PAUSE;
195 }
196
cleanup(void)197 void cleanup(void)
198 {
199 rm_shm(shm_id_1);
200
201 set_sys_tune("nr_hugepages", orig_hugepages, 0);
202
203 tst_rmdir();
204 }
205