DF-5800 / fragstress.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | /* * DF pass-3 vm_map.c stress rig 2 — clip/simplify/unclip contention. * * Builds a heavily fragmented user map (adjacent anon mappings with * alternating protections and inheritances), then several threads beat on * overlapping ranges with mprotect / munmap+mmap / madvise / minherit / * mlock / munlock concurrently. Exercises: * - vm_map_clip_start/clip_end + vm_map_simplify_entry merging under * MAP_ENTRY_IN_TRANSITION contention (mlock's clip_range) * - vm_map_unclip_range KASSERT paths * - vm_map_insert coalesce path (adjacent identical mappings) * - freehint updates vs deletion * * build: cc -O -o fragstress fragstress.c -lpthread */ #include <sys/mman.h> #include <sys/resource.h> #include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #ifndef VM_INHERIT_NONE #define VM_INHERIT_SHARE 0 #define VM_INHERIT_COPY 1 #define VM_INHERIT_NONE 2 #endif #define NMAPS 2048 #define MAPLEN (64 * 1024) static void *base[NMAPS]; static volatile int stop_flag; static volatile long ops; static void * worker(void *arg) { unsigned long id = (unsigned long)arg; unsigned seed = id * 7919 + 13; while (!stop_flag) { int idx = rand_r(&seed) % NMAPS; int len = 1 + rand_r(&seed) % 8; /* spans adjacent entries */ int op = rand_r(&seed) % 8; void *p = base[idx]; size_t sz = (size_t)len * MAPLEN; switch (op) { case 0: mprotect(p, sz, PROT_READ | PROT_WRITE); break; case 1: mprotect(p, sz, PROT_READ); break; case 2: mprotect(p, sz, PROT_READ | PROT_WRITE | PROT_EXEC); break; case 3: madvise(p, sz, MADV_DONTNEED); break; case 4: minherit(p, sz, VM_INHERIT_NONE); break; case 5: minherit(p, sz, VM_INHERIT_COPY); break; case 6: mlock(p, sz); break; case 7: munlock(p, sz); break; } __sync_fetch_and_add(&ops, 1); } return NULL; } int main(void) { pthread_t th[6]; int i, round; /* Reserve a big contiguous span then chop it into pieces */ char *arena = mmap(NULL, (size_t)NMAPS * MAPLEN * 2, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0); if (arena == MAP_FAILED) { perror("arena mmap"); return 1; } for (i = 0; i < NMAPS; i++) { base[i] = mmap(arena + (size_t)i * MAPLEN * 2, MAPLEN, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0); if (base[i] == MAP_FAILED) { perror("piece mmap"); return 1; } memset(base[i], 0x5a, MAPLEN); } for (round = 0; round < 3; round++) { for (i = 0; i < 6; i++) pthread_create(&th[i], NULL, worker, (void *)(long)i); sleep(10); stop_flag = 1; for (i = 0; i < 6; i++) pthread_join(th[i], NULL); stop_flag = 0; printf("round %d: %ld ops complete\n", round, ops); fflush(stdout); } /* sanity: all pieces still readable */ for (i = 0; i < NMAPS; i += 64) if (*(volatile char *)base[i] != 0x5a && *(volatile char *)base[i] != 0) { printf("CORRUPTION at %p: %02x\n", base[i], *(volatile char *)base[i]); return 2; } printf("fragstress: complete, no corruption\n"); return 0; } |