[PATCH] Add APIs for selecting on write fds.

Keith Packard keithp at keithp.com
Tue Jun 19 12:00:12 PDT 2012


This adds API support for waking the server when an fd becomes
writable.

    void AddWriteSocket(int fd);

	Add an FD to the select write mask; the server will wake when
	this fd is writable.

    void RemoveWriteSocket(int fd);

	Remove the FD from the select write mask.

	Note that there is no automated mechanism for emptying the set of
	fds. The caller is responsible for removing the fd whenever
	appropriate, including when the fd is closed, and when the
	user no longer has pending write data.

    Bool CheckWriteSocket(int fd);

	Checks if the last select call marked this fd as
	writable. This value persists until select is called again.

This patch also adds a helper function for sockets used for reading:

    Bool CheckReadSocket(int fd);

	A matching function that checks for fds marked as readable
	that have been added with AddGeneralSocket or
	AddEnabledDevice.

The mechanism used is to keep a separate fd_set of write sockets, and
OR that with the client write mask to create a global select write
mask. The only other change necessary in WaitFor is to mask out the
resulting non-client fds when checking for unblocked client sockets.

Signed-off-by: Keith Packard <keithp at keithp.com>
---
 include/os.h |    8 ++++++
 os/WaitFor.c |   79 +++++++++++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 78 insertions(+), 9 deletions(-)

diff --git a/include/os.h b/include/os.h
index 276eb52..efb2b65 100644
--- a/include/os.h
+++ b/include/os.h
@@ -157,6 +157,14 @@ extern _X_EXPORT void MakeClientGrabImpervious(ClientPtr /*client */ );
 
 extern _X_EXPORT void MakeClientGrabPervious(ClientPtr /*client */ );
 
+extern _X_EXPORT void AddWriteSocket(int fd);
+
+extern _X_EXPORT void RemoveWriteSocket(int fd);
+
+extern _X_EXPORT Bool CheckWriteSocket(int fd);
+
+extern _X_EXPORT Bool CheckReadSocket(int fd);
+
 #ifdef XQUARTZ
 extern void ListenOnOpenFD(int /* fd */ , int /* noxauth */ );
 #endif
diff --git a/os/WaitFor.c b/os/WaitFor.c
index 393890f..bf03273 100644
--- a/os/WaitFor.c
+++ b/os/WaitFor.c
@@ -123,6 +123,62 @@ struct _OsTimerRec {
 static void DoTimer(OsTimerPtr timer, CARD32 now, OsTimerPtr *prev);
 static void CheckAllTimers(void);
 static OsTimerPtr timers = NULL;
+static fd_set WriteSelectMask;
+static Bool AnyWriteSelectMask;
+static fd_set LastSelectWriteMask;
+
+/*****************
+ * AddWriteSocket:
+ *     Add 'fd' to the list of write descriptors that will
+ *     wake the server from select.
+ */
+
+void
+AddWriteSocket(int fd)
+{
+    FD_SET(fd, &WriteSelectMask);
+    AnyWriteSelectMask = TRUE;
+}
+
+/*****************
+ * RemoveWriteSocket:
+ *     Remove 'fd' from the list of write descriptors that will
+ *     wake the server from select.
+ */
+
+void
+RemoveWriteSocket(int fd)
+{
+    FD_CLR(fd, &WriteSelectMask);
+    AnyWriteSelectMask = XFD_ANYSET(&WriteSelectMask);
+}
+
+/*****************
+ * CheckWriteSocket:
+ *     Called from a WakeupHandler to check of 'fd'
+ *     was marked as writable during the last select
+ *     call
+ */
+
+Bool
+CheckWriteSocket(int fd)
+{
+    return AnyWriteSelectMask && FD_ISSET(fd, &LastSelectWriteMask);
+}
+
+/*****************
+ * CheckReadSocket:
+ *     Called from a WakeupHandler to check of 'fd'
+ *     was marked as readable during the last select
+ *     call
+ */
+
+Bool
+CheckReadSocket(int fd)
+{
+    return FD_ISSET(fd, &LastSelectMask);
+}
+
 
 /*****************
  * WaitForSomething:
@@ -213,9 +269,11 @@ 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 (AnyClientsWriteBlocked || AnyWriteSelectMask) {
+            XFD_COPYSET(&ClientsWriteBlocked, &LastSelectWriteMask);
+	    if (AnyWriteSelectMask)
+		XFD_ORSET(&LastSelectWriteMask, &WriteSelectMask, &LastSelectWriteMask);
+            i = Select(MaxClients, &LastSelectMask, &LastSelectWriteMask, NULL, wt);
         }
         else {
             i = Select(MaxClients, &LastSelectMask, NULL, NULL, wt);
@@ -285,12 +343,15 @@ 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 (AnyClientsWriteBlocked) {
+		XFD_ANDSET(&clientsWritable, &LastSelectWriteMask, &ClientsWriteBlocked);
+		if (XFD_ANYSET(&clientsWritable)) {
+		    NewOutputPending = TRUE;
+		    XFD_ORSET(&OutputPending, &clientsWritable, &OutputPending);
+		    XFD_UNSET(&ClientsWriteBlocked, &clientsWritable);
+		    if (!XFD_ANYSET(&ClientsWriteBlocked))
+			AnyClientsWriteBlocked = FALSE;
+		}
             }
 
             XFD_ANDSET(&devicesReadable, &LastSelectMask, &EnabledDevices);
-- 
1.7.10



More information about the xorg-devel mailing list