os: Switch server to poll(2) [v3]

Eliminates all of the fd_set mangling in the server main thread

v2: Listen for POLLOUT while writes are blocked.

v3: Only mark client not ready on EAGAIN return from read

Signed-off-by: Keith Packard <keithp@keithp.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
This commit is contained in:
Keith Packard 2016-05-26 10:40:44 -07:00 committed by Adam Jackson
parent 8f1edf4bd3
commit f993091e7d
8 changed files with 223 additions and 449 deletions

View File

@ -242,12 +242,14 @@ void Dispatch(void);
static struct xorg_list ready_clients;
static struct xorg_list saved_ready_clients;
struct xorg_list output_pending_clients;
static void
init_client_ready(void)
{
xorg_list_init(&ready_clients);
xorg_list_init(&saved_ready_clients);
xorg_list_init(&output_pending_clients);
}
Bool
@ -3411,6 +3413,7 @@ CloseDownClient(ClientPtr client)
UngrabServer(client);
}
mark_client_not_ready(client);
xorg_list_del(&client->output_pending);
BITCLEAR(grabWaiters, client->index);
DeleteClientFromAnySelections(client);
ReleaseActiveGrabs(client);
@ -3501,6 +3504,7 @@ InitClient(ClientPtr client, int i, void *ospriv)
{
client->index = i;
xorg_list_init(&client->ready);
xorg_list_init(&client->output_pending);
client->clientAsMask = ((Mask) i) << CLIENTOFFSET;
client->closeDownMode = i ? DestroyAll : RetainPermanent;
client->requestVector = InitialVector;

View File

@ -77,6 +77,7 @@ typedef struct _Client {
void *requestBuffer;
void *osPrivate; /* for OS layer, including scheduler */
struct xorg_list ready; /* List of clients ready to run */
struct xorg_list output_pending; /* List of clients with output queued */
Mask clientAsMask;
short index;
unsigned char majorOp, minorOp;
@ -153,6 +154,25 @@ static inline Bool client_is_ready(ClientPtr client)
Bool
clients_are_ready(void);
extern struct xorg_list output_pending_clients;
static inline void
output_pending_mark(ClientPtr client)
{
if (xorg_list_is_empty(&client->output_pending))
xorg_list_append(&client->output_pending, &output_pending_clients);
}
static inline void
output_pending_clear(ClientPtr client)
{
xorg_list_del(&client->output_pending);
}
static inline Bool any_output_pending(void) {
return !xorg_list_is_empty(&output_pending_clients);
}
#define SMART_MAX_PRIORITY (20)
#define SMART_MIN_PRIORITY (-20)

View File

@ -66,7 +66,6 @@ SOFTWARE.
#include "misc.h"
#include "osdep.h"
#include <X11/Xpoll.h>
#include "dixstruct.h"
#include "opaque.h"
#ifdef DPMSExtension
@ -146,22 +145,20 @@ Bool
WaitForSomething(Bool are_ready)
{
int i;
struct timeval waittime, *wt;
int timeout;
fd_set clientsReadable;
fd_set clientsWritable;
int curclient;
int selecterr;
static int nready;
int pollerr;
static Bool were_ready;
Bool timer_is_running;
CARD32 now = 0;
Bool someNotifyWriteReady = FALSE;
FD_ZERO(&clientsReadable);
FD_ZERO(&clientsWritable);
timer_is_running = were_ready;
if (nready)
if (were_ready && !are_ready) {
timer_is_running = FALSE;
SmartScheduleStopTimer();
nready = 0;
}
were_ready = FALSE;
#ifdef BUSFAULT
busfault_check();
@ -176,8 +173,6 @@ WaitForSomething(Bool are_ready)
if (are_ready) {
timeout = 0;
XFD_COPYSET(&AllSockets, &LastSelectMask);
XFD_UNSET(&LastSelectMask, &ClientsWithInput);
}
else {
timeout = -1;
@ -195,57 +190,39 @@ WaitForSomething(Bool are_ready)
timeout = 0;
}
}
XFD_COPYSET(&AllSockets, &LastSelectMask);
}
BlockHandler(&timeout);
if (timeout < 0)
wt = NULL;
else {
waittime.tv_sec = timeout / MILLI_PER_SECOND;
waittime.tv_usec = (timeout % MILLI_PER_SECOND) *
(1000000 / MILLI_PER_SECOND);
wt = &waittime;
}
if (NewOutputPending)
FlushAllOutput();
/* 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);
}
selecterr = GetErrno();
else
i = ospoll_wait(server_poll, timeout);
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 (are_ready) {
/*
* If no-one else is home, bail quickly
*/
XFD_COPYSET(&ClientsWithInput, &LastSelectMask);
XFD_COPYSET(&ClientsWithInput, &clientsReadable);
break;
}
if (*checkForInput[0] != *checkForInput[1])
@ -269,93 +246,39 @@ WaitForSomething(Bool are_ready)
}
}
else {
fd_set tmp_set;
if (*checkForInput[0] == *checkForInput[1]) {
if (timers) {
int expired = 0;
now = GetTimeInMillis();
if ((int) (timers->expires - now) <= 0)
expired = 1;
if (expired) {
OsBlockSignals();
while (timers && (int) (timers->expires - now) <= 0)
DoTimer(timers, now, &timers);
OsReleaseSignals();
return FALSE;
}
}
}
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;
}
}
XFD_ANDSET(&clientsReadable, &LastSelectMask, &AllClients);
XFD_ANDSET(&tmp_set, &LastSelectMask, &NotifyReadFds);
if (XFD_ANYSET(&tmp_set) || someNotifyWriteReady)
HandleNotifyFds();
if (are_ready || XFD_ANYSET(&clientsReadable))
break;
/* check here for DDXes that queue events during Block/Wakeup */
if (*checkForInput[0] != *checkForInput[1])
return FALSE;
if (timers) {
int expired = 0;
now = GetTimeInMillis();
if ((int) (timers->expires - now) <= 0)
expired = 1;
if (expired) {
OsBlockSignals();
while (timers && (int) (timers->expires - now) <= 0)
DoTimer(timers, now, &timers);
OsReleaseSignals();
return FALSE;
}
}
are_ready = clients_are_ready();
if (are_ready)
break;
}
}
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 (are_ready) {
were_ready = TRUE;
if (!timer_is_running)
SmartScheduleStartTimer();
}
if (nready)
SmartScheduleStartTimer();
return TRUE;
}

