[Python-checkins] CVS: python/dist/src/Modules mmapmodule.c,2.33,2.34

Tim Peters tim_one@users.sourceforge.net
Tue, 13 Nov 2001 15:11:21 -0800


Update of /cvsroot/python/python/dist/src/Modules
In directory usw-pr-cvs1:/tmp/cvs-serv31339/python/Modules

Modified Files:
	mmapmodule.c 
Log Message:
CVS patch #477161:  New "access" keyword for mmap, from Jay T Miller.
This gives mmap() on Windows the ability to create read-only, write-
through and copy-on-write mmaps.  A new keyword argument is introduced
because the mmap() signatures diverged between Windows and Unix, so
while they (now) both support this functionality, there wasn't a way to
spell it in a common way without introducing a new spelling gimmick.
The old spellings are still accepted, so there isn't a backward-
compatibility issue here.


Index: mmapmodule.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Modules/mmapmodule.c,v
retrieving revision 2.33
retrieving revision 2.34
diff -C2 -d -r2.33 -r2.34
*** mmapmodule.c	2001/11/05 21:22:41	2.33
--- mmapmodule.c	2001/11/13 23:11:19	2.34
***************
*** 30,36 ****
  my_getpagesize(void)
  {
!     SYSTEM_INFO si;
!     GetSystemInfo(&si);
!     return si.dwPageSize;
  }
  #endif
--- 30,36 ----
  my_getpagesize(void)
  {
! 	SYSTEM_INFO si;
! 	GetSystemInfo(&si);
! 	return si.dwPageSize;
  }
  #endif
***************
*** 50,54 ****
  my_getpagesize(void)
  {
!     return sysconf(_SC_PAGESIZE);
  }
  #else
--- 50,54 ----
  my_getpagesize(void)
  {
! 	return sysconf(_SC_PAGESIZE);
  }
  #else
***************
*** 63,66 ****
--- 63,74 ----
  static PyObject *mmap_module_error;
  
+ typedef enum
+ {
+ 	ACCESS_DEFAULT,
+ 	ACCESS_READ,
+ 	ACCESS_WRITE,
+ 	ACCESS_COPY
+ } access_mode;
+ 
  typedef struct {
  	PyObject_HEAD
***************
*** 78,83 ****
--- 86,94 ----
          int fd;
  #endif
+ 
+         access_mode access;
  } mmap_object;
  
+ 
  static void
  mmap_object_dealloc(mmap_object *m_obj)
