Data-NDArray-Shared
view release on metacpan or search on metacpan
hdr->array_id = nda_gen_array_id(base);
__atomic_thread_fence(__ATOMIC_SEQ_CST);
}
static inline NdaHandle *nda_setup(void *base, size_t map_size,
const char *path, int backing_fd) {
NdaHeader *hdr = (NdaHeader *)base;
NdaHandle *h = (NdaHandle *)calloc(1, sizeof(NdaHandle));
if (!h) {
munmap(base, map_size);
if (backing_fd >= 0) close(backing_fd);
return NULL;
}
h->hdr = hdr;
h->base = base;
h->reader_slots = (NdaReaderSlot *)((uint8_t *)base + hdr->reader_slots_off);
h->mmap_size = map_size;
h->path = path ? strdup(path) : NULL;
h->backing_fd = backing_fd;
h->my_slot_idx = UINT32_MAX;
return h;
}
/* Validate a mapped header (shared by reopen and open_fd). Stored
* dtype/shape/strides/size win on reopen; require self-consistency and the
* file size to match. */
static inline int nda_validate_header(const NdaHeader *hdr, uint64_t file_size) {
if (hdr->magic != NDA_MAGIC) return 0;
if (hdr->version != NDA_VERSION) return 0;
if (hdr->dtype >= NDA_NTYPES) return 0;
if (hdr->ndim < 1 || hdr->ndim > NDA_MAX_DIMS) return 0;
if (hdr->itemsize != nda_itemsize_tab[hdr->dtype]) return 0;
uint64_t size = 1;
for (uint32_t d = 0; d < hdr->ndim; d++) {
if (hdr->shape[d] < 1) return 0;
if (hdr->shape[d] > UINT64_MAX / size) return 0;
size *= hdr->shape[d];
}
if (hdr->size != size) return 0;
if (size > NDA_MAX_BYTES / hdr->itemsize) return 0;
/* row-major stride check */
uint64_t st = 1;
for (int d = (int)hdr->ndim - 1; d >= 0; d--) {
if (hdr->strides[d] != st) return 0;
st *= hdr->shape[d];
}
uint64_t data_bytes = size * hdr->itemsize;
NdaLayout L = nda_layout();
if (hdr->reader_slots_off != L.reader_slots) return 0;
if (hdr->data_off != L.data) return 0;
if (hdr->total_size != L.data + data_bytes) return 0;
if (hdr->total_size != file_size) return 0;
return 1;
}
/* Securely obtain a fd: create exclusively (O_CREAT|O_EXCL|O_NOFOLLOW at mode,
* default 0600), or attach an existing file (O_RDWR|O_NOFOLLOW, no O_CREAT). */
static int nda_secure_open(const char *path, mode_t mode, char *errbuf) {
for (int attempt = 0; attempt < 100; attempt++) {
int fd = open(path, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_CLOEXEC, mode);
if (fd >= 0) { (void)fchmod(fd, mode); return fd; } /* exact mode: umask narrowed the O_EXCL create */
if (errno != EEXIST) { NDA_ERR("create %s: %s", path, strerror(errno)); return -1; }
fd = open(path, O_RDWR|O_NOFOLLOW|O_CLOEXEC);
if (fd >= 0) return fd;
if (errno == ENOENT) continue; /* creator unlinked between our two opens; retry */
NDA_ERR("open %s: %s", path, strerror(errno)); /* ELOOP => symlink rejected */
return -1;
}
NDA_ERR("open %s: create/attach kept racing", path);
return -1;
}
static NdaHandle *nda_create(const char *path, int dtype,
const uint64_t *shape, uint32_t ndim, mode_t mode, char *errbuf) {
uint64_t size, strides[NDA_MAX_DIMS], data_bytes;
if (!nda_validate_create_args(dtype, shape, ndim, &size, strides, &data_bytes, errbuf))
return NULL;
uint64_t total = nda_total_size(data_bytes);
int anonymous = (path == NULL);
int fd = -1;
size_t map_size;
void *base;
if (anonymous) {
map_size = (size_t)total;
base = mmap(NULL, map_size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
if (base == MAP_FAILED) { NDA_ERR("mmap: %s", strerror(errno)); return NULL; }
} else {
fd = nda_secure_open(path, mode, errbuf);
if (fd < 0) return NULL;
if (flock(fd, LOCK_EX) < 0) { NDA_ERR("flock: %s", strerror(errno)); close(fd); return NULL; }
struct stat stt;
if (fstat(fd, &stt) < 0) { NDA_ERR("fstat: %s", strerror(errno)); flock(fd, LOCK_UN); close(fd); return NULL; }
int is_new = (stt.st_size == 0);
if (!is_new && (uint64_t)stt.st_size < sizeof(struct NdaHeader)) {
NDA_ERR("%s: file too small (%lld)", path, (long long)stt.st_size);
flock(fd, LOCK_UN); close(fd); return NULL;
}
if (is_new && ftruncate(fd, (off_t)total) < 0) {
NDA_ERR("ftruncate: %s", strerror(errno)); flock(fd, LOCK_UN); close(fd); return NULL;
}
map_size = is_new ? (size_t)total : (size_t)stt.st_size;
base = mmap(NULL, map_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (base == MAP_FAILED) { NDA_ERR("mmap: %s", strerror(errno)); flock(fd, LOCK_UN); close(fd); return NULL; }
if (!is_new) {
if (!nda_validate_header((NdaHeader *)base, (uint64_t)stt.st_size)) {
NDA_ERR("invalid ndarray file"); munmap(base, map_size); flock(fd, LOCK_UN); close(fd); return NULL;
}
flock(fd, LOCK_UN); close(fd);
return nda_setup(base, map_size, path, -1);
}
}
nda_init_header(base, dtype, shape, ndim, size, strides, total);
if (fd >= 0) { flock(fd, LOCK_UN); close(fd); }
return nda_setup(base, map_size, path, -1);
}
static NdaHandle *nda_create_memfd(const char *name, int dtype,
const uint64_t *shape, uint32_t ndim, char *errbuf) {
uint64_t size, strides[NDA_MAX_DIMS], data_bytes;
( run in 1.981 second using v1.01-cache-2.11-cpan-600a1bdf6e4 )