move poll compat func to .c file, make fd_set runtime resizeable
authorMarko Kreen <markokr@gmail.com>
Wed, 2 Jan 2008 09:32:58 +0000 (09:32 +0000)
committerMarko Kreen <markokr@gmail.com>
Wed, 2 Jan 2008 09:32:58 +0000 (09:32 +0000)
Makefile
src/poll_compat.c [new file with mode: 0644]
src/poll_compat.h

index b715a55a0c479c4f07e5363175fcf9fa02ff2ae6..39cd5f555b2e2c157a161d88a96921316db7e92a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -12,7 +12,7 @@ BISON = bison
 # module setup
 MODULE_big = plproxy
 SRCS = src/cluster.c src/execute.c src/function.c src/main.c \
-       src/query.c src/result.c src/type.c
+       src/query.c src/result.c src/type.c src/poll_compat.c
 OBJS = src/scanner.o src/parser.tab.o $(SRCS:.c=.o)
 DATA_built = plproxy.sql
 EXTRA_CLEAN = src/scanner.[ch] src/parser.tab.[ch]
@@ -51,6 +51,7 @@ src/scanner.c: src/scanner.l
 # dependencies
 $(OBJS): src/plproxy.h src/rowstamp.h
 src/execute.o: src/poll_compat.h
+src/poll_compat.o: src/poll_compat.h
 
 # utility rules
 
diff --git a/src/poll_compat.c b/src/poll_compat.c
new file mode 100644 (file)
index 0000000..fa180da
--- /dev/null
@@ -0,0 +1,128 @@
+
+#include "postgres.h"
+
+#include "poll_compat.h"
+
+#ifdef PLPROXY_POLL_COMPAT
+
+/*
+ * Emulate poll() with select()
+ */
+
+#include <sys/time.h>
+#include <sys/select.h>
+
+/*
+ * dynamic buffer for fd_set to avoid depending on FD_SETSIZE
+ */
+
+struct fd_buf {
+       fd_set *set;
+       int alloc_bytes;
+};
+
+static void fdbuf_zero(struct fd_buf *buf)
+{
+       if (buf->set)
+               memset(buf->set, 0, buf->alloc_bytes);
+}
+
+static bool fdbuf_resize(struct fd_buf *buf, int fd)
+{
+       /* get some extra room for quaranteed alignment */
+       int need_bytes = fd/8 + 32;
+       /* default - 2048 fds */
+       int alloc = 256;
+       uint8 *ptr;
+
+       if (buf->alloc_bytes < need_bytes)
+       {
+               while (alloc < need_bytes)
+                       alloc *= 2;
+
+               if (!buf->set)
+                       ptr = malloc(alloc);
+               else
+                       ptr = realloc(buf->set, alloc);
+
+               if (!ptr)
+                       return false;
+
+               /* clean new area */
+               memset(ptr + buf->alloc_bytes, 0, alloc - buf->alloc_bytes);
+
+               buf->set = (fd_set *)ptr;
+               buf->alloc_bytes = alloc;
+       }
+       return true;
+}
+
+int poll(struct pollfd *fds, nfds_t nfds, int timeout_ms)
+{
+       static struct fd_buf readfds = { NULL, 0 };
+       static struct fd_buf writefds = { NULL, 0 };
+
+       struct pollfd *pf;
+       int i, fd_max = 0;
+       int res;
+       struct timeval *tv = NULL;
+       struct timeval tvreal;
+
+       fdbuf_zero(&readfds);
+       fdbuf_zero(&writefds);
+
+       for (i = 0; i < nfds; i++)
+       {
+               pf = fds + i;
+               if (pf->fd < 0)
+                       goto badf;
+
+               /* sets must be equal size */
+               if (!fdbuf_resize(&readfds, pf->fd))
+                       goto nomem;
+               if (!fdbuf_resize(&writefds, pf->fd))
+                       goto nomem;
+
+               if (pf->events & POLLIN)
+                       FD_SET(pf->fd, readfds.set);
+               if (pf->events & POLLOUT)
+                       FD_SET(pf->fd, writefds.set);
+               if (pf->fd > fd_max)
+                       fd_max = pf->fd;
+       }
+
+       if (timeout_ms >= 0)
+       {
+               tvreal.tv_sec = timeout_ms / 1000;
+               tvreal.tv_usec = (timeout_ms % 1000) * 1000;
+               tv = &tvreal;
+       }
+
+       res = select(fd_max + 1, readfds.set, writefds.set, NULL, tv);
+       if (res <= 0)
+               return res;
+
+       for (i = 0; i < nfds; i++)
+       {
+               pf = fds + i;
+               pf->revents = 0;
+               if ((pf->events & POLLIN) && FD_ISSET(pf->fd, readfds.set))
+                       pf->revents |= POLLIN;
+               if ((pf->events & POLLOUT) && FD_ISSET(pf->fd, writefds.set))
+                       pf->revents |= POLLOUT;
+       }
+
+       /* select() may count differently than poll()? */
+       return res;
+
+nomem:
+       errno = ENOMEM;
+       return -1;
+
+badf:
+       errno = EBADF;
+       return -1;
+}
+
+#endif /* PLPROXY_POLL_COMPAT */
+
index 0a016b9991f9e6a14038cbb4674fafb650167221..dccc97fa565b7899f2f24f5d8257a8882280c655 100644 (file)
@@ -1,23 +1,43 @@
 