***************
*** 179,183 ****
  static PyObject *
  mmap_read_line_method(mmap_object *self,
! 		     PyObject *args)
  {
  	char *start = self->data+self->pos;
--- 190,194 ----
  static PyObject *
  mmap_read_line_method(mmap_object *self,
! 		      PyObject *args)
  {
  	char *start = self->data+self->pos;
***************
*** 237,245 ****
  
                  if (start < 0)
!                     start += self->size;
                  if (start < 0)
!                     start = 0;
                  else if ((size_t)start > self->size)
!                     start = self->size;
                  p = self->data + start;
  
--- 248,256 ----
  
                  if (start < 0)
! 			start += self->size;
                  if (start < 0)
! 			start = 0;
                  else if ((size_t)start > self->size)
! 			start = self->size;
                  p = self->data + start;
  
***************
*** 261,264 ****
--- 272,295 ----
  }
  
+ static int 
+ is_writeable(mmap_object *self)
+ {
+ 	if (self->access != ACCESS_READ)
+ 		return 1; 
+ 	PyErr_Format(PyExc_TypeError, "mmap can't modify a readonly memory map.");
+ 	return 0;
+ }
+ 
+ static int 
+ is_resizeable(mmap_object *self)
+ {
+ 	if ((self->access == ACCESS_WRITE) || (self->access == ACCESS_DEFAULT))
+ 		return 1; 
+ 	PyErr_Format(PyExc_TypeError, 
+ 		     "mmap can't resize a readonly or copy-on-write memory map.");
+ 	return 0;
+ }
+ 
+ 
  static PyObject *
  mmap_write_method(mmap_object *self,
***************
*** 272,275 ****
--- 303,309 ----
  		return(NULL);
  
+ 	if (!is_writeable(self))
+ 		return NULL;
+ 
  	if ((self->pos + length) > self->size) {
  		PyErr_SetString (PyExc_ValueError, "data out of range");
***************
*** 292,295 ****
--- 326,331 ----
  		return(NULL);
  
+ 	if (!is_writeable(self))
+ 		return NULL;
  	*(self->data+self->pos) = value;
  	self->pos += 1;
***************
*** 297,301 ****
  	return (Py_None);
  }
! 
  static PyObject *
  mmap_size_method(mmap_object *self,
--- 333,337 ----
  	return (Py_None);
  }
!  
  static PyObject *
  mmap_size_method(mmap_object *self,
***************
*** 343,347 ****
  	unsigned long new_size;
  	CHECK_VALID(NULL);
! 	if (!PyArg_ParseTuple (args, "l:resize", &new_size)) {
  		return NULL;
  #ifdef MS_WIN32
--- 379,384 ----
  	unsigned long new_size;
  	CHECK_VALID(NULL);
! 	if (!PyArg_ParseTuple (args, "l:resize", &new_size) || 
! 	    !is_resizeable(self)) {
  		return NULL;
  #ifdef MS_WIN32
***************
*** 387,415 ****
  #ifdef UNIX
  #ifndef HAVE_MREMAP 
! } else {
! 	PyErr_SetString(PyExc_SystemError,
! 			"mmap: resizing not available--no mremap()");
! 	return NULL;
  #else
! } else {
! 	void *newmap;
  
  #ifdef MREMAP_MAYMOVE
! 	newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
  #else
! 	newmap = mremap(self->data, self->size, new_size, 0);
  #endif
! 	if (newmap == (void *)-1) 
! 	{
! 		PyErr_SetFromErrno(mmap_module_error);
! 		return NULL;
! 	}
! 	self->data = newmap;
! 	self->size = new_size;
! 	Py_INCREF(Py_None);
! 	return Py_None;
  #endif /* HAVE_MREMAP */
  #endif /* UNIX */
! }
  }
  
--- 424,452 ----
  #ifdef UNIX
  #ifndef HAVE_MREMAP 
! 	} else {
! 		PyErr_SetString(PyExc_SystemError,
! 				"mmap: resizing not available--no mremap()");
! 		return NULL;
  #else
! 	} else {
! 		void *newmap;
  
  #ifdef MREMAP_MAYMOVE
! 		newmap = mremap(self->data, self->size, new_size, MREMAP_MAYMOVE);
  #else
! 		newmap = mremap(self->data, self->size, new_size, 0);
  #endif
! 		if (newmap == (void *)-1) 
! 		{
! 			PyErr_SetFromErrno(mmap_module_error);
! 			return NULL;
! 		}
! 		self->data = newmap;
! 		self->size = new_size;
! 		Py_INCREF(Py_None);
! 		return Py_None;
  #endif /* HAVE_MREMAP */
  #endif /* UNIX */
! 	}
  }
  
***************
*** 492,496 ****
  	}
  
! onoutofrange:
  	PyErr_SetString (PyExc_ValueError, "seek out of range");
  	return NULL;
--- 529,533 ----
  	}
  
!   onoutofrange:
  	PyErr_SetString (PyExc_ValueError, "seek out of range");
  	return NULL;
***************
*** 502,506 ****
  	unsigned long dest, src, count;
  	CHECK_VALID(NULL);
