[PATCH xserver 17/25] os: use poll(2) instead of select(2)
Keith Packard
keithp at keithp.com
Wed May 25 05:38:54 UTC 2016
This leaves all of the select file descriptor bashing in place, and
just adds the necessary hooks to compute the poll data as well.
Signed-off-by: Keith Packard <keithp at keithp.com>
---
os/WaitFor.c | 143 ++++++++++++++-----------------------
os/connection.c | 214 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
os/osdep.h | 27 +++++++
3 files changed, 277 insertions(+), 107 deletions(-)
diff --git a/os/WaitFor.c b/os/WaitFor.c
index e78e358..eff2f70 100644
--- a/os/WaitFor.c
+++ b/os/WaitFor.c
@@ -148,20 +148,19 @@ WaitForSomething(Bool clients_are_ready)
int i;
struct timeval waittime, *wt;
INT32 timeout = 0;
- fd_set clientsReadable;
- fd_set clientsWritable;
- int curclient;
- int selecterr;
- static int nready;
+ int pollerr;
+ static Bool clients_were_ready;
+ Bool timer_is_running;
CARD32 now = 0;
- Bool someNotifyWriteReady = FALSE;
- FD_ZERO(&clientsReadable);
- FD_ZERO(&clientsWritable);
+ timer_is_running = clients_were_ready;
- if (nready)
+ if (clients_were_ready && !clients_are_ready) {
+ timer_is_running = FALSE;
SmartScheduleStopTimer();
- nready = 0;
+ }
+
+ clients_were_ready = FALSE;
#ifdef BUSFAULT
busfault_check();
@@ -178,8 +177,6 @@ WaitForSomething(Bool clients_are_ready)
waittime.tv_sec = 0;
waittime.tv_usec = 0;
wt = &waittime;
- XFD_COPYSET(&AllSockets, &LastSelectMask);
- XFD_UNSET(&LastSelectMask, &ClientsWithInput);
}
else {
wt = NULL;
@@ -201,7 +198,6 @@ WaitForSomething(Bool clients_are_ready)
wt = &waittime;
}
}
- XFD_COPYSET(&AllSockets, &LastSelectMask);
}
BlockHandler(&wt);
@@ -210,40 +206,37 @@ WaitForSomething(Bool clients_are_ready)
/* keep this check close to select() call to minimize race */
if (dispatchException)
i = -1;
- else if (AnyWritesPending) {
- XFD_COPYSET(&ClientsWriteBlocked, &LastSelectWriteMask);
- XFD_ORSET(&LastSelectWriteMask, &NotifyWriteFds, &LastSelectWriteMask);
- i = Select(MaxClients, &LastSelectMask, &LastSelectWriteMask, NULL, wt);
- }
- else {
- i = Select(MaxClients, &LastSelectMask, NULL, NULL, wt);
+ else
+ {
+ int poll_timeout = -1;
+
+ if (wt)
+ poll_timeout = wt->tv_sec * 1000 + wt->tv_usec / 1000;
+ i = poll(poll_fds, poll_fds_num, poll_timeout);
}
- selecterr = GetErrno();
+ pollerr = GetErrno();
WakeupHandler(i);
if (i <= 0) { /* An error or timeout occurred */
if (dispatchException)
return FALSE;
if (i < 0) {
- if (selecterr == EBADF) { /* Some client disconnected */
+ if (pollerr == EBADF) { /* Some client disconnected */
CheckConnections();
- if (!XFD_ANYSET(&AllClients))
- return FALSE;
+ return FALSE;
}
- else if (selecterr == EINVAL) {
- FatalError("WaitForSomething(): select: %s\n",
- strerror(selecterr));
+ else if (pollerr == EINVAL) {
+ FatalError("WaitForSomething(): poll: %s\n",
+ strerror(pollerr));
}
- else if (selecterr != EINTR && selecterr != EAGAIN) {
- ErrorF("WaitForSomething(): select: %s\n",
- strerror(selecterr));
+ else if (pollerr != EINTR && pollerr != EAGAIN) {
+ ErrorF("WaitForSomething(): poll: %s\n",
+ strerror(pollerr));
}
}
else if (clients_are_ready) {
/*
* If no-one else is home, bail quickly
*/
- XFD_COPYSET(&ClientsWithInput, &LastSelectMask);
- XFD_COPYSET(&ClientsWithInput, &clientsReadable);
break;
}
if (*checkForInput[0] != *checkForInput[1])
@@ -267,7 +260,7 @@ WaitForSomething(Bool clients_are_ready)
}
}
else {
- fd_set tmp_set;
+ int p;
if (*checkForInput[0] == *checkForInput[1]) {
if (timers) {
@@ -287,72 +280,44 @@ WaitForSomething(Bool clients_are_ready)
}
}
}
-
- if (AnyWritesPending) {
- XFD_ANDSET(&clientsWritable, &LastSelectWriteMask, &ClientsWriteBlocked);
- if (XFD_ANYSET(&clientsWritable)) {
- NewOutputPending = TRUE;
- XFD_ORSET(&OutputPending, &clientsWritable, &OutputPending);
- XFD_UNSET(&ClientsWriteBlocked, &clientsWritable);
- if (!XFD_ANYSET(&ClientsWriteBlocked) && NumNotifyWriteFd == 0)
- AnyWritesPending = FALSE;
- }
- if (NumNotifyWriteFd != 0) {
- XFD_ANDSET(&tmp_set, &LastSelectWriteMask, &NotifyWriteFds);
- if (XFD_ANYSET(&tmp_set))
- someNotifyWriteReady = TRUE;
+ for (p = 0; p < poll_fds_num; p++) {
+ short revents = poll_fds[p].revents;
+
+ if (revents) {
+ int client_index = ConnectionTranslation[poll_fds[p].fd];
+
+ if (client_index) {
+ if (revents & ~(POLLIN|POLLOUT))
+ CloseDownClient(clients[client_index]);
+ else {
+ if (revents & POLLIN) {
+ mark_client_ready(clients[client_index]);
+ clients_are_ready = TRUE;
+ }
+ if (revents & POLLOUT) {
+ NewOutputPending = TRUE;
+ }
+ }
+ } else {
+ HandleNotifyFd(poll_fds[p].fd, revents);
+ }
}
}
- XFD_ANDSET(&clientsReadable, &LastSelectMask, &AllClients);
-
- XFD_ANDSET(&tmp_set, &LastSelectMask, &NotifyReadFds);
- if (XFD_ANYSET(&tmp_set) || someNotifyWriteReady)
- HandleNotifyFds();
-
- if (clients_are_ready || XFD_ANYSET(&clientsReadable))
- break;
-
/* check here for DDXes that queue events during Block/Wakeup */
if (*checkForInput[0] != *checkForInput[1])
return FALSE;
- }
- }
-
- nready = 0;
- if (XFD_ANYSET(&clientsReadable)) {
-#ifndef WIN32
- for (i = 0; i < howmany(XFD_SETSIZE, NFDBITS); i++) {
- while (clientsReadable.fds_bits[i]) {
- int client_index;
-
- curclient = mffs(clientsReadable.fds_bits[i]) - 1;
- client_index = /* raphael: modified */
- ConnectionTranslation[curclient +
- (i * (sizeof(fd_mask) * 8))];
-#else
- fd_set savedClientsReadable;
-
- XFD_COPYSET(&clientsReadable, &savedClientsReadable);
- for (i = 0; i < XFD_SETCOUNT(&savedClientsReadable); i++) {
- int client_priority, client_index;
- curclient = XFD_FD(&savedClientsReadable, i);
- client_index = GetConnectionTranslation(curclient);
-#endif
- nready++;
- mark_client_ready(clients[client_index]);
-#ifndef WIN32
- clientsReadable.fds_bits[i] &= ~(((fd_mask) 1L) << curclient);
- }
-#else
- FD_CLR(curclient, &clientsReadable);
-#endif
+ if (clients_are_ready)
+ break;
}
}
- if (nready)
- SmartScheduleStartTimer();
+ if (clients_are_ready) {
+ clients_were_ready = TRUE;
+ if (!timer_is_running)
+ SmartScheduleStartTimer();
+ }
return TRUE;
}
diff --git a/os/connection.c b/os/connection.c
index d3fda35..edf1764 100644
--- a/os/connection.c
+++ b/os/connection.c
@@ -121,6 +121,9 @@ SOFTWARE.
static int lastfdesc; /* maximum file descriptor */
+struct pollfd *poll_fds;
+int poll_fds_num;
+
fd_set NotifyReadFds; /* mask for other file descriptors */
fd_set NotifyWriteFds; /* mask for other write file descriptors */
fd_set AllSockets; /* select on this */
@@ -155,6 +158,12 @@ int GrabInProgress = 0;
static void
QueueNewConnections(int curconn, int ready, void *data);
+static void
+set_poll_client(ClientPtr client);
+
+static void
+set_poll_clients(void);
+
#if !defined(WIN32)
int *ConnectionTranslation = NULL;
#else
@@ -392,6 +401,7 @@ CreateWellKnownSockets(void)
int i;
int partial;
+ poll_fd_init();
FD_ZERO(&AllSockets);
FD_ZERO(&AllClients);
FD_ZERO(&LastSelectMask);
@@ -774,6 +784,7 @@ AllocNewConnection(XtransConnInfo trans_conn, int fd, CARD32 conn_time)
oc->output = (ConnectionOutputPtr) NULL;
oc->auth_id = None;
oc->conn_time = conn_time;
+ oc->flags = 0;
if (!(client = NextAvailableClient((void *) oc))) {
free(oc);
return NullClient;
@@ -784,6 +795,9 @@ AllocNewConnection(XtransConnInfo trans_conn, int fd, CARD32 conn_time)
#else
SetConnectionTranslation(fd, client->index);
#endif
+ poll_fd_add(fd);
+ set_poll_client(client);
+
if (GrabInProgress) {
FD_SET(fd, &SavedAllClients);
FD_SET(fd, &SavedAllSockets);
@@ -944,6 +958,7 @@ CloseDownFileDescriptor(OsCommPtr oc)
#else
SetConnectionTranslation(connection, 0);
#endif
+ poll_fd_remove(connection);
FD_CLR(connection, &AllSockets);
FD_CLR(connection, &AllClients);
FD_CLR(connection, &ClientsWithInput);
@@ -1046,22 +1061,6 @@ CloseDownConnection(ClientPtr client)
AuditF("client %d disconnected\n", client->index);
}
-static void
-AddGeneralSocket(int fd)
-{
- FD_SET(fd, &AllSockets);
- if (GrabInProgress)
- FD_SET(fd, &SavedAllSockets);
-}
-
-static void
-RemoveGeneralSocket(int fd)
-{
- FD_CLR(fd, &AllSockets);
- if (GrabInProgress)
- FD_CLR(fd, &SavedAllSockets);
-}
-
struct notify_fd {
struct xorg_list list;
int fd;
@@ -1118,20 +1117,30 @@ SetNotifyFd(int fd, NotifyFdProcPtr notify, int mask, void *data)
if (changes & X_NOTIFY_READ) {
if (mask & X_NOTIFY_READ) {
+ poll_fd_add(fd);
+ poll_fd_listen(fd, POLLIN);
FD_SET(fd, &NotifyReadFds);
- AddGeneralSocket(fd);
+ FD_SET(fd, &AllSockets);
+ if (GrabInProgress)
+ FD_SET(fd, &SavedAllSockets);
} else {
- RemoveGeneralSocket(fd);
+ poll_fd_mute(fd, POLLIN);
+ FD_CLR(fd, &AllSockets);
+ if (GrabInProgress)
+ FD_CLR(fd, &SavedAllSockets);
FD_CLR(fd, &NotifyReadFds);
}
}
if (changes & X_NOTIFY_WRITE) {
if (mask & X_NOTIFY_WRITE) {
+ poll_fd_add(fd);
+ poll_fd_listen(fd, POLLOUT);
FD_SET(fd, &NotifyWriteFds);
if (!NumNotifyWriteFd++)
AnyWritesPending = TRUE;
} else {
+ poll_fd_mute(fd, POLLOUT);
FD_CLR(fd, &NotifyWriteFds);
if (!--NumNotifyWriteFd)
if (!XFD_ANYSET(&ClientsWriteBlocked))
@@ -1140,6 +1149,7 @@ SetNotifyFd(int fd, NotifyFdProcPtr notify, int mask, void *data)
}
if (mask == 0) {
+ poll_fd_remove(fd);
xorg_list_del(&n->list);
free(n);
} else {
@@ -1158,6 +1168,25 @@ SetNotifyFd(int fd, NotifyFdProcPtr notify, int mask, void *data)
*****************/
void
+HandleNotifyFd(int fd, short revents)
+{
+ struct notify_fd *n, *next;
+
+ xorg_list_for_each_entry_safe(n, next, ¬ify_fds, list) {
+ if (n->fd == fd) {
+ int ready = 0;
+ if (n->mask & X_NOTIFY_READ && (revents & POLLIN))
+ ready |= X_NOTIFY_READ;
+ if (n->mask & X_NOTIFY_WRITE && (revents & POLLOUT))
+ ready |= X_NOTIFY_WRITE;
+ if (ready != 0)
+ n->notify(n->fd, ready, n->data);
+ break;
+ }
+ }
+}
+
+void
HandleNotifyFds(void)
{
struct notify_fd *n, *next;
@@ -1209,7 +1238,9 @@ OnlyListenToOneClient(ClientPtr client)
FD_SET(connection, &AllClients);
XFD_ORSET(&AllSockets, &AllSockets, &AllClients);
GrabInProgress = client->index;
+ set_poll_clients();
}
+
return rc;
}
@@ -1226,6 +1257,7 @@ ListenToAllClients(void)
XFD_ORSET(&AllClients, &AllClients, &SavedAllClients);
XFD_ORSET(&ClientsWithInput, &ClientsWithInput, &SavedClientsWithInput);
GrabInProgress = 0;
+ set_poll_clients();
}
}
@@ -1247,6 +1279,10 @@ IgnoreClient(ClientPtr client)
isItTimeToYield = TRUE;
mark_client_not_ready(client);
+
+ oc->flags |= OS_COMM_IGNORED;
+ set_poll_client(client);
+
if (!GrabInProgress || FD_ISSET(connection, &AllClients)) {
if (FD_ISSET(connection, &ClientsWithInput))
FD_SET(connection, &IgnoredClientsWithInput);
@@ -1283,6 +1319,9 @@ AttendClient(ClientPtr client)
if (client->ignoreCount)
return;
+ oc->flags &= ~OS_COMM_IGNORED;
+ set_poll_client(client);
+
if (!GrabInProgress || GrabInProgress == client->index ||
FD_ISSET(connection, &GrabImperviousClients)) {
FD_SET(connection, &AllClients);
@@ -1309,6 +1348,8 @@ MakeClientGrabImpervious(ClientPtr client)
OsCommPtr oc = (OsCommPtr) client->osPrivate;
int connection = oc->fd;
+ oc->flags |= OS_COMM_GRAB_IMPERVIOUS;
+
FD_SET(connection, &GrabImperviousClients);
if (ServerGrabCallback) {
@@ -1328,6 +1369,9 @@ MakeClientGrabPervious(ClientPtr client)
OsCommPtr oc = (OsCommPtr) client->osPrivate;
int connection = oc->fd;
+ oc->flags &= ~OS_COMM_GRAB_IMPERVIOUS;
+ set_poll_client(client);
+
FD_CLR(connection, &GrabImperviousClients);
if (GrabInProgress && (GrabInProgress != client->index)) {
if (FD_ISSET(connection, &ClientsWithInput)) {
@@ -1420,3 +1464,137 @@ AddClientOnOpenFD(int fd)
return TRUE;
}
+
+static int poll_fds_size;
+
+static inline Bool
+listen_to_client(ClientPtr client)
+{
+ OsCommPtr oc = (OsCommPtr) client->osPrivate;
+
+ if (oc->flags & OS_COMM_IGNORED)
+ return FALSE;
+
+ if (!GrabInProgress)
+ return TRUE;
+
+ if (client->index == GrabInProgress)
+ return TRUE;
+
+ if (oc->flags & OS_COMM_GRAB_IMPERVIOUS)
+ return TRUE;
+
+ return FALSE;
+}
+
+static void
+set_poll_client(ClientPtr client)
+{
+ OsCommPtr oc = (OsCommPtr) client->osPrivate;
+
+ if (listen_to_client(client))
+ poll_fd_listen(oc->fd, POLLIN);
+ else
+ poll_fd_mute(oc->fd, POLLIN);
+}
+
+static void
+set_poll_clients(void)
+{
+ int i;
+
+ for (i = 1; i < currentMaxClients; i++) {
+ ClientPtr client = clients[i];
+ if (client && !client->clientGone)
+ set_poll_client(client);
+ }
+}
+
+static int
+poll_fd_find(int fd)
+{
+ int lo = 0;
+ int hi = poll_fds_num - 1;
+
+ while (lo <= hi) {
+ int m = (lo + hi) >> 1;
+ int t = poll_fds[m].fd;
+
+ if (t < fd)
+ lo = m + 1;
+ else if (t > fd)
+ hi = m - 1;
+ else
+ return m;
+ }
+ return -(lo + 1);
+}
+
+void
+poll_fd_init(void)
+{
+ free(poll_fds);
+ poll_fds = NULL;
+ poll_fds_size = poll_fds_num = 0;
+}
+
+Bool
+poll_fd_add(int fd)
+{
+ int pos = poll_fd_find(fd);
+ if (pos >= 0)
+ return TRUE;
+
+ if (poll_fds_num == poll_fds_size) {
+ struct pollfd *new_poll_fds;
+ int new_poll_fds_size = poll_fds_size ? poll_fds_size * 2 : MAXCLIENTS * 2;
+
+ new_poll_fds = realloc(poll_fds, new_poll_fds_size * sizeof (struct pollfd));
+ if (!new_poll_fds)
+ return FALSE;
+ poll_fds = new_poll_fds;
+ poll_fds_size = new_poll_fds_size;
+ }
+ pos = -pos - 1;
+ memmove(&poll_fds[pos + 1], &poll_fds[pos], (poll_fds_num - pos) * sizeof (struct pollfd));
+ poll_fds_num++;
+
+ poll_fds[pos].fd = fd;
+ poll_fds[pos].events = 0;
+ poll_fds[pos].revents = 0;
+ return TRUE;
+}
+
+void
+poll_fd_remove(int fd)
+{
+ int pos = poll_fd_find(fd);
+
+ if (pos < 0)
+ return;
+
+ poll_fds_num--;
+ memmove(&poll_fds[pos], &poll_fds[pos+1], (poll_fds_num - pos) * sizeof (struct pollfd));
+}
+
+void
+poll_fd_listen(int fd, short events)
+{
+ int pos = poll_fd_find(fd);
+
+ if (pos < 0)
+ return;
+
+ poll_fds[pos].events |= events;
+}
+
+void
+poll_fd_mute(int fd, short events)
+{
+ int pos = poll_fd_find(fd);
+
+ if (pos < 0)
+ return;
+
+ poll_fds[pos].events &= ~events;
+}
diff --git a/os/osdep.h b/os/osdep.h
index 3dc2daf..4680850 100644
--- a/os/osdep.h
+++ b/os/osdep.h
@@ -63,6 +63,8 @@ SOFTWARE.
#undef _POSIX_SOURCE
#endif
+#include <poll.h>
+
#ifndef OPEN_MAX
#ifdef SVR4
#define OPEN_MAX 512
@@ -148,8 +150,12 @@ typedef struct _osComm {
XID auth_id; /* authorization id */
CARD32 conn_time; /* timestamp if not established, else 0 */
struct _XtransConnInfo *trans_conn; /* transport connection object */
+ int flags;
} OsCommRec, *OsCommPtr;
+#define OS_COMM_GRAB_IMPERVIOUS 1
+#define OS_COMM_IGNORED 2
+
extern int FlushClient(ClientPtr /*who */ ,
OsCommPtr /*oc */ ,
const void * /*extraBuf */ ,
@@ -161,10 +167,16 @@ extern void FreeOsBuffers(OsCommPtr /*oc */
extern void InitNotifyFds(void);
+void
+HandleNotifyFd(int fd, short revents);
+
extern void HandleNotifyFds(void);
#include "dix.h"
+extern struct pollfd *poll_fds;
+extern int poll_fds_num;
+
extern fd_set AllSockets;
extern fd_set AllClients;
extern fd_set LastSelectMask;
@@ -178,6 +190,21 @@ extern fd_set ClientsWriteBlocked;
extern fd_set OutputPending;
extern fd_set IgnoredClientsWithInput;
+void
+poll_fd_init(void);
+
+Bool
+poll_fd_add(int fd);
+
+void
+poll_fd_remove(int fd);
+
+void
+poll_fd_listen(int fd, short events);
+
+void
+poll_fd_mute(int fd, short events);
+
#if !defined(WIN32) || defined(__CYGWIN__)
extern int *ConnectionTranslation;
#else
--
2.8.0.rc3
More information about the xorg-devel
mailing list