View File

@ -78,6 +78,7 @@ SOFTWARE.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <poll.h>
#ifndef WIN32
#include <sys/socket.h>
@ -120,20 +121,10 @@ SOFTWARE.
#include "probes.h"
static int lastfdesc; /* maximum file descriptor */
struct ospoll *server_poll;
fd_set NotifyReadFds; /* mask for other file descriptors */
fd_set NotifyWriteFds; /* mask for other write file descriptors */
fd_set AllSockets; /* select on this */
fd_set AllClients; /* available clients */
fd_set LastSelectMask; /* mask returned from last select call */
fd_set LastSelectWriteMask; /* mask returned from last select call */
fd_set ClientsWithInput; /* clients with FULL requests in buffer */
fd_set ClientsWriteBlocked; /* clients who cannot receive output */
fd_set OutputPending; /* clients with reply/event data ready to go */
int MaxClients = 0;
int NumNotifyWriteFd; /* Number of NotifyFd members with write set */
Bool NewOutputPending; /* not yet attempted to write some new output */
Bool AnyWritesPending; /* true if some client blocked on write or NotifyFd with write */
Bool NoListenAll; /* Don't establish any listening sockets */
static Bool RunFromSmartParent; /* send SIGUSR1 to parent process */
@ -145,16 +136,17 @@ static Pid_t ParentProcess;
static Bool debug_conns = FALSE;
fd_set IgnoredClientsWithInput;
static fd_set GrabImperviousClients;
static fd_set SavedAllClients;
static fd_set SavedAllSockets;
static fd_set SavedClientsWithInput;
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,11 +384,6 @@ CreateWellKnownSockets(void)
int i;
int partial;
FD_ZERO(&AllSockets);
FD_ZERO(&AllClients);
FD_ZERO(&LastSelectMask);
FD_ZERO(&ClientsWithInput);
#if !defined(WIN32)
for (i = 0; i < MaxClients; i++)
ConnectionTranslation[i] = 0;
@ -751,6 +738,23 @@ ClientAuthorized(ClientPtr client,
return ((char *) NULL);
}
static void
ClientReady(int fd, int xevents, void *data)
{
ClientPtr client = data;
if (xevents & X_NOTIFY_ERROR) {
CloseDownClient(client);
return;
}
if (xevents & X_NOTIFY_READ)
mark_client_ready(client);
if (xevents & X_NOTIFY_WRITE) {
ospoll_mute(server_poll, fd, X_NOTIFY_WRITE);
NewOutputPending = TRUE;
}
}
static ClientPtr
AllocNewConnection(XtransConnInfo trans_conn, int fd, CARD32 conn_time)
{
@ -774,6 +778,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,14 +789,11 @@ AllocNewConnection(XtransConnInfo trans_conn, int fd, CARD32 conn_time)
#else
SetConnectionTranslation(fd, client->index);
#endif
if (GrabInProgress) {
FD_SET(fd, &SavedAllClients);
FD_SET(fd, &SavedAllSockets);
}
else {
FD_SET(fd, &AllClients);
FD_SET(fd, &AllSockets);
}
ospoll_add(server_poll, fd,
ospoll_trigger_edge,
ClientReady,
client);
set_poll_client(client);
#ifdef DEBUG
ErrorF("AllocNewConnection: client index = %d, socket fd = %d\n",
@ -942,19 +944,7 @@ CloseDownFileDescriptor(OsCommPtr oc)
#else
SetConnectionTranslation(connection, 0);
#endif
FD_CLR(connection, &AllSockets);
FD_CLR(connection, &AllClients);
FD_CLR(connection, &ClientsWithInput);
FD_CLR(connection, &GrabImperviousClients);
if (GrabInProgress) {
FD_CLR(connection, &SavedAllSockets);
FD_CLR(connection, &SavedAllClients);
FD_CLR(connection, &SavedClientsWithInput);
}
FD_CLR(connection, &ClientsWriteBlocked);
if (!XFD_ANYSET(&ClientsWriteBlocked) && NumNotifyWriteFd == 0)
AnyWritesPending = FALSE;
FD_CLR(connection, &OutputPending);
ospoll_remove(server_poll, connection);
}
/*****************
@ -969,53 +959,25 @@ CloseDownFileDescriptor(OsCommPtr oc)
void
CheckConnections(void)
{
#ifndef WIN32
fd_mask mask;
#endif
fd_set tmask;
int curclient, curoff;
int i;
struct timeval notime;
int r;
#ifdef WIN32
fd_set savedAllClients;
#endif
for (i = 1; i < currentMaxClients; i++) {
ClientPtr client = clients[i];
if (!client->clientGone) {
OsCommPtr oc = (OsCommPtr) client->osPrivate;
struct pollfd poll_fd;
notime.tv_sec = 0;
notime.tv_usec = 0;
poll_fd.fd = oc->fd;
poll_fd.events = POLLIN|POLLOUT;
#ifndef WIN32
for (i = 0; i < howmany(XFD_SETSIZE, NFDBITS); i++) {
mask = AllClients.fds_bits[i];
while (mask) {
curoff = mffs(mask) - 1;
curclient = curoff + (i * (sizeof(fd_mask) * 8));
FD_ZERO(&tmask);
FD_SET(curclient, &tmask);
do {
r = Select(curclient + 1, &tmask, NULL, NULL, &notime);
r = poll(&poll_fd, 1, 0);
} while (r < 0 && (errno == EINTR || errno == EAGAIN));
if (r < 0)
if (ConnectionTranslation[curclient] > 0)
CloseDownClient(clients[ConnectionTranslation[curclient]]);
mask &= ~((fd_mask) 1 << curoff);
CloseDownClient(client);
}
}
#else
XFD_COPYSET(&AllClients, &savedAllClients);
for (i = 0; i < XFD_SETCOUNT(&savedAllClients); i++) {
curclient = XFD_FD(&savedAllClients, i);
FD_ZERO(&tmask);
FD_SET(curclient, &tmask);
do {
r = Select(curclient + 1, &tmask, NULL, NULL, &notime);
} while (r < 0 && (errno == EINTR || errno == EAGAIN));
if (r < 0)
if (GetConnectionTranslation(curclient) > 0)
CloseDownClient(clients[GetConnectionTranslation(curclient)]);
}
#endif
}
/*****************
@ -1045,28 +1007,22 @@ CloseDownConnection(ClientPtr client)
}
struct notify_fd {
struct xorg_list list;
int fd;
int mask;
NotifyFdProcPtr notify;
void *data;
};
static struct xorg_list notify_fds;
/*****************
* HandleNotifyFd
* A poll callback to be called when the registered
* file descriptor is ready.
*****************/
void
InitNotifyFds(void)
static void
HandleNotifyFd(int fd, int xevents, void *data)
{
struct notify_fd *s, *next;
static int been_here;
if (been_here)
xorg_list_for_each_entry_safe(s, next, &notify_fds, list)
RemoveNotifyFd(s->fd);
xorg_list_init(&notify_fds);
NumNotifyWriteFd = 0;
been_here = 1;
struct notify_fd *n = data;
n->notify(fd, xevents, n->data);
}
/*****************
@ -1079,56 +1035,32 @@ Bool
SetNotifyFd(int fd, NotifyFdProcPtr notify, int mask, void *data)
{
struct notify_fd *n;
int changes;
xorg_list_for_each_entry(n, &notify_fds, list)
if (n->fd == fd)
break;
if (&n->list == &notify_fds) {
n = ospoll_data(server_poll, fd);
if (!n) {
if (mask == 0)
return TRUE;
n = calloc(1, sizeof (struct notify_fd));
if (!n)
return FALSE;
n->fd = fd;
xorg_list_add(&n->list, &notify_fds);
}
changes = n->mask ^ mask;
if (changes & X_NOTIFY_READ) {
if (mask & X_NOTIFY_READ) {
FD_SET(fd, &NotifyReadFds);
FD_SET(fd, &AllSockets);
if (GrabInProgress)
FD_SET(fd, &SavedAllSockets);
} else {
FD_CLR(fd, &AllSockets);
if (GrabInProgress)
FD_CLR(fd, &SavedAllSockets);
FD_CLR(fd, &NotifyReadFds);
}
}
if (changes & X_NOTIFY_WRITE) {
if (mask & X_NOTIFY_WRITE) {
FD_SET(fd, &NotifyWriteFds);
if (!NumNotifyWriteFd++)
AnyWritesPending = TRUE;
} else {
FD_CLR(fd, &NotifyWriteFds);
if (!--NumNotifyWriteFd)
if (!XFD_ANYSET(&ClientsWriteBlocked))
AnyWritesPending = FALSE;
}
ospoll_add(server_poll, fd,
ospoll_trigger_level,
HandleNotifyFd,
n);
}
if (mask == 0) {
xorg_list_del(&n->list);
ospoll_remove(server_poll, fd);
free(n);
} else {
int listen = mask & ~n->mask;
int mute = n->mask & ~mask;
if (listen)
ospoll_listen(server_poll, fd, listen);
if (mute)
ospoll_mute(server_poll, fd, mute);
n->mask = mask;
n->data = data;
n->notify = notify;
@ -1137,28 +1069,6 @@ SetNotifyFd(int fd, NotifyFdProcPtr notify, int mask, void *data)
return TRUE;
}
/*****************
* HandlNotifyFds
* A WorkProc to be called when any of the registered
* file descriptors are readable.
*****************/
void
HandleNotifyFds(void)
{
struct notify_fd *n, *next;
xorg_list_for_each_entry_safe(n, next, &notify_fds, list) {
int ready = 0;
if ((n->mask & X_NOTIFY_READ) && FD_ISSET(n->fd, &LastSelectMask))
ready |= X_NOTIFY_READ;
if ((n->mask & X_NOTIFY_WRITE) & FD_ISSET(n->fd, &LastSelectWriteMask))
ready |= X_NOTIFY_WRITE;
if (ready != 0)
n->notify(n->fd, ready, n->data);
}
}
/*****************
* OnlyListenToOneClient:
* Only accept requests from one client. Continue to handle new
@ -1172,30 +1082,17 @@ HandleNotifyFds(void)
int
OnlyListenToOneClient(ClientPtr client)
{
OsCommPtr oc = (OsCommPtr) client->osPrivate;
int rc, connection = oc->fd;
int rc;
rc = XaceHook(XACE_SERVER_ACCESS, client, DixGrabAccess);
if (rc != Success)
return rc;
if (!GrabInProgress) {
XFD_COPYSET(&ClientsWithInput, &SavedClientsWithInput);
XFD_ANDSET(&ClientsWithInput,
&ClientsWithInput, &GrabImperviousClients);
if (FD_ISSET(connection, &SavedClientsWithInput)) {
FD_CLR(connection, &SavedClientsWithInput);
FD_SET(connection, &ClientsWithInput);
}
XFD_UNSET(&SavedClientsWithInput, &GrabImperviousClients);
XFD_COPYSET(&AllSockets, &SavedAllSockets);
XFD_COPYSET(&AllClients, &SavedAllClients);
XFD_UNSET(&AllSockets, &AllClients);
XFD_ANDSET(&AllClients, &AllClients, &GrabImperviousClients);
FD_SET(connection, &AllClients);
XFD_ORSET(&AllSockets, &AllSockets, &AllClients);
GrabInProgress = client->index;
set_poll_clients();
}
return rc;
}
@ -1208,10 +1105,8 @@ void
ListenToAllClients(void)
{
if (GrabInProgress) {
XFD_ORSET(&AllSockets, &AllSockets, &SavedAllSockets);
XFD_ORSET(&AllClients, &AllClients, &SavedAllClients);
XFD_ORSET(&ClientsWithInput, &ClientsWithInput, &SavedClientsWithInput);
GrabInProgress = 0;
set_poll_clients();
}
}
@ -1225,7 +1120,6 @@ void
IgnoreClient(ClientPtr client)
{
OsCommPtr oc = (OsCommPtr) client->osPrivate;
int connection = oc->fd;
client->ignoreCount++;
if (client->ignoreCount > 1)
@ -1233,25 +1127,9 @@ IgnoreClient(ClientPtr client)
isItTimeToYield = TRUE;
mark_client_not_ready(client);
if (!GrabInProgress || FD_ISSET(connection, &AllClients)) {
if (FD_ISSET(connection, &ClientsWithInput))
FD_SET(connection, &IgnoredClientsWithInput);
else
FD_CLR(connection, &IgnoredClientsWithInput);
FD_CLR(connection, &ClientsWithInput);
FD_CLR(connection, &AllSockets);
FD_CLR(connection, &AllClients);
FD_CLR(connection, &LastSelectMask);
}
else {
if (FD_ISSET(connection, &SavedClientsWithInput))
FD_SET(connection, &IgnoredClientsWithInput);
else
FD_CLR(connection, &IgnoredClientsWithInput);
FD_CLR(connection, &SavedClientsWithInput);
FD_CLR(connection, &SavedAllSockets);
FD_CLR(connection, &SavedAllClients);
}
oc->flags |= OS_COMM_IGNORED;
set_poll_client(client);
}
/****************
@ -1263,28 +1141,15 @@ void
AttendClient(ClientPtr client)
{
OsCommPtr oc = (OsCommPtr) client->osPrivate;
int connection = oc->fd;
client->ignoreCount--;
if (client->ignoreCount)
return;
if (!GrabInProgress || GrabInProgress == client->index ||
FD_ISSET(connection, &GrabImperviousClients)) {
FD_SET(connection, &AllClients);
FD_SET(connection, &AllSockets);
FD_SET(connection, &LastSelectMask);
if (FD_ISSET(connection, &IgnoredClientsWithInput)) {
FD_SET(connection, &ClientsWithInput);
mark_client_ready(client);
}
}
else {
FD_SET(connection, &SavedAllClients);
FD_SET(connection, &SavedAllSockets);
if (FD_ISSET(connection, &IgnoredClientsWithInput))
FD_SET(connection, &SavedClientsWithInput);
}
oc->flags &= ~OS_COMM_IGNORED;
set_poll_client(client);
if (listen_to_client(client))
mark_client_ready(client);
}
/* make client impervious to grabs; assume only executing client calls this */
@ -1293,9 +1158,9 @@ void
MakeClientGrabImpervious(ClientPtr client)
{
OsCommPtr oc = (OsCommPtr) client->osPrivate;
int connection = oc->fd;
FD_SET(connection, &GrabImperviousClients);
oc->flags |= OS_COMM_GRAB_IMPERVIOUS;
set_poll_client(client);
if (ServerGrabCallback) {
ServerGrabInfoRec grabinfo;
@ -1312,18 +1177,10 @@ void
MakeClientGrabPervious(ClientPtr client)
{
OsCommPtr oc = (OsCommPtr) client->osPrivate;
int connection = oc->fd;
FD_CLR(connection, &GrabImperviousClients);
if (GrabInProgress && (GrabInProgress != client->index)) {
if (FD_ISSET(connection, &ClientsWithInput)) {
FD_SET(connection, &SavedClientsWithInput);
FD_CLR(connection, &ClientsWithInput);
}
FD_CLR(connection, &AllSockets);
FD_CLR(connection, &AllClients);
isItTimeToYield = TRUE;
}
oc->flags &= ~OS_COMM_GRAB_IMPERVIOUS;
set_poll_client(client);
isItTimeToYield = TRUE;
if (ServerGrabCallback) {
ServerGrabInfoRec grabinfo;
@ -1405,3 +1262,46 @@ AddClientOnOpenFD(int fd)
return TRUE;
}
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))
ospoll_listen(server_poll, oc->fd, X_NOTIFY_READ);
else
ospoll_mute(server_poll, oc->fd, X_NOTIFY_READ);
}
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);
}
}

