1 /******************************************************************************/
2 /*                                                                            */
3 /* Copyright (c) 2009 FUJITSU LIMITED                                         */
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 /* Author: Miao Xie <miaox@cn.fujitsu.com>                                    */
20 /*                                                                            */
21 /******************************************************************************/
22 
23 #include "config.h"
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <signal.h>
28 #include <err.h>
29 #include <limits.h>
30 #include <getopt.h>
31 #include <string.h>
32 #include <fcntl.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <sys/mman.h>
36 #include <sys/shm.h>
37 #include <syscall.h>
38 #include <pthread.h>
39 
40 char *TCID = "cpuset_memory_test";
41 int TST_TOTAL = 1;
42 
43 #if HAVE_LINUX_MEMPOLICY_H
44 
45 #include "../cpuset_lib/cpuset.h"
46 
47 static int fd;
48 
49 static int opt_mmap_anon;
50 static int opt_mmap_file;
51 static int opt_mmap_lock1;
52 static int opt_mmap_lock2;
53 static int opt_shm;
54 static int opt_hugepage;
55 static int opt_check; /* check node when munmap memory (only for mmap_anon()) */
56 static int opt_thread;
57 
58 static int key_id;			/* used with opt_shm */
59 static unsigned long memsize;
60 
61 #define FILE_HUGEPAGE	"/hugetlb/hugepagefile"
62 
63 #define MMAP_ANON	(SCHAR_MAX + 1)
64 #define MMAP_FILE	(SCHAR_MAX + 2)
65 #define MMAP_LOCK1	(SCHAR_MAX + 3)
66 #define MMAP_LOCK2	(SCHAR_MAX + 4)
67 #define SHM		(SCHAR_MAX + 5)
68 #define HUGEPAGE	(SCHAR_MAX + 6)
69 #define CHECK		(SCHAR_MAX + 7)
70 #define THREAD		(SCHAR_MAX + 8)
71 
72 const struct option long_opts[] = {
73 	{"mmap-anon", 0, NULL, MMAP_ANON},
74 	{"mmap-file", 0, NULL, MMAP_FILE},
75 	{"mmap-lock1", 0, NULL, MMAP_LOCK1},
76 	{"mmap-lock2", 0, NULL, MMAP_LOCK2},
77 	{"shm", 0, NULL, SHM},
78 	{"hugepage", 0, NULL, HUGEPAGE},
79 	{"check", 0, NULL, CHECK},
80 	{"thread", 0, NULL, THREAD},
81 	{"size", 1, NULL, 's'},
82 	{"key", 1, NULL, 'k'},
83 	{NULL, 0, NULL, 0},
84 };
85 
86 /*
87  * process_options: read options from user input
88  */
process_options(int argc,char * argv[])89 void process_options(int argc, char *argv[])
90 {
91 	int c;
92 	char *end;
93 
94 	while (1) {
95 		c = getopt_long(argc, argv, "s:k:", long_opts, NULL);
96 		if (c == -1)
97 			break;
98 
99 		switch (c) {
100 		case 's':
101 			memsize = strtoul(optarg, &end, 10);
102 			if (*end != '\0')
103 				errx(1, "wrong -s argument!");
104 			break;
105 		case 'k':
106 			key_id = atoi(optarg);
107 			break;
108 		case MMAP_ANON:
109 			opt_mmap_anon = 1;
110 			break;
111 		case MMAP_FILE:
112 			opt_mmap_file = 1;
113 			break;
114 		case MMAP_LOCK1:
115 			opt_mmap_lock1 = 1;
116 			break;
117 		case MMAP_LOCK2:
118 			opt_mmap_lock2 = 1;
119 			break;
120 		case SHM:
121 			opt_shm = 1;
122 			break;
123 		case HUGEPAGE:
124 			opt_hugepage = 1;
125 			break;
126 		case CHECK:
127 			opt_check = 1;
128 			break;
129 		case THREAD:
130 			opt_thread = 1;
131 			break;
132 		default:
133 			errx(1, "unknown option!\n");
134 			break;
135 		}
136 	}
137 
138 	if (!memsize)
139 		memsize = sysconf(_SC_PAGESIZE);
140 }
141 
142 /*
143  * touch_memory: force allocating phy memory
144  */
touch_memory_and_echo_node(char * p,int size)145 void touch_memory_and_echo_node(char *p, int size)
146 {
147 	int i;
148 	int pagesize = sysconf(_SC_PAGESIZE);
149 
150 	for (i = 0; i < size; i += pagesize)
151 		p[i] = 0xef;
152 
153 	printf("%d\n", cpuset_addr2node(p));
154 }
155 
mmap_anon(int flag_allocated)156 void mmap_anon(int flag_allocated)
157 {
158 	static char *p;
159 
160 	if (!flag_allocated) {
161 		p = mmap(NULL, memsize, PROT_WRITE | PROT_READ,
162 			 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
163 		if (p == MAP_FAILED)
164 			err(1, "mmap(anonymous) failed");
165 		touch_memory_and_echo_node(p, memsize);
166 	} else {
167 		if (opt_check)
168 			touch_memory_and_echo_node(p, memsize);
169 		if (munmap(p, memsize) == -1)
170 			err(1, "munmap(anonymous) failed");
171 	}
172 }
173 
mmap_file(int flag_allocated)174 void mmap_file(int flag_allocated)
175 {
176 	static char *p;
177 	static int fd_hugepage;
178 	int fd_tmp;
179 
180 	if (!flag_allocated) {
181 		if (opt_hugepage) {
182 			fd_hugepage = open(FILE_HUGEPAGE,
183 					   O_CREAT | O_RDWR, 0755);
184 			if (fd_hugepage < 0)
185 				err(1, "open hugepage file failed");
186 			fd_tmp = fd_hugepage;
187 		} else
188 			fd_tmp = fd;
189 
190 		p = mmap(NULL, memsize, PROT_WRITE | PROT_READ,
191 			 MAP_SHARED, fd_tmp, 0);
192 		if (p == MAP_FAILED) {
193 			if (opt_hugepage)
194 				unlink(FILE_HUGEPAGE);
195 			err(1, "mmap(file) failed");
196 		}
197 		touch_memory_and_echo_node(p, memsize);
198 	} else {
199 		if (munmap(p, memsize) == -1)
200 			err(1, "munmap(file) failed");
201 
202 		if (opt_hugepage) {
203 			close(fd_hugepage);
204 			unlink(FILE_HUGEPAGE);
205 		}
206 	}
207 }
208 
mmap_lock1(int flag_allocated)209 void mmap_lock1(int flag_allocated)
210 {
211 	static char *p;
212 
213 	if (!flag_allocated) {
214 		p = mmap(NULL, memsize, PROT_WRITE | PROT_READ,
215 			 MAP_PRIVATE | MAP_ANONYMOUS | MAP_LOCKED, 0, 0);
216 		if (p == MAP_FAILED)
217 			err(1, "mmap(lock) failed");
218 		touch_memory_and_echo_node(p, memsize);
219 	} else {
220 		if (munmap(p, memsize) == -1)
221 			err(1, "munmap(lock) failed");
222 	}
223 }
224 
mmap_lock2(int flag_allocated)225 void mmap_lock2(int flag_allocated)
226 {
227 	static char *p;
228 
229 	if (!flag_allocated) {
230 		p = mmap(NULL, memsize, PROT_WRITE | PROT_READ,
231 			 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
232 		if (p == MAP_FAILED)
233 			err(1, "mmap failed");
234 
235 		if (mlock(p, memsize))
236 			err(1, "mlock failed");
237 		touch_memory_and_echo_node(p, memsize);
238 	} else {
239 		if (munmap(p, memsize) == -1)
240 			err(1, "munmap failed");
241 	}
242 }
243 
shm(int flag_allocated)244 void shm(int flag_allocated)
245 {
246 	static char *p;
247 	static int shmid;
248 	unsigned long flag;
249 
250 	key_t key;
251 
252 	if (!flag_allocated) {
253 		flag = IPC_CREAT | SHM_R | SHM_W;
254 		if (opt_hugepage)
255 			flag |= SHM_HUGETLB;
256 
257 		key = ftok("/dev/null", key_id);
258 		if (key == -1)
259 			err(1, "ftok() failed\n");
260 
261 		shmid = shmget(key, memsize, flag);
262 		if (shmid == -1)
263 			err(1, "shmget() failed\n");
264 		shmctl(shmid, IPC_RMID, NULL);
265 
266 		shmid = shmget(key, memsize, flag);
267 		if (shmid == -1)
268 			err(1, "shmget() failed\n");
269 
270 		p = shmat(shmid, NULL, 0);
271 		if (p == (void *)-1) {
272 			shmctl(shmid, IPC_RMID, NULL);
273 			err(1, "shmat() failed\n");
274 		}
275 		touch_memory_and_echo_node(p, memsize);
276 	} else {
277 		if (shmdt(p) == -1)
278 			err(1, "shmdt() failed\n");
279 		if (shmctl(shmid, IPC_RMID, NULL) == -1)
280 			err(1, "shmctl() failed\n");
281 	}
282 }
283 
thread2_routine(void * arg)284 void *thread2_routine(void __attribute__ ((unused)) * arg)
285 {
286 	sigset_t set;
287 	sigset_t waitset;
288 	int flag_allocated;
289 
290 	sigemptyset(&set);
291 	sigaddset(&set, SIGUSR1);
292 	sigaddset(&set, SIGINT);
293 	pthread_sigmask(SIG_BLOCK, &set, NULL);
294 
295 	sigemptyset(&waitset);
296 	sigaddset(&waitset, SIGUSR2);
297 	pthread_sigmask(SIG_BLOCK, &waitset, NULL);
298 
299 	flag_allocated = 0;
300 
301 	for (;;) {
302 		if (sigwaitinfo(&waitset, NULL) < 0)
303 			err(1, "sigwaitinfo() in thread2 failed");
304 
305 		mmap_anon(flag_allocated);
306 		flag_allocated = !flag_allocated;
307 	}
308 
309 	return NULL;
310 }
311 
312 /*
313  * When we receive SIGUSR1, we allocate some memory according
314  * to the user intput when the process started.
315  * When we receive SIGUSR1 again, we will free all the allocated
316  * memory.
317  * Similiar for --thread option but SIGUSR2 signal is used
318  * to control thread2 behaviour.
319  */
main(int argc,char * argv[])320 int main(int argc, char *argv[])
321 {
322 	sigset_t waitset;
323 	int signo;
324 	int flag_allocated;
325 
326 	pthread_t thread2;
327 
328 	fd = open("/dev/zero", O_RDWR);
329 	if (fd < 0)
330 		err(1, "open /dev/zero failed");
331 
332 	process_options(argc, argv);
333 
334 	if (opt_thread) {
335 		sigset_t set;
336 		sigemptyset(&set);
337 		sigaddset(&set, SIGUSR2);
338 
339 		pthread_create(&thread2, NULL, thread2_routine, NULL);
340 
341 		pthread_sigmask(SIG_BLOCK, &set, NULL);
342 	}
343 
344 
345 	sigemptyset(&waitset);
346 	sigaddset(&waitset, SIGINT);
347 	sigaddset(&waitset, SIGUSR1);
348 
349 	pthread_sigmask(SIG_BLOCK, &waitset, NULL);
350 
351 	flag_allocated = 0;
352 
353 	for (;;) {
354 		signo = sigwaitinfo(&waitset, NULL);
355 		if (signo < 0)
356 			err(1, "sigwaitinfo() failed");
357 
358 		if (signo == SIGUSR1) {
359 			if (opt_mmap_anon)
360 				mmap_anon(flag_allocated);
361 
362 			if (opt_mmap_file)
363 				mmap_file(flag_allocated);
364 
365 			if (opt_mmap_lock1)
366 				mmap_lock1(flag_allocated);
367 
368 			if (opt_mmap_lock2)
369 				mmap_lock2(flag_allocated);
370 
371 			if (opt_shm)
372 				shm(flag_allocated);
373 
374 			flag_allocated = !flag_allocated;
375 		} else {
376 			break;
377 		}
378 	}
379 
380 	if (opt_thread) {
381 		void *retv;
382 		pthread_cancel(thread2);
383 		pthread_join(thread2, &retv);
384 	}
385 
386 	close(fd);
387 
388 	return 0;
389 }
390 
391 #else
main(void)392 int main(void)
393 {
394 	printf("System doesn't have required mempolicy support\n");
395 	return 1;
396 }
397 #endif
398