#include #include #include #include #include #include #include #include #include #define MADV_FREE 4 int pid; void sig_handler(int signo) { printf("pid %d sig received %d\n", pid, signo); exit(1); } void free_bufs(void **bufs, unsigned long buf_count, unsigned long buf_size) { int i; for (i = 0; i < buf_count; i++) { if (bufs[i] != NULL) { munmap(bufs[i], buf_size); bufs[i] = NULL; } } } void alloc_bufs(void **bufs, unsigned long buf_count, unsigned long buf_size) { int i; time_t rawtime; struct tm * timeinfo; void *addr = (void*)0x600000000000; for (i = 0; i < buf_count; i++) { void *ptr = NULL; ptr = mmap(addr, buf_size, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, 0, 0); if (ptr == MAP_FAILED) { char bufs[64]; sprintf(bufs, "cat /proc/%d/maps", pid); printf("error to allocate %p\n", addr); system(bufs); exit(1); } addr += buf_size; bufs[i] = ptr; } } void fill_bufs(void **bufs, unsigned long buf_count, unsigned long buf_size) { int i; char msg[64] = {0, }; for (i = 0; i < buf_count; i++) memset(bufs[i], 'a' + i, buf_size); sprintf(msg, "pid %d buf_count %ld complete", pid, buf_count); } void madvise_bufs(void **bufs, unsigned long buf_count, unsigned long buf_size, int advise) { int i, ret; for (i = 0; i < buf_count; i++) { retry: if (ret = madvise(bufs[i], buf_size, advise)) { perror("fail to madvise\n"); if (ret == EAGAIN) { sleep(1); goto retry; } exit(1); } } } void madvise_free_bufs(void **bufs, unsigned long buf_count, unsigned long buf_size) { int i; for (i = 0; i < buf_count; i++) { if (madvise(bufs[i], buf_size, MADV_FREE)) { printf("[%d] bufs[%d] %p madvise_free fail\n", pid, i, bufs[i]); } } } void check_madvise_bufs(void **bufs, unsigned long buf_count, unsigned long buf_size, int freeable) { int i, j; for (i = 0; i < buf_count; i++) { char tmp; void *buf = bufs[i]; for (j = 0; j < buf_size; j++) { int ret; unsigned long addr; tmp = *(char*)(buf + j); /* The page was not purged */ if (tmp == 'a' + i) continue; /* The page was purged */ if (freeable && (int)tmp == 0) continue; /* Something wrong happens */ addr = (unsigned long)(buf + j); printf("pid %d bufaddr %p ofs %d freeable %d expected %c but %c\n", pid, buf, j, freeable, 'a' + i, tmp); exit(1); } } } int main(int argc, char *argv[]) { int i, ret, advise; unsigned long buf_size, buf_count, loop; void **bufs; pid = getpid(); if (argc != 4) { printf("check your argument\n"); return 1; } buf_size = atol(argv[1]); buf_count = atol(argv[2]); advise = atol(argv[3]); if (buf_size & ((2<<20) - 1)) { printf("buf_size should be 2M aligned\n"); return 1; } printf("[%d] buf size %ld buf_count %ld advise %d\n", pid, buf_size, buf_count, advise); if (signal(SIGINT, sig_handler) == SIG_ERR) { printf("Fail to register signal handler\n"); return 1; } if (signal(SIGHUP, sig_handler) == SIG_ERR) { printf("Fail to register signal handler\n"); return 1; } bufs = malloc(sizeof(void *) * buf_count); if (!bufs) return 1; memset(bufs, 0, sizeof(void *) * buf_count); srandom(pid); while (1) { int madvise_free = madvise_free = random() % 2; alloc_bufs(bufs, buf_count, buf_size); fill_bufs(bufs, buf_count, buf_size); /* We touched buffers so MADV_FREE cannot free pages */ check_madvise_bufs(bufs, buf_count, buf_size, 0); madvise_bufs(bufs, buf_count, buf_size, advise); sleep(1); /* syscall MADV_FREE */ madvise_free_bufs(bufs, buf_count, buf_size); sleep(1); check_madvise_bufs(bufs, buf_count, buf_size, 1); free_bufs(bufs, buf_count, buf_size); } return 0; }