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 <kei...@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 _______________________________________________ xorg-devel@lists.x.org: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: https://lists.x.org/mailman/listinfo/xorg-devel