# 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]
# 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
--- /dev/null
+
+#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 */
+
-#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;
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 */