#include "config.h" #include #include /** * rszshm - resizable pointer-safe shared memory * * If two separate processes have shared mappings of the same file at the * same address, then pointers to addresses within the region can be shared * between the processes and safely dereferenced. * * Mapping to the same address in unrelated processes is nontrivial. One can * request a specific address, but mmap will return another in case of an * overlap. One can require a specific address, but mmap will unmap anything * overlapped. On Linux boxes it can be seen that the used addresses clump * at either end of the address range. rszshm tries to mmap in the middle * of the address range, and checks if the requested address matches the * returned address. If not, additional addresses are tried. Once mapped, * the address is recorded to a header in the file. Another process reads the * header and requests the saved address from mmap. If the returned address * matches, work proceeds. While the defaults provide a propitious search, * all the search parameters may be specified. * * To accommodate resizing, rszshm first maps a large, private, noreserve map. * This serves to claim a span of addresses. The shared file mapping then * overlays the beginning of the span. Later calls to extend the mapping * overlay more of the span. Attempts to extend beyond the end of the span * return an error. * * Example: * // fork x times, grow and fill shared memory cooperatively * #include * #include * #include * #include * #include * #include * * #define ok(x) ({ int n = (x); if (n == -1) err(1, "%s", #x); n; }) * * int main(int argc, char *argv[]) { * int pidcnt, stopval, n, i; * struct rszshm *r; * char *m; * * assert(argc == 3); * pidcnt = atoi(argv[1]); * stopval = atoi(argv[2]); * assert(pidcnt > 0 && stopval > 0); * * if (!rszshm_mkm(r, 4096, NULL)) * err(1, "rszshm_mkm"); * * printf("%s\n", r->fname); * * for (n = 0; n < pidcnt - 1; n++) * if (ok(fork()) == 0) * break; * * m = (char *) r->dat + sizeof(int); * #define next() (__sync_fetch_and_add((int *) r->dat, 1)) * * for(i = next(); i < stopval; i = next()) { * if (i >= r->cap - sizeof(int)) * ok(rszshm_grow(r)); * assert(m[i] == '\0'); * m[i] = 'A' + n; * kill(0, 0); // busy work * } * * rszshm_free(r); * return 0; * } * // $ ./foo 8 $((4*1024*1024-28)) * // /dev/shm/rszshm_LAsEvt/0 * // $ tail -c +29 /dev/shm/rszshm_LAsEvt/0 | sed 's/./&\n/g' | sort | uniq -c | tr '\n' '\t'; echo * // 515532 A 527251 B 512930 C 513062 D 544326 E 545876 F 512936 G 522363 H * * Ccanlint: tests_pass_valgrind FAIL * License: APACHE-2 * Author: Dan Good * * Ccanlint: * // tests use optional macros containing statement expressions * tests_compile_without_features FAIL */ int main(int argc, char *argv[]) { /* Expect exactly one argument */ if (argc != 2) return 1; if (strcmp(argv[1], "depends") == 0) return 0; return 1; }