! 	if (!PyArg_ParseTuple (args, "iii:move", &dest, &src, &count)) {
  		return NULL;
  	} else {
--- 539,544 ----
  	unsigned long dest, src, count;
  	CHECK_VALID(NULL);
! 	if (!PyArg_ParseTuple (args, "iii:move", &dest, &src, &count) ||
! 	    !is_writeable(self)) {
  		return NULL;
  	} else {
***************
*** 562,565 ****
--- 600,605 ----
  		return -1;
  	}
+ 	if (!is_writeable(self))
+ 		return -1;
  	*ptr = self->data;
  	return self->size;
***************
*** 666,670 ****
  	if (v == NULL) {
  		PyErr_SetString(PyExc_TypeError,
! 			"mmap object doesn't support slice deletion");
  		return -1;
  	}
--- 706,710 ----
  	if (v == NULL) {
  		PyErr_SetString(PyExc_TypeError,
! 				"mmap object doesn't support slice deletion");
  		return -1;
  	}
***************
*** 679,682 ****
--- 719,724 ----
  		return -1;
  	}
+ 	if (!is_writeable(self))
+ 		return -1;
  	buf = PyString_AsString(v);
  	memcpy(self->data + ilow, buf, ihigh-ilow);
***************
*** 696,707 ****
  	if (v == NULL) {
  		PyErr_SetString(PyExc_TypeError,
! 			"mmap object doesn't support item deletion");
  		return -1;
  	}
  	if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
  		PyErr_SetString(PyExc_IndexError, 
! 			"mmap assignment must be single-character string");
  		return -1;
  	}
  	buf = PyString_AsString(v);
  	self->data[i] = buf[0];
--- 738,751 ----
  	if (v == NULL) {
  		PyErr_SetString(PyExc_TypeError,
! 				"mmap object doesn't support item deletion");
  		return -1;
  	}
  	if (! (PyString_Check(v) && PyString_Size(v)==1) ) {
  		PyErr_SetString(PyExc_IndexError, 
! 				"mmap assignment must be single-character string");
  		return -1;
  	}
+ 	if (!is_writeable(self))
+ 		return -1;
  	buf = PyString_AsString(v);
  	self->data[i] = buf[0];
***************
*** 793,808 ****
  	else {
  		PyErr_SetString(PyExc_TypeError,
! 			"map size must be an integral value");
  		return -1;
  	}
  
! onnegoverflow:
  	PyErr_SetString(PyExc_OverflowError,
! 		"memory mapped size must be positive");
  	return -1;
  
! onposoverflow:
  	PyErr_SetString(PyExc_OverflowError,
! 		"memory mapped size is too large (limited by C int)");
  	return -1;
  }
--- 837,852 ----
  	else {
  		PyErr_SetString(PyExc_TypeError,
! 				"map size must be an integral value");
  		return -1;
  	}
  
!   onnegoverflow:
  	PyErr_SetString(PyExc_OverflowError,
! 			"memory mapped size must be positive");
  	return -1;
  
!   onposoverflow:
  	PyErr_SetString(PyExc_OverflowError,
! 			"memory mapped size is too large (limited by C int)");
  	return -1;
  }
***************
*** 816,829 ****
  	int map_size;
  	int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
! 	char *keywords[] = {"file", "size", "flags", "prot", NULL};
  
! 	if (!PyArg_ParseTupleAndKeywords(args, kwdict, 
! 					 "iO|ii", keywords, 
! 					 &fd, &map_size_obj, &flags, &prot)
! 		)
  		return NULL;
  	map_size = _GetMapSize(map_size_obj);
  	if (map_size < 0)
  		return NULL;
  	
  	m_obj = PyObject_New (mmap_object, &mmap_object_type);
--- 860,899 ----
  	int map_size;
  	int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
! 	access_mode access = ACCESS_DEFAULT;
! 	char *keywords[] = {"fileno", "length", 
! 			    "flags", "prot", 
! 			    "access", NULL};
  
! 	if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|iii", keywords, 
! 					 &fd, &map_size_obj, &flags, &prot, &access))
  		return NULL;
  	map_size = _GetMapSize(map_size_obj);
  	if (map_size < 0)
  		return NULL;
