diff options
author | Keith Packard <keithp@keithp.com> | 2015-11-11 22:02:03 -0800 |
---|---|---|
committer | Adam Jackson <ajax@redhat.com> | 2015-12-01 13:55:07 -0500 |
commit | 4020aacd1fc5b9c63369f011aeb9120af9c55218 (patch) | |
tree | 95bfe1a2ce69e1b640d742031ba9740958ab68ff /os | |
parent | 0c41b7af4ab0c8d22b88f201293f59524d1e7317 (diff) |
os: Implement support for NotifyFd X_NOTIFY_WRITE
This adds the ability to be notified when a file descriptor is
available for writing.
Reviewed-by: Adam Jackson <ajax@redhat.com>
Signed-off-by: Keith Packard <keithp@keithp.com>
Diffstat (limited to 'os')
-rw-r--r-- | os/WaitFor.c | 30 | ||||
-rw-r--r-- | os/connection.c | 40 | ||||
-rw-r--r-- | os/io.c | 8 | ||||
-rw-r--r-- | os/osdep.h | 5 |
4 files changed, 59 insertions, 24 deletions
diff --git a/os/WaitFor.c b/os/WaitFor.c index 12b21bb21..b579e1b01 100644 --- a/os/WaitFor.c +++ b/os/WaitFor.c @@ -156,6 +156,7 @@ WaitForSomething(int *pClientsReady) fd_set devicesReadable; CARD32 now = 0; Bool someReady = FALSE; + Bool someNotifyWriteReady = FALSE; FD_ZERO(&clientsReadable); FD_ZERO(&clientsWritable); @@ -213,9 +214,10 @@ WaitForSomething(int *pClientsReady) /* keep this check close to select() call to minimize race */ if (dispatchException) i = -1; - else if (AnyClientsWriteBlocked) { - XFD_COPYSET(&ClientsWriteBlocked, &clientsWritable); - i = Select(MaxClients, &LastSelectMask, &clientsWritable, NULL, wt); + 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); @@ -291,12 +293,20 @@ WaitForSomething(int *pClientsReady) } if (someReady) XFD_ORSET(&LastSelectMask, &ClientsWithInput, &LastSelectMask); - if (AnyClientsWriteBlocked && XFD_ANYSET(&clientsWritable)) { - NewOutputPending = TRUE; - XFD_ORSET(&OutputPending, &clientsWritable, &OutputPending); - XFD_UNSET(&ClientsWriteBlocked, &clientsWritable); - if (!XFD_ANYSET(&ClientsWriteBlocked)) - AnyClientsWriteBlocked = 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(&devicesReadable, &LastSelectMask, &EnabledDevices); @@ -307,7 +317,7 @@ WaitForSomething(int *pClientsReady) (void *) &LastSelectMask); XFD_ANDSET(&tmp_set, &LastSelectMask, &NotifyReadFds); - if (XFD_ANYSET(&tmp_set)) + if (XFD_ANYSET(&tmp_set) || someNotifyWriteReady) HandleNotifyFds(); if (XFD_ANYSET(&devicesReadable) || XFD_ANYSET(&clientsReadable)) diff --git a/os/connection.c b/os/connection.c index 0df439189..4da01a641 100644 --- a/os/connection.c +++ b/os/connection.c @@ -124,15 +124,18 @@ static int lastfdesc; /* maximum file descriptor */ fd_set WellKnownConnections; /* Listener mask */ fd_set EnabledDevices; /* mask for input devices that are on */ 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 AnyClientsWriteBlocked; /* true if some client blocked on write */ +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 */ @@ -969,8 +972,8 @@ CloseDownFileDescriptor(OsCommPtr oc) FD_CLR(connection, &SavedClientsWithInput); } FD_CLR(connection, &ClientsWriteBlocked); - if (!XFD_ANYSET(&ClientsWriteBlocked)) - AnyClientsWriteBlocked = FALSE; + if (!XFD_ANYSET(&ClientsWriteBlocked) && NumNotifyWriteFd == 0) + AnyWritesPending = FALSE; FD_CLR(connection, &OutputPending); } @@ -1112,6 +1115,7 @@ InitNotifyFds(void) RemoveNotifyFd(s->fd); xorg_list_init(¬ify_fds); + NumNotifyWriteFd = 0; been_here = 1; } @@ -1153,6 +1157,20 @@ SetNotifyFd(int fd, NotifyFdProcPtr notify, int mask, void *data) 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; + } + } + if (mask == 0) { xorg_list_del(&n->list); free(n); @@ -1174,12 +1192,16 @@ SetNotifyFd(int fd, NotifyFdProcPtr notify, int mask, void *data) void HandleNotifyFds(void) { - struct notify_fd *s, *next; - - xorg_list_for_each_entry_safe(s, next, ¬ify_fds, list) { - if (FD_ISSET(s->fd, &LastSelectMask)) { - s->notify(s->fd, X_NOTIFY_READ, s->data); - } + struct notify_fd *n, *next; + + xorg_list_for_each_entry_safe(n, next, ¬ify_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); } } @@ -946,7 +946,7 @@ FlushClient(ClientPtr who, OsCommPtr oc, const void *__extraBuf, int extraCount) and not ready to accept more. Make a note of it and buffer the rest. */ FD_SET(connection, &ClientsWriteBlocked); - AnyClientsWriteBlocked = TRUE; + AnyWritesPending = TRUE; if (written < oco->count) { if (written > 0) { @@ -1009,10 +1009,10 @@ 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 (AnyClientsWriteBlocked) { + if (AnyWritesPending) { FD_CLR(oc->fd, &ClientsWriteBlocked); - if (!XFD_ANYSET(&ClientsWriteBlocked)) - AnyClientsWriteBlocked = FALSE; + if (!XFD_ANYSET(&ClientsWriteBlocked) && NumNotifyWriteFd == 0) + AnyWritesPending = FALSE; } if (oco->size > BUFWATERMARK) { free(oco->buf); diff --git a/os/osdep.h b/os/osdep.h index 2bfc783f0..2fbfc48f6 100644 --- a/os/osdep.h +++ b/os/osdep.h @@ -168,9 +168,11 @@ extern void HandleNotifyFds(void); 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; @@ -185,7 +187,8 @@ extern void ClearConnectionTranslation(void); #endif extern Bool NewOutputPending; -extern Bool AnyClientsWriteBlocked; +extern Bool AnyWritesPending; +extern Bool NumNotifyWriteFd; extern WorkQueuePtr workQueue; |