[PATCH xserver 07/24] os: Add NotifyFd interfaces

Keith Packard keithp at keithp.com
Sun Sep 20 23:16:18 PDT 2015


This provides a callback-based interface to monitor file
descriptors beyond the usual client and device interfaces.

Modules within the server using file descriptors for reading and/or
writing can call

    Bool SetNotifyFd(int fd, NotifyFdProcPtr notify_fd, int mask, void *data);

mask can be any combination of X_NOTIFY_READ and X_NOTIFY_WRITE.

When 'fd' becomes readable or writable, the notify_fd function will be
called with the 'fd', the ready conditions and 'data' values as arguments,

When the module no longer needs to monitor the fd, it will call

    void RemoveNotifyFd(int fd);

RemoveNotifyFd may be called from the notify function.

Signed-off-by: Keith Packard <keithp at keithp.com>
---
 include/os.h    | 13 ++++++++
 os/WaitFor.c    |  4 +++
 os/connection.c | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 os/osdep.h      |  5 ++++
 os/osinit.c     |  1 +
 5 files changed, 116 insertions(+)

diff --git a/include/os.h b/include/os.h
index 9937f2e..aed2e2f 100644
--- a/include/os.h
+++ b/include/os.h
@@ -154,6 +154,19 @@ extern _X_EXPORT void AddEnabledDevice(int /*fd */ );
 
 extern _X_EXPORT void RemoveEnabledDevice(int /*fd */ );
 
+typedef void (*NotifyFdProcPtr)(int fd, int ready, void *data);
+
+#define X_NOTIFY_NONE   0
+#define X_NOTIFY_READ   1
+#define X_NOTIFY_WRITE  2
+
+extern _X_EXPORT Bool SetNotifyFd(int fd, NotifyFdProcPtr notify_fd, int mask, void *data);
+
+static inline void RemoveNotifyFd(int fd)
+{
+    (void) SetNotifyFd(fd, NULL, X_NOTIFY_NONE, NULL);
+}
+
 extern _X_EXPORT int OnlyListenToOneClient(ClientPtr /*client */ );
 
 extern _X_EXPORT void ListenToAllClients(void);
diff --git a/os/WaitFor.c b/os/WaitFor.c
index 424cdfc..b4c2675 100644
--- a/os/WaitFor.c
+++ b/os/WaitFor.c
@@ -305,6 +305,10 @@ WaitForSomething(int *pClientsReady)
                 QueueWorkProc(EstablishNewConnections, NULL,
                               (void *) &LastSelectMask);
 
+            XFD_ANDSET(&tmp_set, &LastSelectMask, &NotifyReadFds);
+            if (XFD_ANYSET(&tmp_set))
+                HandleNotifyFds();
+
             if (XFD_ANYSET(&devicesReadable) || XFD_ANYSET(&clientsReadable))
                 break;
             /* check here for DDXes that queue events during Block/Wakeup */
diff --git a/os/connection.c b/os/connection.c
index 3d33c41..4f2e989 100644
--- a/os/connection.c
+++ b/os/connection.c
@@ -123,6 +123,7 @@ 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 AllSockets;              /* select on this */
 fd_set AllClients;              /* available clients */
 fd_set LastSelectMask;          /* mask returned from last select call */
@@ -1090,6 +1091,98 @@ RemoveEnabledDevice(int fd)
     RemoveGeneralSocket(fd);
 }
 
+struct notify_fd {
+    struct xorg_list list;
+    int fd;
+    int mask;
+    NotifyFdProcPtr notify;
+    void *data;
+};
+
+static struct xorg_list notify_fds;
+
+void
+InitNotifyFds(void)
+{
+    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);
+    been_here = 1;
+}
+
+/*****************
+ * SetNotifyFd
+ *    Registers a callback to be invoked when the specified
+ *    file descriptor becomes readable.
+ *****************/
+
+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) {
+        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);
+            AddGeneralSocket(fd);
+        } else {
+            RemoveGeneralSocket(fd);
+            FD_CLR(fd, &NotifyReadFds);
+        }
+    }
+    if (mask == 0) {
+        xorg_list_del(&n->list);
+        free(n);
+    } else {
+        n->mask = mask;
+        n->data = data;
+        n->notify = notify;
+    }
+
+    return TRUE;
+}
+
+/*****************
+ * HandlNotifyFds
+ *    A WorkProc to be called when any of the registered
+ *    file descriptors are readable.
+ *****************/
+
+void
+HandleNotifyFds(void)
+{
+    struct notify_fd *s, *next; 
+
+    xorg_list_for_each_entry_safe(s, next, &notify_fds, list) {
+        if (FD_ISSET(s->fd, &LastSelectMask)) {
+            s->notify(s->fd, X_NOTIFY_READ, s->data);
+        }
+    }
+}
+
 /*****************
  * OnlyListenToOneClient:
  *    Only accept requests from  one client.  Continue to handle new
diff --git a/os/osdep.h b/os/osdep.h
index 86263a5..2bfc783 100644
--- a/os/osdep.h
+++ b/os/osdep.h
@@ -159,6 +159,10 @@ extern int FlushClient(ClientPtr /*who */ ,
 extern void FreeOsBuffers(OsCommPtr     /*oc */
     );
 
+extern void InitNotifyFds(void);
+
+extern void HandleNotifyFds(void);
+
 #include "dix.h"
 
 extern fd_set AllSockets;
@@ -166,6 +170,7 @@ extern fd_set AllClients;
 extern fd_set LastSelectMask;
 extern fd_set WellKnownConnections;
 extern fd_set EnabledDevices;
+extern fd_set NotifyReadFds;
 extern fd_set ClientsWithInput;
 extern fd_set ClientsWriteBlocked;
 extern fd_set OutputPending;
diff --git a/os/osinit.c b/os/osinit.c
index ddd3fce..ffc3691 100644
--- a/os/osinit.c
+++ b/os/osinit.c
@@ -312,6 +312,7 @@ OsInit(void)
         LockServer();
         been_here = TRUE;
     }
+    InitNotifyFds();
     TimerInit();
     OsVendorInit();
     OsResetSignals();
-- 
2.5.0



More information about the xorg-devel mailing list