store_t* open_mmap_store(const char* base_dir, const char* name, int flags) { int dir_fd = open(base_dir, O_DIRECTORY, (mode_t)0600); if (dir_fd == -1) return NULL; int real_fd = openat(dir_fd, name, O_RDWR, (mode_t)0600); ensure(real_fd > 0, "Failed to open mmap store file"); close(dir_fd); struct stat sb; int ret = fstat(real_fd, &sb); ensure(ret != -1, "Failed to fstat file"); int size = sb.st_size; // This is nearly identical to the create_mmap_store. Maybe should make an "init mmap store" or // something? struct mmap_store *store = (struct mmap_store*) calloc(1, sizeof(struct mmap_store)); if (store == NULL) return NULL; void *mapping = mmap(NULL, (size_t) size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE | MAP_NONBLOCK , real_fd, 0); if (mapping == NULL) return NULL; madvise(mapping, size, MADV_SEQUENTIAL); uint32_t off = sizeof(uint32_t) * 2; ensure(((uint32_t *)mapping)[0] == 0xDEADBEEF, "Magic number does not match. Bad file format"); ensure(((uint32_t *)mapping)[1] == size, "Size recorded does not match file size. Bad file format"); ensure(asprintf(&(store->filename), "%s/%s", base_dir, name) > 0, "Failed to allocate store filename"); store->fd = real_fd; store->capacity = size; store->flags = flags; store->mapping = mapping; // These don't really matter because writers aren't allowed... ck_pr_store_32(&store->write_cursor, off); ck_pr_store_32(&store->last_sync, 0); ck_pr_store_32(&store->read_cursor, -1); // We infer that this store has been synced... ck_pr_store_32(&store->syncing_and_writers, 0x80000000U); ck_pr_store_32(&store->synced, 1); ck_pr_fence_atomic(); ensure(msync(mapping, off, MS_SYNC) == 0, "Unable to sync"); ensure(store->write_cursor != 0, "Cursor incorrect"); ((store_t *)store)->write = &_mmap_write; ((store_t *)store)->open_cursor = &_mmap_open_cursor; ((store_t *)store)->pop_cursor = &_mmap_pop_cursor; ((store_t *)store)->capacity = &_mmap_capacity; ((store_t *)store)->cursor = &_mmap_cursor; ((store_t *)store)->start_cursor = &_mmap_start_cursor; ((store_t *)store)->sync = &_mmap_sync; ((store_t *)store)->close = &_mmap_close; ((store_t *)store)->destroy = &_mmap_destroy; return (store_t *)store; }
store_t* create_mmap_store(uint32_t size, const char* base_dir, const char* name, int flags) { //TODO : Enforce a max size //TODO : Check flags //TODO : check thread sanity //TODO : check size is near a page int dir_fd = open(base_dir, O_DIRECTORY, (mode_t)0600); if (dir_fd == -1) return NULL; int real_fd = openat(dir_fd, name, O_RDWR | O_CREAT, (mode_t)0600); close(dir_fd); // TODO - Check for the race condition if two people attempt to create // the same segment if (real_fd == -1) return NULL; if (posix_fallocate(real_fd, 0, size) != 0) { close(real_fd); return NULL; } struct mmap_store *store = (struct mmap_store*) calloc(1, sizeof(struct mmap_store)); if (store == NULL) return NULL; void *mapping = mmap(NULL, (size_t) size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE | MAP_NONBLOCK , real_fd, 0); if (mapping == NULL) return NULL; madvise(mapping, size, MADV_SEQUENTIAL); uint32_t off = sizeof(uint32_t) * 2; ((uint32_t *)mapping)[0] = 0xDEADBEEF; ((uint32_t *)mapping)[1] = size; store->fd = real_fd; store->capacity = size; store->flags = flags; store->mapping = mapping; ck_pr_store_32(&store->write_cursor, off); ck_pr_store_32(&store->sync_cursor, off); ck_pr_fence_atomic(); ensure(msync(mapping, off, MS_SYNC) == 0, "Unable to sync"); ensure(store->write_cursor != 0, "Cursor incorrect"); ensure(store->sync_cursor != 0, "Cursor incorrect"); ((store_t *)store)->write = &_mmap_write; ((store_t *)store)->open_cursor = &_mmap_open_cursor; ((store_t *)store)->capacity = &_mmap_capacity; ((store_t *)store)->cursor = &_mmap_cursor; ((store_t *)store)->sync = &_mmap_sync; ((store_t *)store)->close = &_mmap_close; ((store_t *)store)->destroy = &_mmap_destroy; return (store_t *)store; }
int main(void) { int r = 0; /* Below serves as a marker. */ ck_pr_sub_int(&r, 31337); /* * This is a simple test to help ensure all fences compile or crash * on target. Below are generated according to the underlying memory * model's ordering. */ ck_pr_fence_atomic(); ck_pr_fence_atomic_store(); ck_pr_fence_atomic_load(); ck_pr_fence_store_atomic(); ck_pr_fence_load_atomic(); ck_pr_fence_load(); ck_pr_fence_load_store(); ck_pr_fence_store(); ck_pr_fence_store_load(); ck_pr_fence_memory(); ck_pr_fence_release(); ck_pr_fence_acquire(); ck_pr_fence_acqrel(); ck_pr_fence_lock(); ck_pr_fence_unlock(); /* Below serves as a marker. */ ck_pr_sub_int(&r, 31337); /* The following are generating assuming RMO. */ ck_pr_fence_strict_atomic(); ck_pr_fence_strict_atomic_store(); ck_pr_fence_strict_atomic_load(); ck_pr_fence_strict_store_atomic(); ck_pr_fence_strict_load_atomic(); ck_pr_fence_strict_load(); ck_pr_fence_strict_load_store(); ck_pr_fence_strict_store(); ck_pr_fence_strict_store_load(); ck_pr_fence_strict_memory(); ck_pr_fence_strict_release(); ck_pr_fence_strict_acquire(); ck_pr_fence_strict_acqrel(); ck_pr_fence_strict_lock(); ck_pr_fence_strict_unlock(); return 0; }
store_t* create_mmap_store(uint32_t size, const char* base_dir, const char* name, int flags) { //TODO : Enforce a max size //TODO : Check flags //TODO : check thread sanity //TODO : check size is near a page int dir_fd = open(base_dir, O_DIRECTORY, (mode_t)0600); if (dir_fd == -1) return NULL; int openat_flags = O_RDWR | O_CREAT | O_SYNC; if (flags & DELETE_IF_EXISTS) { openat_flags = openat_flags | O_TRUNC; } else { openat_flags = openat_flags | O_EXCL; } int real_fd = openat(dir_fd, name, openat_flags, (mode_t)0600); close(dir_fd); // TODO - Check for the race condition if two people attempt to create // the same segment if (real_fd == -1) { // TODO: This is a terrible hack. We need to fix the error handling, but for now, actually // warn us if we are failing because of loading a garbage file. ensure(errno != EEXIST, "Failed to create mmap store because file already exists"); return NULL; } if (posix_fallocate(real_fd, 0, size) != 0) { close(real_fd); return NULL; } struct mmap_store *store = (struct mmap_store*) calloc(1, sizeof(struct mmap_store)); if (store == NULL) return NULL; void *mapping = mmap(NULL, (size_t) size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE | MAP_NONBLOCK , real_fd, 0); if (mapping == NULL) return NULL; madvise(mapping, size, MADV_SEQUENTIAL); uint32_t off = sizeof(uint32_t) * 2; ((uint32_t *)mapping)[0] = 0xDEADBEEF; ((uint32_t *)mapping)[1] = size; ensure(asprintf(&(store->filename), "%s/%s", base_dir, name) > 0, "Failed to allocate store filename"); store->fd = real_fd; store->capacity = size; store->flags = flags; store->mapping = mapping; ck_pr_store_32(&store->write_cursor, off); ck_pr_store_32(&store->last_sync, 0); ck_pr_store_32(&store->read_cursor, -1); ck_pr_store_32(&store->syncing_and_writers, 0); ck_pr_store_32(&store->synced, 0); ck_pr_fence_atomic(); ensure(msync(mapping, off, MS_SYNC) == 0, "Unable to sync"); ensure(store->write_cursor != 0, "Cursor incorrect"); ((store_t *)store)->write = &_mmap_write; ((store_t *)store)->open_cursor = &_mmap_open_cursor; ((store_t *)store)->pop_cursor = &_mmap_pop_cursor; ((store_t *)store)->capacity = &_mmap_capacity; ((store_t *)store)->cursor = &_mmap_cursor; ((store_t *)store)->start_cursor = &_mmap_start_cursor; ((store_t *)store)->sync = &_mmap_sync; ((store_t *)store)->close = &_mmap_close; ((store_t *)store)->destroy = &_mmap_destroy; return (store_t *)store; }