/* * gcc -Wall -o reader reader.c -lpthread */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include struct thread_data { int fd; size_t size; }; static void *drop_pages(void *arg) { struct thread_data *td = arg; int ret; unsigned long nr_pages = td->size / 4096; unsigned int seed = 0x55443322; off_t offset; unsigned long nr_drops = 0; while (1) { offset = rand_r(&seed) % nr_pages; offset = offset * 4096; ret = posix_fadvise(td->fd, offset, 4096, POSIX_FADV_DONTNEED); if (ret < 0) err(1, "fadvise dontneed"); /* every once and a while, drop everything */ if (nr_drops > nr_pages / 2) { ret = posix_fadvise(td->fd, 0, td->size, POSIX_FADV_DONTNEED); if (ret < 0) err(1, "fadvise dontneed"); fprintf(stderr, "+"); nr_drops = 0; } nr_drops++; } return NULL; } #define READ_BUF (2 * 1024 * 1024) static void *read_pages(void *arg) { struct thread_data *td = arg; char buf[READ_BUF]; ssize_t ret; loff_t offset; while (1) { offset = 0; while(offset < td->size) { ret = pread(td->fd, buf, READ_BUF, offset); if (ret < 0) err(1, "read"); if (ret == 0) break; offset += ret; } } return NULL; } int main(int ac, char **av) { int fd; int ret; struct stat st; struct thread_data td; pthread_t drop_tid; pthread_t drop2_tid; pthread_t read_tid; if (ac != 2) err(1, "usage: reader filename\n"); fd = open(av[1], O_RDONLY, 0600); if (fd < 0) err(1, "unable to open %s", av[1]); ret = fstat(fd, &st); if (ret < 0) err(1, "stat"); td.fd = fd; td.size = st.st_size; ret = pthread_create(&drop_tid, NULL, drop_pages, &td); if (ret) err(1, "pthread_create"); ret = pthread_create(&drop2_tid, NULL, drop_pages, &td); if (ret) err(1, "pthread_create"); ret = pthread_create(&read_tid, NULL, read_pages, &td); if (ret) err(1, "pthread_create"); pthread_join(drop_tid, NULL); pthread_join(drop2_tid, NULL); pthread_join(read_tid, NULL); }