[Python-checkins] CVS: python/dist/src/Modules selectmodule.c,2.42,2.43

A.M. Kuchling python-dev@python.org
Thu, 24 Aug 2000 18:15:37 -0700


Update of /cvsroot/python/python/dist/src/Modules
In directory slayer.i.sourceforge.net:/tmp/cvs-serv13765

Modified Files:
	selectmodule.c 
Log Message:
Add interface to poll() system call (SF patch #100852)


Index: selectmodule.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Modules/selectmodule.c,v
retrieving revision 2.42
retrieving revision 2.43
diff -C2 -r2.42 -r2.43
*** selectmodule.c	2000/07/31 15:28:04	2.42
--- selectmodule.c	2000/08/25 01:15:33	2.43
***************
*** 25,28 ****
--- 25,31 ----
  #include <limits.h>
  #endif
+ #ifdef HAVE_POLL_H
+ #include <poll.h>
+ #endif
  
  #ifdef __sgi
***************
*** 300,303 ****
--- 303,584 ----
  }
  
+ #ifdef HAVE_POLL
+ /* 
+  * poll() support
+  */
+ 
+ typedef struct {
+ 	PyObject_HEAD
+ 	PyObject *dict;
+ 	int ufd_uptodate; 
+ 	int ufd_len;
+         struct pollfd *ufds;
+ } pollObject;
+ 
+ staticforward PyTypeObject poll_Type;
+ 
+ /* Update the malloc'ed array of pollfds to match the dictionary 
+    contained within a pollObject.  Return 1 on success, 0 on an error.
+ */
+ 
+ static int
+ update_ufd_array(pollObject *self)
+ {
+ 	int i, j, pos;
+ 	PyObject *key, *value;
+ 
+ 	self->ufd_len = PyDict_Size(self->dict);
+ 	PyMem_Resize(self->ufds, struct pollfd, self->ufd_len);
+ 	if (self->ufds == NULL) {
+ 		PyErr_NoMemory();
+ 		return 0;
+ 	}
+ 
+ 	i = pos = 0;
+ 	while ((j = PyDict_Next(self->dict, &pos, &key, &value))) {
+ 		self->ufds[i].fd = PyInt_AsLong(key);
+ 		self->ufds[i].events = PyInt_AsLong(value);
+ 		i++;
+ 	}
+ 	self->ufd_uptodate = 1;
+ 	return 1;
+ }
+ 
+ static char poll_register_doc[] =
+ "register(fd [, eventmask] ) -> None\n\n\
+ Register a file descriptor with the polling object.\n\
+ fd -- either an integer, or an object with a fileno() method returning an int.\n\
+ events -- an optional bitmask describing the type of events to check for";
+ 
+ static PyObject *
+ poll_register(pollObject *self, PyObject *args) 
+ {
+ 	PyObject *o, *key, *value;
+ 	int fd, events = POLLIN | POLLPRI | POLLOUT;
+ 
+ 	if (!PyArg_ParseTuple(args, "O|i", &o, &events)) {
+ 		return NULL;
+ 	}
+   
+ 	fd = PyObject_AsFileDescriptor(o);
+ 	if (fd == -1) return NULL;
+ 
+ 	/* Add entry to the internal dictionary: the key is the 
+ 	   file descriptor, and the value is the event mask. */
+ 	if ( (NULL == (key = PyInt_FromLong(fd))) ||
+ 	     (NULL == (value = PyInt_FromLong(events))) ||
+ 	     (PyDict_SetItem(self->dict, key, value)) == -1) {
+ 		return NULL;
+ 	}
+ 	self->ufd_uptodate = 0;
+ 		       
+ 	Py_INCREF(Py_None);
+ 	return Py_None;
+ }
+ 
+ static char poll_unregister_doc[] =
+ "unregister(fd) -> None\n\n\
+ Remove a file descriptor being tracked by the polling object.";
+ 
+ static PyObject *
+ poll_unregister(pollObject *self, PyObject *args) 
+ {
+ 	PyObject *o, *key;
+ 	int fd;
+ 
+ 	if (!PyArg_ParseTuple(args, "O", &o)) {
+ 		return NULL;
+ 	}
+   
+ 	fd = PyObject_AsFileDescriptor( o );
+ 	if (fd == -1) 
+ 		return NULL;
+ 
+ 	/* Check whether the fd is already in the array */
+ 	key = PyInt_FromLong(fd);
+ 	if (key == NULL) 
+ 		return NULL;
+ 
+ 	if (PyDict_DelItem(self->dict, key) == -1) {
+ 		Py_DECREF(key);
+ 		/* This will simply raise the KeyError set by PyDict_DelItem
+ 		   if the file descriptor isn't registered. */
+ 		return NULL;
+ 	}
+ 
+ 	Py_DECREF(key);
+ 	self->ufd_uptodate = 0;
+ 
+ 	Py_INCREF(Py_None);
+ 	return Py_None;
+ }
+ 
+ static char poll_poll_doc[] =
+ "poll( [timeout] ) -> list of (fd, event) 2-tuples\n\n\
+ Polls the set of registered file descriptors, returning a list containing \n\
+ any descriptors that have events or errors to report.";
+ 
+ static PyObject *
+ poll_poll(pollObject *self, PyObject *args) 
+ {
+ 	PyObject *result_list = NULL, *tout = NULL;
+ 	int timeout = 0, poll_result, i, j;
+ 	PyObject *value = NULL, *num = NULL;
+ 
+ 	if (!PyArg_ParseTuple(args, "|O", &tout)) {
+ 		return NULL;
+ 	}
+ 
+ 	/* Check values for timeout */
+ 	if (tout == NULL || tout == Py_None)
+ 		timeout = -1;
+ 	else if (!PyArg_Parse(tout, "i", &timeout)) {
+ 		PyErr_SetString(PyExc_TypeError,
+ 				"timeout must be an integer or None");
+ 		return NULL;
+ 	}
+ 
+ 	/* Ensure the ufd array is up to date */
+ 	if (!self->ufd_uptodate) 
+ 		if (update_ufd_array(self) == 0)
+ 			return NULL;
+ 
+ 	/* call poll() */
+ 	Py_BEGIN_ALLOW_THREADS;
+ 	poll_result = poll(self->ufds, self->ufd_len, timeout);
+ 	Py_END_ALLOW_THREADS;
+  
+ 	if (poll_result < 0) {
+ 		PyErr_SetFromErrno(SelectError);
+ 		return NULL;
+ 	} 
+        
+ 	/* build the result list */
+   
+ 	result_list = PyList_New(poll_result);
+ 	if (!result_list) 
+ 		return NULL;
+ 	else {
+ 		for (i = 0, j = 0; j < poll_result; j++) {
+  			/* skip to the next fired descriptor */
+  			while (!self->ufds[i].revents) {
+  				i++;
+  			}
+ 			/* if we hit a NULL return, set value to NULL
+ 			   and break out of loop; code at end will
+ 			   clean up result_list */
+ 			value = PyTuple_New(2);
+ 			if (value == NULL)
+ 				goto error;
+ 			num = PyInt_FromLong(self->ufds[i].fd);
+ 			if (num == NULL) {
+ 				Py_DECREF(value);
+ 				goto error;
+ 			}
+ 			PyTuple_SET_ITEM(value, 0, num);
+ 
+ 			num = PyInt_FromLong(self->ufds[i].revents);
+ 			if (num == NULL) {
+ 				Py_DECREF(value);
+ 				goto error;
+ 			}
+ 			PyTuple_SET_ITEM(value, 1, num);
+  			if ((PyList_SetItem(result_list, j, value)) == -1) {
+ 				Py_DECREF(value);
+ 				goto error;
+  			}
+  			i++;
+  		}
+  	}
+  	return result_list;
+ 
+   error:
+ 	Py_DECREF(result_list);
+ 	return NULL;
+ }
+ 
+ static PyMethodDef poll_methods[] = {
+ 	{"register",	(PyCFunction)poll_register,	
+ 	 METH_VARARGS,  poll_register_doc},
+ 	{"unregister",	(PyCFunction)poll_unregister,	
+ 	 METH_VARARGS,  poll_unregister_doc},
+ 	{"poll",	(PyCFunction)poll_poll,	
+ 	 METH_VARARGS,  poll_poll_doc},
+ 	{NULL,		NULL}		/* sentinel */
+ };
+ 
+ static pollObject *
+ newPollObject()
+ {
+         pollObject *self;
+ 	self = PyObject_New(pollObject, &poll_Type);
+ 	if (self == NULL)
+ 		return NULL;
+ 	/* ufd_uptodate is a Boolean, denoting whether the 
+ 	   array pointed to by ufds matches the contents of the dictionary. */
+ 	self->ufd_uptodate = 0;
+ 	self->ufds = NULL;
+ 	self->dict = PyDict_New();
+ 	if (self->dict == NULL) {
+ 		Py_DECREF(self);
+ 		return NULL;
+ 	}
+ 	return self;
+ }
+ 
+ static void
+ poll_dealloc(pollObject *self)
+ {
+ 	if (self->ufds != NULL)
+ 		PyMem_DEL(self->ufds);
+ 	Py_XDECREF(self->dict);
+   	PyObject_Del(self);
+ }
+ 
+ static PyObject *
+ poll_getattr(pollObject *self, char *name)
+ {
+ 	return Py_FindMethod(poll_methods, (PyObject *)self, name);
+ }
+ 
+ statichere PyTypeObject poll_Type = {
+ 	/* The ob_type field must be initialized in the module init function
+ 	 * to be portable to Windows without using C++. */
+ 	PyObject_HEAD_INIT(NULL)
+ 	0,			/*ob_size*/
+ 	"poll",			/*tp_name*/
+ 	sizeof(pollObject),	/*tp_basicsize*/
+ 	0,			/*tp_itemsize*/
+ 	/* methods */
+ 	(destructor)poll_dealloc, /*tp_dealloc*/
+ 	0,			/*tp_print*/
+ 	(getattrfunc)poll_getattr, /*tp_getattr*/
+ 	0,                      /*tp_setattr*/
+ 	0,			/*tp_compare*/
+ 	0,			/*tp_repr*/
+ 	0,			/*tp_as_number*/
+ 	0,			/*tp_as_sequence*/
+ 	0,			/*tp_as_mapping*/
+ 	0,			/*tp_hash*/
+ };
+ 
+ static char poll_doc[] = 
+ "Returns a polling object, which supports registering and\n\
+ unregistering file descriptors, and then polling them for I/O events.";
+ 
+ static PyObject *
+ select_poll(PyObject *self, PyObject *args)
+ {
+ 	pollObject *rv;
+ 	
+ 	if (!PyArg_ParseTuple(args, ":poll"))
+ 		return NULL;
+ 	rv = newPollObject();
+ 	if ( rv == NULL )
+ 		return NULL;
+ 	return (PyObject *)rv;
+ }
+ #endif /* HAVE_POLL */
+ 
  static char select_doc[] =
  "select(rlist, wlist, xlist[, timeout]) -> (rlist, wlist, xlist)\n\
***************
*** 323,329 ****
  On Windows, only sockets are supported; on Unix, all file descriptors.";
  