103
os/io.c
View File

@ -74,7 +74,6 @@ SOFTWARE.
#include <X11/Xproto.h>
#include "os.h"
#include "osdep.h"
#include <X11/Xpoll.h>
#include "opaque.h"
#include "dixstruct.h"
#include "misc.h"
@ -188,7 +187,7 @@ static void
YieldControlNoInput(int fd)
{
YieldControl();
FD_CLR(fd, &ClientsWithInput);
ospoll_reset_events(server_poll, fd);
}
static void
@ -439,24 +438,8 @@ ReadRequestFromClient(ClientPtr client)
*/
gotnow -= needed;
if (gotnow >= sizeof(xReq)) {
request = (xReq *) (oci->bufptr + needed);
if (gotnow >= (result = (get_req_len(request, client) << 2))
&& (result ||
(client->big_requests &&
(gotnow >= sizeof(xBigReq) &&
gotnow >= (get_big_req_len(request, client) << 2))))
)
FD_SET(fd, &ClientsWithInput);
else {
FD_CLR(fd, &ClientsWithInput);
}
}
else {
if (!gotnow)
AvailableInput = oc;
FD_CLR(fd, &ClientsWithInput);
}
if (!gotnow)
AvailableInput = oc;
if (move_header) {
request = (xReq *) oci->bufptr;
oci->bufptr += (sizeof(xBigReq) - sizeof(xReq));
@ -549,7 +532,7 @@ InsertFakeRequest(ClientPtr client, char *data, int count)
gotnow += count;
if ((gotnow >= sizeof(xReq)) &&
(gotnow >= (int) (get_req_len((xReq *) oci->bufptr, client) << 2)))
FD_SET(fd, &ClientsWithInput);
mark_client_ready(client);
else
YieldControlNoInput(fd);
return TRUE;
@ -589,12 +572,8 @@ ResetCurrentRequest(ClientPtr client)
}
}
if (gotnow >= (needed << 2)) {
if (FD_ISSET(fd, &AllClients)) {
FD_SET(fd, &ClientsWithInput);
}
else {
FD_SET(fd, &IgnoredClientsWithInput);
}
if (listen_to_client(client))
mark_client_ready(client);
YieldControl();
}
else
@ -615,16 +594,10 @@ ResetCurrentRequest(ClientPtr client)
void
FlushAllOutput(void)
{
register int index, base;
register fd_mask mask; /* raphael */
OsCommPtr oc;
register ClientPtr client;
register ClientPtr client, tmp;
Bool newoutput = NewOutputPending;
#if defined(WIN32)
fd_set newOutputPending;
#endif
if (FlushCallback)
CallCallbacks(&FlushCallback, NULL);
@ -639,48 +612,14 @@ FlushAllOutput(void)
CriticalOutputPending = FALSE;
NewOutputPending = FALSE;
#ifndef WIN32
for (base = 0; base < howmany(XFD_SETSIZE, NFDBITS); base++) {
mask = OutputPending.fds_bits[base];
OutputPending.fds_bits[base] = 0;
while (mask) {
index = ffs(mask) - 1;
mask &= ~lowbit(mask);
if ((index =
ConnectionTranslation[(base * (sizeof(fd_mask) * 8)) +
index]) == 0)
continue;
client = clients[index];
if (client->clientGone)
continue;
oc = (OsCommPtr) client->osPrivate;
if (FD_ISSET(oc->fd, &ClientsWithInput)) {
FD_SET(oc->fd, &OutputPending); /* set the bit again */
NewOutputPending = TRUE;
}
else
(void) FlushClient(client, oc, (char *) NULL, 0);
}
}
#else /* WIN32 */
FD_ZERO(&newOutputPending);
for (base = 0; base < XFD_SETCOUNT(&OutputPending); base++) {
index = XFD_FD(&OutputPending, base);
if ((index = GetConnectionTranslation(index)) == 0)
continue;
client = clients[index];
xorg_list_for_each_entry_safe(client, tmp, &output_pending_clients, output_pending) {
if (client->clientGone)
continue;
oc = (OsCommPtr) client->osPrivate;
if (FD_ISSET(oc->fd, &ClientsWithInput)) {
FD_SET(oc->fd, &newOutputPending); /* set the bit again */
NewOutputPending = TRUE;
}
else
if (!client_is_ready(client)) {
oc = (OsCommPtr) client->osPrivate;
(void) FlushClient(client, oc, (char *) NULL, 0);
}
}
XFD_COPYSET(&newOutputPending, &OutputPending);
#endif /* WIN32 */
}
void
@ -822,8 +761,8 @@ WriteToClient(ClientPtr who, int count, const void *__buf)
}
#endif
if (oco->count == 0 || oco->count + count + padBytes > oco->size) {
FD_CLR(oc->fd, &OutputPending);
if (!XFD_ANYSET(&OutputPending)) {
output_pending_clear(who);
if (!any_output_pending()) {
CriticalOutputPending = FALSE;
NewOutputPending = FALSE;
}
@ -835,7 +774,7 @@ WriteToClient(ClientPtr who, int count, const void *__buf)
}
NewOutputPending = TRUE;
FD_SET(oc->fd, &OutputPending);
output_pending_mark(who);
memmove((char *) oco->buf + oco->count, buf, count);
oco->count += count;
if (padBytes) {
@ -859,7 +798,6 @@ int
FlushClient(ClientPtr who, OsCommPtr oc, const void *__extraBuf, int extraCount)
{
ConnectionOutputPtr oco = oc->output;
int connection = oc->fd;
XtransConnInfo trans_conn = oc->trans_conn;
struct iovec iov[3];
static char padBuffer[3];
@ -932,8 +870,7 @@ FlushClient(ClientPtr who, OsCommPtr oc, const void *__extraBuf, int extraCount)
/* If we've arrived here, then the client is stuffed to the gills
and not ready to accept more. Make a note of it and buffer
the rest. */
FD_SET(connection, &ClientsWriteBlocked);
AnyWritesPending = TRUE;
output_pending_mark(who);
if (written < oco->count) {
if (written > 0) {
@ -973,6 +910,8 @@ FlushClient(ClientPtr who, OsCommPtr oc, const void *__extraBuf, int extraCount)
extraBuf + written, len);
oco->count = notWritten; /* this will include the pad */
ospoll_listen(server_poll, oc->fd, X_NOTIFY_WRITE);
/* return only the amount explicitly requested */
return extraCount;
}
@ -995,12 +934,8 @@ FlushClient(ClientPtr who, OsCommPtr oc, const void *__extraBuf, int extraCount)
/* everything was flushed out */
oco->count = 0;
/* check to see if this client was write blocked */
if (AnyWritesPending) {
FD_CLR(oc->fd, &ClientsWriteBlocked);
if (!XFD_ANYSET(&ClientsWriteBlocked) && NumNotifyWriteFd == 0)
AnyWritesPending = FALSE;
}
output_pending_clear(who);
if (oco->size > BUFWATERMARK) {
free(oco->buf);
free(oco);

View File

@ -162,8 +162,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 */ ,
@ -173,24 +177,13 @@ extern int FlushClient(ClientPtr /*who */ ,
extern void FreeOsBuffers(OsCommPtr /*oc */
);
extern void InitNotifyFds(void);
extern void HandleNotifyFds(void);
#include "dix.h"
#include "ospoll.h"
extern fd_set AllSockets;
extern fd_set AllClients;
extern fd_set LastSelectMask;
extern fd_set LastSelectWriteMask;
extern fd_set WellKnownConnections;
extern fd_set EnabledDevices;
extern fd_set NotifyReadFds;
extern fd_set NotifyWriteFds;
extern fd_set ClientsWithInput;
extern fd_set ClientsWriteBlocked;
extern fd_set OutputPending;
extern fd_set IgnoredClientsWithInput;
extern struct ospoll *server_poll;
Bool
listen_to_client(ClientPtr client);
#if !defined(WIN32) || defined(__CYGWIN__)
extern int *ConnectionTranslation;
@ -201,8 +194,6 @@ extern void ClearConnectionTranslation(void);
#endif
extern Bool NewOutputPending;
extern Bool AnyWritesPending;
extern Bool NumNotifyWriteFd;
extern WorkQueuePtr workQueue;

View File

@ -195,7 +195,9 @@ OsInit(void)
#ifdef BUSFAULT
busfault_init();
#endif
InitNotifyFds();
server_poll = ospoll_create();
if (!server_poll)
FatalError("failed to allocate poll structure");
#ifdef HAVE_BACKTRACE
/*

View File

@ -39,7 +39,6 @@
#include <X11/X.h>
#include <X11/Xmd.h>
#include "misc.h"
#include <X11/Xpoll.h>
#include "osdep.h"
#include "input.h"
#include "dixstruct.h"