summaryrefslogtreecommitdiffstats
path: root/winpr/libwinpr/synch/pollset.c
diff options
context:
space:
mode:
Diffstat (limited to 'winpr/libwinpr/synch/pollset.c')
-rw-r--r--winpr/libwinpr/synch/pollset.c274
1 files changed, 274 insertions, 0 deletions
diff --git a/winpr/libwinpr/synch/pollset.c b/winpr/libwinpr/synch/pollset.c
new file mode 100644
index 0000000..8711ea0
--- /dev/null
+++ b/winpr/libwinpr/synch/pollset.c
@@ -0,0 +1,274 @@
+#ifndef _WIN32
+#include <errno.h>
+
+#include "pollset.h"
+#include <winpr/handle.h>
+#include <winpr/sysinfo.h>
+#include <winpr/assert.h>
+#include "../log.h"
+
+#define TAG WINPR_TAG("sync.pollset")
+
+#ifdef WINPR_HAVE_POLL_H
+static INT16 handle_mode_to_pollevent(ULONG mode)
+{
+ INT16 event = 0;
+
+ if (mode & WINPR_FD_READ)
+ event |= POLLIN;
+
+ if (mode & WINPR_FD_WRITE)
+ event |= POLLOUT;
+
+ return event;
+}
+#endif
+
+BOOL pollset_init(WINPR_POLL_SET* set, size_t nhandles)
+{
+ WINPR_ASSERT(set);
+#ifdef WINPR_HAVE_POLL_H
+ if (nhandles > MAXIMUM_WAIT_OBJECTS)
+ {
+ set->isStatic = FALSE;
+ set->pollset = calloc(nhandles, sizeof(*set->pollset));
+ if (!set->pollset)
+ return FALSE;
+ }
+ else
+ {
+ set->pollset = set->staticSet;
+ set->isStatic = TRUE;
+ }
+#else
+ set->fdIndex = calloc(nhandles, sizeof(*set->fdIndex));
+ if (!set->fdIndex)
+ return FALSE;
+
+ FD_ZERO(&set->rset_base);
+ FD_ZERO(&set->rset);
+ FD_ZERO(&set->wset_base);
+ FD_ZERO(&set->wset);
+ set->maxFd = 0;
+ set->nread = set->nwrite = 0;
+#endif
+
+ set->size = nhandles;
+ set->fillIndex = 0;
+ return TRUE;
+}
+
+void pollset_uninit(WINPR_POLL_SET* set)
+{
+ WINPR_ASSERT(set);
+#ifdef WINPR_HAVE_POLL_H
+ if (!set->isStatic)
+ free(set->pollset);
+#else
+ free(set->fdIndex);
+#endif
+}
+
+void pollset_reset(WINPR_POLL_SET* set)
+{
+ WINPR_ASSERT(set);
+#ifndef WINPR_HAVE_POLL_H
+ FD_ZERO(&set->rset_base);
+ FD_ZERO(&set->wset_base);
+ set->maxFd = 0;
+ set->nread = set->nwrite = 0;
+#endif
+ set->fillIndex = 0;
+}
+
+BOOL pollset_add(WINPR_POLL_SET* set, int fd, ULONG mode)
+{
+ WINPR_ASSERT(set);
+#ifdef WINPR_HAVE_POLL_H
+ struct pollfd* item = NULL;
+ if (set->fillIndex == set->size)
+ return FALSE;
+
+ item = &set->pollset[set->fillIndex];
+ item->fd = fd;
+ item->revents = 0;
+ item->events = handle_mode_to_pollevent(mode);
+#else
+ FdIndex* fdIndex = &set->fdIndex[set->fillIndex];
+ if (mode & WINPR_FD_READ)
+ {
+ FD_SET(fd, &set->rset_base);
+ set->nread++;
+ }
+
+ if (mode & WINPR_FD_WRITE)
+ {
+ FD_SET(fd, &set->wset_base);
+ set->nwrite++;
+ }
+
+ if (fd > set->maxFd)
+ set->maxFd = fd;
+
+ fdIndex->fd = fd;
+ fdIndex->mode = mode;
+#endif
+ set->fillIndex++;
+ return TRUE;
+}
+
+int pollset_poll(WINPR_POLL_SET* set, DWORD dwMilliseconds)
+{
+ WINPR_ASSERT(set);
+ int ret = 0;
+ UINT64 dueTime = 0;
+ UINT64 now = 0;
+
+ now = GetTickCount64();
+ if (dwMilliseconds == INFINITE)
+ dueTime = 0xFFFFFFFFFFFFFFFF;
+ else
+ dueTime = now + dwMilliseconds;
+
+#ifdef WINPR_HAVE_POLL_H
+ int timeout = 0;
+
+ do
+ {
+ if (dwMilliseconds == INFINITE)
+ timeout = -1;
+ else
+ timeout = (int)(dueTime - now);
+
+ ret = poll(set->pollset, set->fillIndex, timeout);
+ if (ret >= 0)
+ return ret;
+
+ if (errno != EINTR)
+ return -1;
+
+ now = GetTickCount64();
+ } while (now < dueTime);
+
+#else
+ do
+ {
+ struct timeval staticTimeout;
+ struct timeval* timeout;
+
+ fd_set* rset = NULL;
+ fd_set* wset = NULL;
+
+ if (dwMilliseconds == INFINITE)
+ {
+ timeout = NULL;
+ }
+ else
+ {
+ long waitTime = (long)(dueTime - now);
+
+ timeout = &staticTimeout;
+ timeout->tv_sec = waitTime / 1000;
+ timeout->tv_usec = (waitTime % 1000) * 1000;
+ }
+
+ if (set->nread)
+ {
+ rset = &set->rset;
+ memcpy(rset, &set->rset_base, sizeof(*rset));
+ }
+
+ if (set->nwrite)
+ {
+ wset = &set->wset;
+ memcpy(wset, &set->wset_base, sizeof(*wset));
+ }
+
+ ret = select(set->maxFd + 1, rset, wset, NULL, timeout);
+ if (ret >= 0)
+ return ret;
+
+ if (errno != EINTR)
+ return -1;
+
+ now = GetTickCount64();
+
+ } while (now < dueTime);
+
+ FD_ZERO(&set->rset);
+ FD_ZERO(&set->wset);
+#endif
+
+ return 0; /* timeout */
+}
+
+BOOL pollset_isSignaled(WINPR_POLL_SET* set, size_t idx)
+{
+ WINPR_ASSERT(set);
+
+ if (idx > set->fillIndex)
+ {
+ WLog_ERR(TAG, "index=%d out of pollset(fillIndex=%" PRIuz ")", idx, set->fillIndex);
+ return FALSE;
+ }
+
+#ifdef WINPR_HAVE_POLL_H
+ return !!(set->pollset[idx].revents & set->pollset[idx].events);
+#else
+ FdIndex* fdIndex = &set->fdIndex[idx];
+ if (fdIndex->fd < 0)
+ return FALSE;
+
+ if ((fdIndex->mode & WINPR_FD_READ) && FD_ISSET(fdIndex->fd, &set->rset))
+ return TRUE;
+
+ if ((fdIndex->mode & WINPR_FD_WRITE) && FD_ISSET(fdIndex->fd, &set->wset))
+ return TRUE;
+
+ return FALSE;
+#endif
+}
+
+BOOL pollset_isReadSignaled(WINPR_POLL_SET* set, size_t idx)
+{
+ WINPR_ASSERT(set);
+
+ if (idx > set->fillIndex)
+ {
+ WLog_ERR(TAG, "index=%d out of pollset(fillIndex=%" PRIuz ")", idx, set->fillIndex);
+ return FALSE;
+ }
+
+#ifdef WINPR_HAVE_POLL_H
+ return !!(set->pollset[idx].revents & POLLIN);
+#else
+ FdIndex* fdIndex = &set->fdIndex[idx];
+ if (fdIndex->fd < 0)
+ return FALSE;
+
+ return FD_ISSET(fdIndex->fd, &set->rset);
+#endif
+}
+
+BOOL pollset_isWriteSignaled(WINPR_POLL_SET* set, size_t idx)
+{
+ WINPR_ASSERT(set);
+
+ if (idx > set->fillIndex)
+ {
+ WLog_ERR(TAG, "index=%d out of pollset(fillIndex=%" PRIuz ")", idx, set->fillIndex);
+ return FALSE;
+ }
+
+#ifdef WINPR_HAVE_POLL_H
+ return !!(set->pollset[idx].revents & POLLOUT);
+#else
+ FdIndex* fdIndex = &set->fdIndex[idx];
+ if (fdIndex->fd < 0)
+ return FALSE;
+
+ return FD_ISSET(fdIndex->fd, &set->wset);
+#endif
+}
+
+#endif