- 
  static PyMethodDef select_methods[] = {
!     {"select",	select_select, 1, select_doc},
      {0,  	0},			     /* sentinel */
  };
--- 604,612 ----
  On Windows, only sockets are supported; on Unix, all file descriptors.";
  
  static PyMethodDef select_methods[] = {
!     {"select",	select_select, METH_VARARGS, select_doc},
! #ifdef HAVE_POLL
!     {"poll",    select_poll,   METH_VARARGS, poll_doc},
! #endif /* HAVE_POLL */
      {0,  	0},			     /* sentinel */
  };
***************
*** 335,338 ****
--- 618,640 ----
  On Windows, only sockets are supported; on Unix, all file descriptors.";
  
+ /*
+  * Convenience routine to export an integer value.
+  * For simplicity, errors (which are unlikely anyway) are ignored.
+  */
+ 
+ static void
+ insint(PyObject *d, char *name, int value)
+ {
+ 	PyObject *v = PyInt_FromLong((long) value);
+ 	if (v == NULL) {
+ 		/* Don't bother reporting this error */
+ 		PyErr_Clear();
+ 	}
+ 	else {
+ 		PyDict_SetItemString(d, name, v);
+ 		Py_DECREF(v);
+ 	}
+ }
+ 
  DL_EXPORT(void)
  initselect(void)
***************
*** 343,345 ****
--- 645,662 ----
  	SelectError = PyErr_NewException("select.error", NULL, NULL);
  	PyDict_SetItemString(d, "error", SelectError);
+ #ifdef HAVE_POLL
+ 	poll_Type.ob_type = &PyType_Type;
+ 	insint(d, "POLLIN", POLLIN);
+ 	insint(d, "POLLPRI", POLLPRI);
+ 	insint(d, "POLLOUT", POLLOUT);
+ 	insint(d, "POLLERR", POLLERR);
+ 	insint(d, "POLLHUP", POLLHUP);
+ 	insint(d, "POLLNVAL", POLLNVAL);
+ 
+ 	insint(d, "POLLRDNORM", POLLRDNORM);
+ 	insint(d, "POLLRDBAND", POLLRDBAND);
+ 	insint(d, "POLLWRNORM", POLLWRNORM);
+ 	insint(d, "POLLWRBAND", POLLWRBAND);
+ 	insint(d, "POLLMSG", POLLMSG);
+ #endif /* HAVE_POLL */
  }