os: Add epoll-like port implementation for Solaris

x11perf -noop with 200 xlogos connected is slightly faster with ports:

  before           after         Operation
----------   -----------------   --------------------
18400000.0   19200000.0 (1.04)   X protocol NoOperation

Acked-by: Keith Packard <keithp@keithp.com>
Signed-off-by: Peter Harris <pharris@opentext.com>
This commit is contained in:
Peter Harris 2017-10-12 16:48:37 -04:00 committed by Adam Jackson
parent 83c04ee6ea
commit edda951fa5
2 changed files with 122 additions and 7 deletions

View File

@ -125,6 +125,7 @@ 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_PORT_CREATE', cc.has_function('port_create'))
conf_data.set('HAVE_REALLOCARRAY', cc.has_function('reallocarray', dependencies: libbsd_dep))
conf_data.set('HAVE_SETEUID', cc.has_function('seteuid'))
conf_data.set('HAVE_SETITIMER', cc.has_function('setitimer'))

View File

@ -38,6 +38,12 @@
#define HAVE_OSPOLL 1
#endif
#if !HAVE_OSPOLL && defined(HAVE_PORT_CREATE)
#include <port.h>
#define PORT 1
#define HAVE_OSPOLL 1
#endif
#if !HAVE_OSPOLL && defined(HAVE_EPOLL_CREATE1)
#include <sys/epoll.h>
#define EPOLL 1
@ -71,7 +77,7 @@ struct ospoll {
#endif
#if EPOLL
#if EPOLL || PORT
#include <sys/epoll.h>
/* epoll-based implementation */
@ -128,7 +134,7 @@ ospoll_find(struct ospoll *ospoll, int fd)
while (lo <= hi) {
int m = (lo + hi) >> 1;
#if EPOLL
#if EPOLL || PORT
int t = ospoll->fds[m]->fd;
#endif
#if POLL || POLLSET
@ -145,7 +151,7 @@ ospoll_find(struct ospoll *ospoll, int fd)
return -(lo + 1);
}
#if EPOLL
#if EPOLL || PORT
static void
ospoll_clean_deleted(struct ospoll *ospoll)
{
@ -205,6 +211,17 @@ ospoll_create(void)
}
return ospoll;
#endif
#if PORT
struct ospoll *ospoll = calloc(1, sizeof (struct ospoll));
ospoll->epoll_fd = port_create();
if (ospoll->epoll_fd < 0) {
free (ospoll);
return NULL;
}
xorg_list_init(&ospoll->deleted);
return ospoll;
#endif
#if EPOLL
struct ospoll *ospoll = calloc(1, sizeof (struct ospoll));
@ -232,7 +249,7 @@ ospoll_destroy(struct ospoll *ospoll)
free(ospoll);
}
#endif
#if EPOLL
#if EPOLL || PORT
if (ospoll) {
assert (ospoll->num == 0);
close(ospoll->epoll_fd);
@ -282,6 +299,41 @@ ospoll_add(struct ospoll *ospoll, int fd,
ospoll->fds[pos].callback = callback;
ospoll->fds[pos].data = data;
#endif
#if PORT
struct ospollfd *osfd;
if (pos < 0) {
osfd = calloc(1, sizeof (struct ospollfd));
if (!osfd)
return FALSE;
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) {
free (osfd);
return FALSE;
}
ospoll->fds = new_fds;
ospoll->size = new_size;
}
osfd->fd = fd;
osfd->xevents = 0;
pos = -pos - 1;
array_insert(ospoll->fds, ospoll->num, sizeof (ospoll->fds[0]), pos);
ospoll->fds[pos] = osfd;
ospoll->num++;
} else {
osfd = ospoll->fds[pos];
}
osfd->data = data;
osfd->callback = callback;
osfd->trigger = trigger;
#endif
#if EPOLL
struct ospollfd *osfd;
@ -378,6 +430,16 @@ ospoll_remove(struct ospoll *ospoll, int fd)
array_delete(ospoll->fds, ospoll->num, sizeof (ospoll->fds[0]), pos);
ospoll->num--;
#endif
#if PORT
struct ospollfd *osfd = ospoll->fds[pos];
port_dissociate(ospoll->epoll_fd, PORT_SOURCE_FD, fd);
array_delete(ospoll->fds, ospoll->num, sizeof (ospoll->fds[0]), pos);
ospoll->num--;
osfd->callback = NULL;
osfd->data = NULL;
xorg_list_add(&osfd->deleted, &ospoll->deleted);
#endif
#if EPOLL
struct ospollfd *osfd = ospoll->fds[pos];
struct epoll_event ev;
@ -400,6 +462,19 @@ ospoll_remove(struct ospoll *ospoll, int fd)
}
}
#if PORT
static void
epoll_mod(struct ospoll *ospoll, struct ospollfd *osfd)
{
int events = 0;
if (osfd->xevents & X_NOTIFY_READ)
events |= EPOLLIN;
if (osfd->xevents & X_NOTIFY_WRITE)
events |= EPOLLOUT;
port_associate(ospool->epoll_fd, PORT_SOURCE_FD, osfd->fd, events, osfd);
}
#endif
#if EPOLL
static void
epoll_mod(struct ospoll *ospoll, struct ospollfd *osfd)
@ -436,7 +511,7 @@ ospoll_listen(struct ospoll *ospoll, int fd, int xevents)
pollset_ctl(ospoll->ps, &ctl, 1);
ospoll->fds[pos].xevents |= xevents;
#endif
#if EPOLL
#if EPOLL || PORT
struct ospollfd *osfd = ospoll->fds[pos];
osfd->xevents |= xevents;
epoll_mod(ospoll, osfd);
@ -476,7 +551,7 @@ ospoll_mute(struct ospoll *ospoll, int fd, int xevents)
pollset_ctl(ospoll->ps, &ctl, 1);
}
#endif
#if EPOLL
#if EPOLL || PORT
struct ospollfd *osfd = ospoll->fds[pos];
osfd->xevents &= ~xevents;
epoll_mod(ospoll, osfd);
@ -522,6 +597,37 @@ ospoll_wait(struct ospoll *ospoll, int timeout)
}
}
#endif
#if PORT
#define MAX_EVENTS 256
port_event_t events[MAX_EVENTS];
uint_t nget = 1;
nready = 0;
if (port_getn(ospoll->epoll_fd, events, MAX_EVENTS, &nget, &timeout) == 0) {
nready = nget;
}
for (int i = 0; i < nready; i++) {
port_event_t *ev = &events[i];
struct ospollfd *osfd = ev->portev_user;
uint32_t revents = ev->portev_events;
int xevents = 0;
if (revents & EPOLLIN)
xevents |= X_NOTIFY_READ;
if (revents & EPOLLOUT)
xevents |= X_NOTIFY_WRITE;
if (revents & (~(EPOLLIN|EPOLLOUT)))
xevents |= X_NOTIFY_ERROR;
if (osfd->callback)
osfd->callback(osfd->fd, xevents, osfd->data);
if (osfd->trigger == ospoll_trigger_level && !osfd->deleted) {
epoll_mod(ospoll, osfd);
}
}
ospoll_clean_deleted(ospoll);
#endif
#if EPOLL
#define MAX_EVENTS 256
struct epoll_event events[MAX_EVENTS];
@ -592,6 +698,14 @@ ospoll_reset_events(struct ospoll *ospoll, int fd)
ospoll->fds[pos].revents = 0;
#endif
#if PORT
int pos = ospoll_find(ospoll, fd);
if (pos < 0)
return;
epoll_mod(ospoll, ospoll->fds[pos]);
#endif
#if POLL
int pos = ospoll_find(ospoll, fd);
@ -612,7 +726,7 @@ ospoll_data(struct ospoll *ospoll, int fd)
#if POLLSET
return ospoll->fds[pos].data;
#endif
#if EPOLL
#if EPOLL || PORT
return ospoll->fds[pos]->data;
#endif
#if POLL