summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/os.h13
-rw-r--r--os/WaitFor.c4
-rw-r--r--os/connection.c93
-rw-r--r--os/osdep.h5
-rw-r--r--os/osinit.c1
5 files changed, 116 insertions, 0 deletions
diff --git a/include/os.h b/include/os.h
index 9937f2ea5..aed2e2f99 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 732543086..12b21bb21 100644
--- a/os/WaitFor.c
+++ b/os/WaitFor.c
@@ -306,6 +306,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 3d33c4170..0df439189 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 86263a53e..2bfc783f0 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 6ec2f1167..54b39a0e8 100644
--- a/os/osinit.c
+++ b/os/osinit.c
@@ -314,6 +314,7 @@ OsInit(void)
LockServer();
been_here = TRUE;
}
+ InitNotifyFds();
TimerInit();
OsVendorInit();
OsResetSignals();