os: Add epoll-like pollset implementation for AIX
AIX's poll only allows FD_SETSIZE entries in the fd list, which is insufficient for expanded MaxClients. As a bonus, x11perf -noop with ~250 xlogos connected is slightly faster with pollset: before after Operation --------- ---------------- -------------------- 5750000.0 5990000.0 (1.04) X protocol NoOperation Signed-off-by: Peter Harris <pharris@opentext.com> Acked-by: Keith Packard <keithp@keithp.com>
This commit is contained in:
parent
bed2830099
commit
83c04ee6ea
|
@ -123,6 +123,7 @@ conf_data.set('HAVE_GETPROGNAME', cc.has_function('getprogname'))
|
|||
conf_data.set('HAVE_GETZONEID', cc.has_function('getzoneid'))
|
||||
conf_data.set('HAVE_MMAP', cc.has_function('mmap'))
|
||||
conf_data.set('HAVE_POLL', cc.has_function('poll'))
|
||||
conf_data.set('HAVE_POLLSET_CREATE', cc.has_function('pollset_create'))
|
||||
conf_data.set('HAVE_POSIX_FALLOCATE', cc.has_function('posix_fallocate'))
|
||||
conf_data.set('HAVE_REALLOCARRAY', cc.has_function('reallocarray', dependencies: libbsd_dep))
|
||||
conf_data.set('HAVE_SETEUID', cc.has_function('seteuid'))
|
||||
|
|
146
os/ospoll.c
146
os/ospoll.c
|
@ -32,6 +32,12 @@
|
|||
#include "ospoll.h"
|
||||
#include "list.h"
|
||||
|
||||
#if !HAVE_OSPOLL && defined(HAVE_POLLSET_CREATE)
|
||||
#include <sys/pollset.h>
|
||||
#define POLLSET 1
|
||||
#define HAVE_OSPOLL 1
|
||||
#endif
|
||||
|
||||
#if !HAVE_OSPOLL && defined(HAVE_EPOLL_CREATE1)
|
||||
#include <sys/epoll.h>
|
||||
#define EPOLL 1
|
||||
|
@ -44,6 +50,27 @@
|
|||
#define HAVE_OSPOLL 1
|
||||
#endif
|
||||
|
||||
#if POLLSET
|
||||
|
||||
// pollset-based implementation (as seen on AIX)
|
||||
struct ospollfd {
|
||||
int fd;
|
||||
int xevents;
|
||||
short revents;
|
||||
enum ospoll_trigger trigger;
|
||||
void (*callback)(int fd, int xevents, void *data);
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct ospoll {
|
||||
pollset_t ps;
|
||||
struct ospollfd *fds;
|
||||
int num;
|
||||
int size;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#if EPOLL
|
||||
#include <sys/epoll.h>
|
||||
|
||||
|
@ -104,7 +131,7 @@ ospoll_find(struct ospoll *ospoll, int fd)
|
|||
#if EPOLL
|
||||
int t = ospoll->fds[m]->fd;
|
||||
#endif
|
||||
#if POLL
|
||||
#if POLL || POLLSET
|
||||
int t = ospoll->fds[m].fd;
|
||||
#endif
|
||||
|
||||
|
@ -168,6 +195,16 @@ array_delete(void *base, size_t num, size_t size, size_t pos)
|
|||
struct ospoll *
|
||||
ospoll_create(void)
|
||||
{
|
||||
#if POLLSET
|
||||
struct ospoll *ospoll = calloc(1, sizeof (struct ospoll));
|
||||
|
||||
ospoll->ps = pollset_create(-1);
|
||||
if (ospoll->ps < 0) {
|
||||
free (ospoll);
|
||||
return NULL;
|
||||
}
|
||||
return ospoll;
|
||||
#endif
|
||||
#if EPOLL
|
||||
struct ospoll *ospoll = calloc(1, sizeof (struct ospoll));
|
||||
|
||||
|
@ -187,6 +224,14 @@ ospoll_create(void)
|
|||
void
|
||||
ospoll_destroy(struct ospoll *ospoll)
|
||||
{
|
||||
#if POLLSET
|
||||
if (ospoll) {
|
||||
assert (ospoll->num == 0);
|
||||
pollset_destroy(ospoll->ps);
|
||||
free(ospoll->fds);
|
||||
free(ospoll);
|
||||
}
|
||||
#endif
|
||||
#if EPOLL
|
||||
if (ospoll) {
|
||||
assert (ospoll->num == 0);
|
||||
|
@ -213,6 +258,30 @@ ospoll_add(struct ospoll *ospoll, int fd,
|
|||
void *data)
|
||||
{
|
||||
int pos = ospoll_find(ospoll, fd);
|
||||
#if POLLSET
|
||||
if (pos < 0) {
|
||||
if (ospoll->num == ospoll->size) {
|
||||
struct ospollfd *new_fds;
|
||||
int new_size = ospoll->size ? ospoll->size * 2 : MAXCLIENTS * 2;
|
||||
|
||||
new_fds = reallocarray(ospoll->fds, new_size, sizeof (ospoll->fds[0]));
|
||||
if (!new_fds)
|
||||
return FALSE;
|
||||
ospoll->fds = new_fds;
|
||||
ospoll->size = new_size;
|
||||
}
|
||||
pos = -pos - 1;
|
||||
array_insert(ospoll->fds, ospoll->num, sizeof (ospoll->fds[0]), pos);
|
||||
ospoll->num++;
|
||||
|
||||
ospoll->fds[pos].fd = fd;
|
||||
ospoll->fds[pos].xevents = 0;
|
||||
ospoll->fds[pos].revents = 0;
|
||||
}
|
||||
ospoll->fds[pos].trigger = trigger;
|
||||
ospoll->fds[pos].callback = callback;
|
||||
ospoll->fds[pos].data = data;
|
||||
#endif
|
||||
#if EPOLL
|
||||
struct ospollfd *osfd;
|
||||
|
||||
|
@ -301,6 +370,14 @@ ospoll_remove(struct ospoll *ospoll, int fd)
|
|||
|
||||
pos = ospoll_find(ospoll, fd);
|
||||
if (pos >= 0) {
|
||||
#if POLLSET
|
||||
struct ospollfd *osfd = &ospoll->fds[pos];
|
||||
struct poll_ctl ctl = { .cmd = PS_DELETE, .fd = fd };
|
||||
pollset_ctl(ospoll->ps, &ctl, 1);
|
||||
|
||||
array_delete(ospoll->fds, ospoll->num, sizeof (ospoll->fds[0]), pos);
|
||||
ospoll->num--;
|
||||
#endif
|
||||
#if EPOLL
|
||||
struct ospollfd *osfd = ospoll->fds[pos];
|
||||
struct epoll_event ev;
|
||||
|
@ -346,6 +423,19 @@ ospoll_listen(struct ospoll *ospoll, int fd, int xevents)
|
|||
int pos = ospoll_find(ospoll, fd);
|
||||
|
||||
if (pos >= 0) {
|
||||
#if POLLSET
|
||||
struct poll_ctl ctl = { .cmd = PS_MOD, .fd = fd };
|
||||
if (xevents & X_NOTIFY_READ) {
|
||||
ctl.events |= POLLIN;
|
||||
ospoll->fds[pos].revents &= ~POLLIN;
|
||||
}
|
||||
if (xevents & X_NOTIFY_WRITE) {
|
||||
ctl.events |= POLLOUT;
|
||||
ospoll->fds[pos].revents &= ~POLLOUT;
|
||||
}
|
||||
pollset_ctl(ospoll->ps, &ctl, 1);
|
||||
ospoll->fds[pos].xevents |= xevents;
|
||||
#endif
|
||||
#if EPOLL
|
||||
struct ospollfd *osfd = ospoll->fds[pos];
|
||||
osfd->xevents |= xevents;
|
||||
|
@ -370,6 +460,22 @@ ospoll_mute(struct ospoll *ospoll, int fd, int xevents)
|
|||
int pos = ospoll_find(ospoll, fd);
|
||||
|
||||
if (pos >= 0) {
|
||||
#if POLLSET
|
||||
struct ospollfd *osfd = &ospoll->fds[pos];
|
||||
osfd->xevents &= ~xevents;
|
||||
struct poll_ctl ctl = { .cmd = PS_DELETE, .fd = fd };
|
||||
pollset_ctl(ospoll->ps, &ctl, 1);
|
||||
if (osfd->xevents) {
|
||||
ctl.cmd = PS_ADD;
|
||||
if (osfd->xevents & X_NOTIFY_READ) {
|
||||
ctl.events |= POLLIN;
|
||||
}
|
||||
if (osfd->xevents & X_NOTIFY_WRITE) {
|
||||
ctl.events |= POLLOUT;
|
||||
}
|
||||
pollset_ctl(ospoll->ps, &ctl, 1);
|
||||
}
|
||||
#endif
|
||||
#if EPOLL
|
||||
struct ospollfd *osfd = ospoll->fds[pos];
|
||||
osfd->xevents &= ~xevents;
|
||||
|
@ -389,6 +495,33 @@ int
|
|||
ospoll_wait(struct ospoll *ospoll, int timeout)
|
||||
{
|
||||
int nready;
|
||||
#if POLLSET
|
||||
#define MAX_EVENTS 256
|
||||
struct pollfd events[MAX_EVENTS];
|
||||
|
||||
nready = pollset_poll(ospoll->ps, events, MAX_EVENTS, timeout);
|
||||
for (int i = 0; i < nready; i++) {
|
||||
struct pollfd *ev = &events[i];
|
||||
int pos = ospoll_find(ospoll, ev->fd);
|
||||
struct ospollfd *osfd = &ospoll->fds[pos];
|
||||
short revents = ev->revents;
|
||||
short oldevents = osfd->revents;
|
||||
|
||||
osfd->revents = (revents & (POLLIN|POLLOUT));
|
||||
if (osfd->trigger == ospoll_trigger_edge)
|
||||
revents &= ~oldevents;
|
||||
if (revents) {
|
||||
int xevents = 0;
|
||||
if (revents & POLLIN)
|
||||
xevents |= X_NOTIFY_READ;
|
||||
if (revents & POLLOUT)
|
||||
xevents |= X_NOTIFY_WRITE;
|
||||
if (revents & (~(POLLIN|POLLOUT)))
|
||||
xevents |= X_NOTIFY_ERROR;
|
||||
osfd->callback(osfd->fd, xevents, osfd->data);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if EPOLL
|
||||
#define MAX_EVENTS 256
|
||||
struct epoll_event events[MAX_EVENTS];
|
||||
|
@ -451,6 +584,14 @@ ospoll_wait(struct ospoll *ospoll, int timeout)
|
|||
void
|
||||
ospoll_reset_events(struct ospoll *ospoll, int fd)
|
||||
{
|
||||
#if POLLSET
|
||||
int pos = ospoll_find(ospoll, fd);
|
||||
|
||||
if (pos < 0)
|
||||
return;
|
||||
|
||||
ospoll->fds[pos].revents = 0;
|
||||
#endif
|
||||
#if POLL
|
||||
int pos = ospoll_find(ospoll, fd);
|
||||
|
||||
|
@ -468,6 +609,9 @@ ospoll_data(struct ospoll *ospoll, int fd)
|
|||
|
||||
if (pos < 0)
|
||||
return NULL;
|
||||
#if POLLSET
|
||||
return ospoll->fds[pos].data;
|
||||
#endif
|
||||
#if EPOLL
|
||||
return ospoll->fds[pos]->data;
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue
Block a user