/* * Test nested inherited shared memory through several * generations of child processes */ #include #include #include #include #include #include #include #include #include #include #include #include #define MAX_MM 1073741824 /* 1Gb */ #define TESTFILE "mmap.test.arena" #define MAX_FLAGS 3 int minherit_flags[MAX_FLAGS] = { MAP_INHERIT_NONE, MAP_INHERIT_SHARE, MAP_INHERIT_COPY }; void do_strange_things(char *, int, int); extern char *optarg; extern int opterr; extern int optind; extern int optopt; extern int optreset; char *arena; size_t arena_size = MAX_MM; int nerv = 20; int num_r = 4; int debug = 0; void usage(void) { printf("Usage:\n"); printf("\t-f \tuse to mmap on\n"); printf("\t-m \tsize of mmaped area in bytes\n"); printf("\t-r \tthe number of recursions \n"); printf("\t-n \tnumber of byteblocks to touch in each incarnation\n"); exit(1); } int main(int argc, char **argv) { int ch, fd; char *numend; char *filename = TESTFILE; int status; while ((ch = getopt(argc, argv, "c:df:m:n:r:")) != -1) { switch (ch) { case 'd': debug = 1; break; case 'm': errno = 0; arena_size = (size_t) strtoul(optarg, &numend, 10); /* if (optarg[0] == '\0' || *numend == '\0') { errx(1, "-m needs a number argument"); } if (errno == ERANGE && arena_size == ULONG_MAX) { errx(1, "-m argument out of range"); } */ break; case 'f': filename = strdup((const char *) optarg); break; case 'r': num_r = atoi(optarg); break; case 'n': nerv = atoi(optarg); break; default: usage(); /* not reached */ break; } } argc -= optind; argv += optind; /* Setup everything for the kids to play with */ if ((fd = open(TESTFILE, O_CREAT | O_RDWR | O_TRUNC | O_NOFOLLOW, 0660)) == -1) { errx(1, "Could not open %s: %s", filename, strerror(errno)); } if (ftruncate(fd, arena_size) == -1) errx(1, "Could not truncate %s to %lu bytes: %s", filename, arena_size, strerror(errno)); if ((arena = mmap(NULL, arena_size, PROT_READ | PROT_WRITE, MAP_INHERIT | MAP_SHARED, fd, 0)) == MAP_FAILED) errx(1, "Could not mmap to %s: %s", filename, strerror(errno)); /* start the kids */ do_strange_things(arena, arena_size, 0); waitpid(WAIT_ANY, &status, WNOHANG); if (munmap(arena, arena_size) != 0) errx(1, "Error munmapping: %s", strerror(errno)); close(fd); if (unlink(filename) != 0) errx(1, "Error unlinking %s: %s", filename, strerror(errno)); return 0; } void do_strange_things(char *astart, int your_size, int level) { int chunk_size; int pid, count; int w, i; char *base[2]; int to[2]; int mynum; if (level > num_r) { return; /* end of recursion */ } mynum = arena_size / your_size; mynum += (astart - arena) / your_size; w = mynum % MAX_FLAGS; if ((minherit(astart, your_size, minherit_flags[w])) < 0) { printf("minherit failed: %s", strerror(errno)); } chunk_size = your_size / 2; for (i = 0; i < 2; i++) { pid = fork(); if (pid == 0) { /* child */ do_strange_things(astart + (chunk_size * i), chunk_size, (level + 1)); } else if (pid == -1) { errx(1, "Could not fork %d-th child: %s", i, strerror(errno)); } else { /* parent */ ; } } /* Set a few bytes and copy them around */ for (count = 0; count < nerv && level > 0; count++) { /* sleep random microseconds, at least one tick */ usleep((useconds_t) (random() % 40 + 10)); /* random bytes inside our chunk */ base[0] = astart + (random() % chunk_size); base[1] = astart + (random() % chunk_size); /* random bytes ouside our chunk */ while ((arena + (to[0] = random() % arena_size) > astart) && (arena + to[0] < astart + chunk_size)) { /* empty body. on purpose */ } while ((arena + (to[1] = random() % arena_size) > astart) && (arena + to[1] < astart + chunk_size)) { /* empty body. on purpose */ } /* copy out */ memset(base[0], mynum, sizeof(int)); memcpy(arena + to[0], base[0], sizeof(int)); /* copy in */ memset(arena + to[1], mynum, sizeof(u_int32_t)); memcpy(base[1], arena + to[1], sizeof(int)); } }