+ 
+ 	if ((access != ACCESS_DEFAULT) && 
+ 	    ((flags != MAP_SHARED) || ( prot != (PROT_WRITE | PROT_READ))))
+ 		return PyErr_Format(PyExc_ValueError, 
+ 				    "mmap can't specify both access and flags, prot.");
+ 	switch(access) {
+ 	case ACCESS_READ:
+ 		flags = MAP_SHARED;
+ 		prot = PROT_READ;
+ 		break;
+ 	case ACCESS_WRITE:
+ 		flags = MAP_SHARED;
+ 		prot = PROT_READ | PROT_WRITE;
+ 		break;
+ 	case ACCESS_COPY:
+ 		flags = MAP_PRIVATE;
+ 		prot = PROT_READ | PROT_WRITE;
+ 		break;
+ 	case ACCESS_DEFAULT: 
+ 		/* use the specified or default values of flags and prot */
+ 		break;
+ 	default:
+ 		return PyErr_Format(PyExc_ValueError, 
+ 				    "mmap invalid access parameter.");
+ 	}
  	
  	m_obj = PyObject_New (mmap_object, &mmap_object_type);
***************
*** 835,844 ****
  			   prot, flags,
  			   fd, 0);
! 	if (m_obj->data == (char *)-1)
! 	{
  		Py_DECREF(m_obj);
  		PyErr_SetFromErrno(mmap_module_error);
  		return NULL;
  	}
  	return (PyObject *)m_obj;
  }
--- 905,914 ----
  			   prot, flags,
  			   fd, 0);
! 	if (m_obj->data == (char *)-1) {
  		Py_DECREF(m_obj);
  		PyErr_SetFromErrno(mmap_module_error);
  		return NULL;
  	}
+ 	m_obj->access = access;
  	return (PyObject *)m_obj;
  }
***************
*** 847,851 ****
  #ifdef MS_WIN32
  static PyObject *
! new_mmap_object(PyObject *self, PyObject *args)
  {
  	mmap_object *m_obj;
--- 917,921 ----
  #ifdef MS_WIN32
  static PyObject *
! new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
  {
  	mmap_object *m_obj;
***************
*** 853,869 ****
  	int map_size;
  	char *tagname = "";
- 
  	DWORD dwErr = 0;
  	int fileno;
  	HANDLE fh = 0;
  
! 	if (!PyArg_ParseTuple(args,
! 			  "iO|z",
! 			  &fileno,
! 			  &map_size_obj,
! 			  &tagname)
! 		)
  		return NULL;
!   
  	map_size = _GetMapSize(map_size_obj);
  	if (map_size < 0)
--- 923,959 ----
  	int map_size;
  	char *tagname = "";
  	DWORD dwErr = 0;
  	int fileno;
  	HANDLE fh = 0;
+ 	access_mode   access = ACCESS_DEFAULT;
+ 	DWORD flProtect, dwDesiredAccess;
+ 	char *keywords[] = { "fileno", "length", 
+ 			     "tagname", 
+ 			     "access", NULL };
  
! 	if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iO|zi", keywords,
! 					 &fileno, &map_size_obj, 
! 					 &tagname, &access)) {
  		return NULL;
! 	}
! 
! 	switch(access) {
! 	case ACCESS_READ:
! 		flProtect = PAGE_READONLY;
! 		dwDesiredAccess = FILE_MAP_READ;
! 		break;
! 	case ACCESS_DEFAULT:  case ACCESS_WRITE:
! 		flProtect = PAGE_READWRITE;
! 		dwDesiredAccess = FILE_MAP_WRITE;
! 		break;
! 	case ACCESS_COPY:
! 		flProtect = PAGE_WRITECOPY;
! 		dwDesiredAccess = FILE_MAP_COPY;
! 		break;
! 	default:
! 		return PyErr_Format(PyExc_ValueError, 
! 				    "mmap invalid access parameter.");
! 	}
! 
  	map_size = _GetMapSize(map_size_obj);
  	if (map_size < 0)
***************
*** 874,879 ****
  		fh = (HANDLE)_get_osfhandle(fileno);
  		if (fh==(HANDLE)-1) {
! 		    PyErr_SetFromErrno(mmap_module_error);
! 		    return NULL;
  		}
  		/* Win9x appears to need us seeked to zero */
