• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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