[NeoStats-Devel] [Commits] r2411 - trunk/lib/event

[email protected]
Newsgroups gmane.comp.neostats.devel
Message-ID <[email protected]>
Author: Fish
Date: Thu Mar 31 19:04:16 2005
New Revision: 2411

Modified:
   trunk/lib/event/devpoll.c
Log:
updates to the devpoll interface from the libevent package

Modified: trunk/lib/event/devpoll.c
==============================================================================
--- trunk/lib/event/devpoll.c	(original)
+++ trunk/lib/event/devpoll.c	Thu Mar 31 19:04:16 2005
@@ -73,6 +73,8 @@
 	int nevents;
 	int dpfd;
 	sigset_t evsigmask;
+	struct pollfd *changes;
+	int nchanges;
 };
 
 void *devpoll_init	(void);
@@ -92,6 +94,42 @@
 
 #define NEVENT	32000
 
+static int
+devpoll_commit(struct devpollop *devpollop)
+{
+	/*
+	 * Due to a bug in Solaris, we have to use pwrite with an offset of 0.
+	 * Write is limited to 2GB of data, until it will fail.
+	 */
+	if (pwrite(devpollop->dpfd, devpollop->changes,
+		sizeof(struct pollfd) * devpollop->nchanges, 0) == -1)
+		return(-1);
+
+	devpollop->nchanges = 0;
+	return(0);
+}
+
+static int
+devpoll_queue(struct devpollop *devpollop, int fd, int events) {
+	struct pollfd *pfd;
+
+	if (devpollop->nchanges >= devpollop->nevents) {
+		/*
+		 * Change buffer is full, must commit it to /dev/poll before 
+		 * adding more 
+		 */
+		if (devpoll_commit(devpollop) != 0)
+			return(-1);
+	}
+
+	pfd = &devpollop->changes[devpollop->nchanges++];
+	pfd->fd = fd;
+	pfd->events = events;
+	pfd->revents = 0;
+
+	return(0);
+}
+
 void *
 devpoll_init(void)
 {
@@ -137,6 +175,15 @@
 	}
 	devpollop->nfds = nfiles;
 
+	devpollop->changes = calloc(nfiles, sizeof(struct pollfd));
+	if (devpollop->changes == NULL) {
+		free(devpollop->fds);
+		free(devpollop->events);
+		free(devpollop);
+		close(dpfd);
+		return (NULL);
+	}
+
 	evsignal_init(&devpollop->evsigmask);
 
 	return (devpollop);
@@ -181,6 +228,9 @@
 	if (evsignal_deliver(&devpollop->evsigmask) == -1)
 		return (-1);
 
+	if (devpollop->nchanges)
+		devpoll_commit(devpollop);
+
 	timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
 
 	dvp.dp_fds = devpollop->events;
@@ -251,7 +301,6 @@
 devpoll_add(void *arg, struct event *ev)
 {
 	struct devpollop *devpollop = arg;
-	struct pollfd dpev;
 	struct evdevpoll *evdp;
 	int fd, events;
 
@@ -266,28 +315,32 @@
 	}
 	evdp = &devpollop->fds[fd];
 
+	/* 
+	 * It's not necessary to OR the existing read/write events that we
+	 * are currently interested in with the new event we are adding.
+	 * The /dev/poll driver ORs any new events with the existing events
+	 * that it has cached for the fd.
+	 */
+
 	events = 0;
-	if (evdp->evread != NULL) {
+	if (ev->ev_events & EV_READ) {
+		if (evdp->evread && evdp->evread != ev) {
+		   /* There is already a different read event registered */
+		   return(-1);
+		}
 		events |= POLLIN;
 	}
-	if (evdp->evwrite != NULL) {
-		events |= POLLOUT;
-	}
 
-	if (ev->ev_events & EV_READ)
-		events |= POLLIN;
-	if (ev->ev_events & EV_WRITE)
+	if (ev->ev_events & EV_WRITE) {
+		if (evdp->evwrite && evdp->evwrite != ev) {
+		   /* There is already a different write event registered */
+		   return(-1);
+		}
 		events |= POLLOUT;
+	}
 
-	dpev.fd = fd;
-	dpev.events = events;
-	dpev.revents = 0;
-	/*
-	 * Due to a bug in Solaris, we have to use pwrite with an offset of 0.
-	 * Write is limited to 2GB of data, until it will fail.
-	 */
-	if (pwrite(devpollop->dpfd, &dpev, sizeof(dpev), 0) == -1)
-			return (-1);
+	if (devpoll_queue(devpollop, fd, events) != 0)
+		return(-1);
 
 	/* Update events responsible */
 	if (ev->ev_events & EV_READ)
@@ -302,9 +355,8 @@
 devpoll_del(void *arg, struct event *ev)
 {
 	struct devpollop *devpollop = arg;
-	struct pollfd dpev;
 	struct evdevpoll *evdp;
-	int fd, events, op;
+	int fd, events;
 	int needwritedelete = 1, needreaddelete = 1;
 
 	if (ev->ev_events & EV_SIGNAL)
@@ -321,24 +373,33 @@
 	if (ev->ev_events & EV_WRITE)
 		events |= POLLOUT;
 
+	/*
+	 * The only way to remove an fd from the /dev/poll monitored set is
+	 * to use POLLREMOVE by itself.  This removes ALL events for the fd 
+	 * provided so if we care about two events and are only removing one 
+	 * we must re-add the other event after POLLREMOVE.
+	 */
+
+	if (devpoll_queue(devpollop, fd, POLLREMOVE) != 0)
+		return(-1);
+
 	if ((events & (POLLIN|POLLOUT)) != (POLLIN|POLLOUT)) {
+		/*
+		 * We're not deleting all events, so we must resubmit the
+		 * event that we are still interested in if one exists.
+		 */
+
 		if ((events & POLLIN) && evdp->evwrite != NULL) {
+			/* Deleting read, still care about write */
+			devpoll_queue(devpollop, fd, POLLOUT);
 			needwritedelete = 0;
-			events = POLLOUT;
 		} else if ((events & POLLOUT) && evdp->evread != NULL) {
+			/* Deleting write, still care about read */
+			devpoll_queue(devpollop, fd, POLLIN);
 			needreaddelete = 0;
-			events = POLLIN;
 		}
 	}
 
-	dpev.fd = fd;
-	/* dpev.events = events | POLLREMOVE; */
-	dpev.events = POLLREMOVE;
-	dpev.revents = 0;
-
-	if (pwrite(devpollop->dpfd, &dpev, sizeof(dpev), 0) == -1)
-		return (-1);
-
 	if (needreaddelete)
 		evdp->evread = NULL;
 	if (needwritedelete)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.