--- 964,969 ----
  		fh = (HANDLE)_get_osfhandle(fileno);
  		if (fh==(HANDLE)-1) {
! 			PyErr_SetFromErrno(mmap_module_error);
! 			return NULL;
  		}
  		/* Win9x appears to need us seeked to zero */
***************
*** 895,905 ****
  		   Python code can close it on us */
  		if (!DuplicateHandle(
! 			    GetCurrentProcess(), /* source process handle */
! 			    fh, /* handle to be duplicated */
! 			    GetCurrentProcess(), /* target proc handle */
! 			    (LPHANDLE)&m_obj->file_handle, /* result */
! 			    0, /* access - ignored due to options value */
! 			    FALSE, /* inherited by child processes? */
! 			    DUPLICATE_SAME_ACCESS)) { /* options */
  			dwErr = GetLastError();
  			Py_DECREF(m_obj);
--- 985,995 ----
  		   Python code can close it on us */
  		if (!DuplicateHandle(
! 			GetCurrentProcess(), /* source process handle */
! 			fh, /* handle to be duplicated */
! 			GetCurrentProcess(), /* target proc handle */
! 			(LPHANDLE)&m_obj->file_handle, /* result */
! 			0, /* access - ignored due to options value */
! 			FALSE, /* inherited by child processes? */
! 			DUPLICATE_SAME_ACCESS)) { /* options */
  			dwErr = GetLastError();
  			Py_DECREF(m_obj);
***************
*** 933,939 ****
  		m_obj->tagname = NULL;
  
  	m_obj->map_handle = CreateFileMapping (m_obj->file_handle,
  					       NULL,
! 					       PAGE_READWRITE,
  					       0,
  					       m_obj->size,
--- 1023,1030 ----
  		m_obj->tagname = NULL;
  
+ 	m_obj->access = access;
  	m_obj->map_handle = CreateFileMapping (m_obj->file_handle,
  					       NULL,
! 					       flProtect,
  					       0,
  					       m_obj->size,
***************
*** 941,945 ****
  	if (m_obj->map_handle != NULL) {
  		m_obj->data = (char *) MapViewOfFile (m_obj->map_handle,
! 						      FILE_MAP_WRITE,
  						      0,
  						      0,
--- 1032,1036 ----
  	if (m_obj->map_handle != NULL) {
  		m_obj->data = (char *) MapViewOfFile (m_obj->map_handle,
! 						      dwDesiredAccess,
  						      0,
  						      0,
***************
*** 948,952 ****
  			return ((PyObject *) m_obj);
  		} else {
! 		    dwErr = GetLastError();
  		}
  	} else {
--- 1039,1043 ----
  			return ((PyObject *) m_obj);
  		} else {
! 			dwErr = GetLastError();
  		}
  	} else {
***************
*** 967,971 ****
  
  DL_EXPORT(void)
! initmmap(void)
  {
  	PyObject *dict, *module;
--- 1058,1062 ----
  
  DL_EXPORT(void)
! 	initmmap(void)
  {
  	PyObject *dict, *module;
***************
*** 1012,1015 ****
  	PyDict_SetItemString (dict, "PAGESIZE",
  			      PyInt_FromLong( (long)my_getpagesize() ) );
- }
  
--- 1103,1112 ----
  	PyDict_SetItemString (dict, "PAGESIZE",
  			      PyInt_FromLong( (long)my_getpagesize() ) );
  
+ 	PyDict_SetItemString (dict, "ACCESS_READ",	
+ 			      PyInt_FromLong(ACCESS_READ));
+ 	PyDict_SetItemString (dict, "ACCESS_WRITE", 
+ 			      PyInt_FromLong(ACCESS_WRITE));
+ 	PyDict_SetItemString (dict, "ACCESS_COPY",	
+ 			      PyInt_FromLong(ACCESS_COPY));
+ }