Commit 00b93dae authored by Kirill Kouzoubov's avatar Kirill Kouzoubov
Browse files

Use mmap only, no reads or seek

At least on a mac `lseek` and `read` fail when operating on a shared memory file
descriptor. Seems like POSIX only promises resize and memory map, but not read
or seek.

Also on a mac resizing shared memory file rounds up to nearest 4K, so we have to
query actual file size after resize before writing header information to the end
of the file.
parent 994285c0
Loading
Loading
Loading
Loading
+20 −20
Original line number Diff line number Diff line
@@ -34,8 +34,9 @@
 */
static PyObject *do_attach(const char *name)
{
	struct array_meta meta;
	struct array_meta *meta;
	int fd;
	struct stat file_info;
	size_t map_size;
	void *map_addr;
	PyObject *array;
@@ -45,43 +46,42 @@ static PyObject *do_attach(const char *name)
	if ((fd = open_file(name, O_RDWR, 0)) < 0)
		return PyErr_SetFromErrnoWithFilename(PyExc_OSError, name);

	/* Seek to the meta data location */
	if (lseek(fd, -sizeof (meta), SEEK_END) < 0) {
	if ( fstat(fd, &file_info) < 0 ) {
		close(fd);
		return PyErr_SetFromErrnoWithFilename(PyExc_OSError, name);
	}

	/* Read the meta data structure */
	if (read(fd, &meta, sizeof (meta)) != sizeof (meta)) {
	if (file_info.st_size < sizeof(*meta)) {
		close(fd);
		return PyErr_SetFromErrnoWithFilename(PyExc_OSError, name);
		PyErr_SetString(PyExc_IOError, "No SharedArray at this address");
		return NULL;
	}
	map_size = file_info.st_size;

	/* Check the meta data */
	if (strncmp(meta.magic, SHARED_ARRAY_MAGIC, sizeof (meta.magic))) {
	/* Map the array data */
	map_addr = mmap(NULL, map_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
	close(fd);
	if (map_addr == MAP_FAILED)
		return PyErr_SetFromErrnoWithFilename(PyExc_OSError, name);

	meta = (struct array_meta *) (map_addr + (map_size - sizeof(*meta)));

	/* Check the meta data */
	if (strncmp(meta->magic, SHARED_ARRAY_MAGIC, sizeof (meta->magic))) {
		munmap(map_addr, map_size);
		PyErr_SetString(PyExc_IOError, "No SharedArray at this address");
		return NULL;
	}

	/* Check the number of dimensions */
	if (meta.ndims > NPY_MAXDIMS) {
		close(fd);
	if (meta->ndims > NPY_MAXDIMS) {
		munmap(map_addr, map_size);
		PyErr_Format(PyExc_ValueError,
			     "number of dimensions must be within [0, %d]",
			     NPY_MAXDIMS);
		return NULL;
	}

	/* Calculate the size of the mmap'd area */
	map_size = meta.size + sizeof (meta);

	/* Map the array data */
	map_addr = mmap(NULL, map_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
	close(fd);
	if (map_addr == MAP_FAILED)
		return PyErr_SetFromErrnoWithFilename(PyExc_OSError, name);

	/* Hand over the memory map to a MapOwner instance */
	map_owner = PyObject_MALLOC(sizeof (*map_owner));
	PyObject_INIT((PyObject *) map_owner, &PyMapOwner_Type);
@@ -89,7 +89,7 @@ static PyObject *do_attach(const char *name)
	map_owner->map_size = map_size;

	/* Create the array object */
	array = PyArray_SimpleNewFromData(meta.ndims, meta.dims, meta.typenum, map_addr);
	array = PyArray_SimpleNewFromData(meta->ndims, meta->dims, meta->typenum, map_addr);

	/* Attach MapOwner to the array */
	PyArray_SetBaseObject((PyArrayObject *) array, (PyObject *) map_owner);
+9 −1
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ static PyObject *do_create(const char *name, int ndims, npy_intp *dims, PyArray_
	void *map_addr;
	int i;
	int fd;
	struct stat file_info;
	PyObject *array;
	PyMapOwnerObject *map_owner;

@@ -69,6 +70,13 @@ static PyObject *do_create(const char *name, int ndims, npy_intp *dims, PyArray_
		return PyErr_SetFromErrnoWithFilename(PyExc_OSError, name);
	}

	/* Find actual file size after growing (on some systems it rounds up to 4K)*/
	if ( fstat(fd, &file_info) < 0 ) {
		close(fd);
		return PyErr_SetFromErrnoWithFilename(PyExc_OSError, name);
	}
	map_size = file_info.st_size;

	/* Map it */
	map_addr = mmap(NULL, map_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
	close(fd);
@@ -76,7 +84,7 @@ static PyObject *do_create(const char *name, int ndims, npy_intp *dims, PyArray_
		return PyErr_SetFromErrnoWithFilename(PyExc_OSError, name);

	/* Append meta-data to the array in memory */
	meta = (struct array_meta *) (map_addr + size);
	meta = (struct array_meta *) (map_addr + (map_size - sizeof(*meta)));
	strncpy(meta->magic, SHARED_ARRAY_MAGIC, sizeof (meta->magic));
	meta->size = size;
	meta->typenum = dtype->type_num;
+18 −15
Original line number Diff line number Diff line
@@ -32,39 +32,42 @@
 */
static PyObject *do_delete(const char *name)
{
	struct array_meta meta;
	struct array_meta *meta;
	int fd;
	int size;
	struct stat file_info;
	size_t map_size;
	void *map_addr;

	/* Open the file */
	if ((fd = open_file(name, O_RDWR, 0)) < 0)
		return PyErr_SetFromErrnoWithFilename(PyExc_OSError, name);

	/* Seek to the meta data location */
	if (lseek(fd, -sizeof (meta), SEEK_END) < 0) {
	if ( fstat(fd, &file_info) < 0 ) {
		close(fd);
		return PyErr_SetFromErrnoWithFilename(PyExc_OSError, name);
	}

	/* Read the meta data structure */
	size = read(fd, &meta, sizeof (meta));
	if (file_info.st_size < sizeof(*meta)) {
		close(fd);
		PyErr_SetString(PyExc_IOError, "No SharedArray at this address (too small)");
		return NULL;
	}
	map_size = file_info.st_size;

	/* Catch read errors */
	if (size <= 0)
	/* Map whole file into memory */
	map_addr = mmap(NULL, map_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
	close(fd);
	if (map_addr == MAP_FAILED)
		return PyErr_SetFromErrnoWithFilename(PyExc_OSError, name);

	/* Catch short reads */
	if (size != sizeof (meta)) {
		PyErr_SetString(PyExc_IOError, "No SharedArray at this address");
		return NULL;
	}
	meta = (struct array_meta *) (map_addr + (map_size - sizeof(*meta)));

	/* Check the meta data */
	if (strncmp(meta.magic, SHARED_ARRAY_MAGIC, sizeof (meta.magic))) {
	if (strncmp(meta->magic, SHARED_ARRAY_MAGIC, sizeof (meta->magic))) {
		PyErr_SetString(PyExc_IOError, "No SharedArray at this address");
		return NULL;
	}
	munmap(map_addr, map_size);

	/* Unlink the file */
	if (unlink_file(name) < 0)