FreeRDP/winpr/libwinpr/synch/pollset.c
2024-02-15 11:49:16 +01:00

275 lines
4.9 KiB
C

#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