-#ifdef HAVE_POLL_H
+#ifndef POLL_COMPAT_H
+#define POLL_COMPAT_H
 
-#include <poll.h>
+#define PLPROXY_POLL_COMPAT
 
+#include <sys/time.h>
+
+/* see if real poll() can be used */
+#ifndef PLPROXY_POLL_COMPAT
+#ifdef HAVE_POLL_H
+#include <poll.h>
 #else
 #ifdef HAVE_SYS_POLL_H
-
 #include <sys/poll.h>
-
 #else
-
-#include <sys/select.h>
-
-#define POLLIN (1 << 0)
-#define POLLOUT        (1 << 1)
-#define POLLHUP        (1 << 2)
-
-#define pollfd compat_pollfd
-#define poll compat_poll
+#define PLPROXY_POLL_COMPAT
+#endif
+#endif
+#endif
+
+/*
+ * Emulate poll() with select(), if needed.
+ */
+#ifdef PLPROXY_POLL_COMPAT
+
+/* in/out event types */
+#define POLLIN         (1 << 0)
+#define POLLOUT                (1 << 1)
+
+/* rest are unused in this implementation */
+#define POLLHUP                (1 << 2)
+#define POLLPRI                (1 << 3)
+#define POLLNVAL       (1 << 4)
+#define POLLERR                (1 << 5)
+
+/* avoid namespace conflicts */
+#define pollfd plproxy_compat_pollfd
+#define poll   plproxy_compat_poll
+#define nfds_t plproxy_compat_nfds_t
 
 struct pollfd {
        int fd;
@@ -25,56 +45,11 @@ struct pollfd {
        short revents;
 };
 
-static int poll(struct pollfd *fds, unsigned nfds, int timeout_ms)
-{
-       struct pollfd *pf;
-       int i, fd_max = 0;
-       int res;
-       fd_set r_set, w_set;
-
-       FD_ZERO(&r_set);
-       FD_ZERO(&w_set);
-       for (i = 0; i < nfds; i++) {
-               pf = fds + i;
-               if (pf->fd < 0 || pf->fd >= FD_SETSIZE)
-               {
-                       /* give different errno for FD_SETSIZE to allow detect it */
-                       errno = (pf->fd < 0) ? EBADF : EFAULT;
-                       return -1;
-               }
-               if (pf->events & POLLIN)
-                       FD_SET(pf->fd, &r_set);
-               if (pf->events & POLLOUT)
-                       FD_SET(pf->fd, &w_set);
-               if (pf->fd > fd_max)
-                       fd_max = pf->fd;
-       }
-
-       if (timeout_ms >= 0)
-       {
-               struct timeval tv;
-               tv.tv_sec = timeout_ms / 1000;
-               tv.tv_usec = timeout_ms % 1000;
-               res = select(fd_max + 1, &r_set, &w_set, NULL, &tv);
-       } else
-               res = select(fd_max + 1, &r_set, &w_set, NULL, NULL);
-
-       if (res <= 0)
-               return res;
-
-       for (i = 0; i < nfds; i++) {
-               pf = fds + i;
-               pf->revents = 0;
-               if ((pf->events & POLLIN) && FD_ISSET(pf->fd, &r_set))
-                       pf->revents |= POLLIN;
-               if ((pf->events & POLLOUT) && FD_ISSET(pf->fd, &w_set))
-                       pf->revents |= POLLOUT;
-       }
+typedef unsigned long nfds_t;
 
-       return res;
-}
+int poll(struct pollfd *fds, nfds_t nfds, int timeout_ms);
 
-#endif /* !HAVE_SYS_POLL_H */
-#endif /* !HAVE_POLL_H */
+#endif /* PLPROXY_POLL_COMPAT */
 
+#endif /* POLL_COMPAT_H */