summaryrefslogtreecommitdiffstats
path: root/unix/xserver
diff options
context:
space:
mode:
authorPierre Ossman <ossman@cendio.se>2011-10-25 15:13:13 +0000
committerPierre Ossman <ossman@cendio.se>2011-10-25 15:13:13 +0000
commit4ce51ffc4ec5fb060855dbe17579cbb3d9228e61 (patch)
tree77a584a327ef2e1ad6d50882943e5605bde10e81 /unix/xserver
parent7d4e88868a1304caafdc6bef84d0e94785f2ddb5 (diff)
downloadtigervnc-4ce51ffc4ec5fb060855dbe17579cbb3d9228e61.tar.gz
tigervnc-4ce51ffc4ec5fb060855dbe17579cbb3d9228e61.zip
Make socket writes non-blockable. This allows the system to more quickly
return back to the Xorg main loop, meaning that things will be more responsive in the presence of slow VNC clients. git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4735 3789f03b-4d11-0410-bbf8-ca57d06f2519
Diffstat (limited to 'unix/xserver')
-rw-r--r--unix/xserver/hw/vnc/XserverDesktop.cc74
-rw-r--r--unix/xserver/hw/vnc/XserverDesktop.h2
-rw-r--r--unix/xserver/hw/vnc/vncExtInit.cc88
3 files changed, 164 insertions, 0 deletions
diff --git a/unix/xserver/hw/vnc/XserverDesktop.cc b/unix/xserver/hw/vnc/XserverDesktop.cc
index 9afbb49b..9c5b20b5 100644
--- a/unix/xserver/hw/vnc/XserverDesktop.cc
+++ b/unix/xserver/hw/vnc/XserverDesktop.cc
@@ -581,6 +581,7 @@ void XserverDesktop::wakeupHandler(fd_set* fds, int nfds)
if (FD_ISSET(listener->getFd(), fds)) {
FD_CLR(listener->getFd(), fds);
Socket* sock = listener->accept();
+ sock->outStream().setBlocking(false);
server->addSocket(sock);
vlog.debug("new client, sock %d",sock->getFd());
}
@@ -590,6 +591,7 @@ void XserverDesktop::wakeupHandler(fd_set* fds, int nfds)
if (FD_ISSET(httpListener->getFd(), fds)) {
FD_CLR(httpListener->getFd(), fds);
Socket* sock = httpListener->accept();
+ sock->outStream().setBlocking(false);
httpServer->addSocket(sock);
vlog.debug("new http client, sock %d",sock->getFd());
}
@@ -632,6 +634,78 @@ void XserverDesktop::wakeupHandler(fd_set* fds, int nfds)
}
}
+void XserverDesktop::writeBlockHandler(fd_set* fds)
+{
+ try {
+ std::list<Socket*> sockets;
+ std::list<Socket*>::iterator i;
+
+ server->getSockets(&sockets);
+ for (i = sockets.begin(); i != sockets.end(); i++) {
+ int fd = (*i)->getFd();
+ if ((*i)->isShutdown()) {
+ vlog.debug("client gone, sock %d",fd);
+ server->removeSocket(*i);
+ vncClientGone(fd);
+ delete (*i);
+ } else {
+ if ((*i)->outStream().bufferUsage() > 0)
+ FD_SET(fd, fds);
+ }
+ }
+
+ if (httpServer) {
+ httpServer->getSockets(&sockets);
+ for (i = sockets.begin(); i != sockets.end(); i++) {
+ int fd = (*i)->getFd();
+ if ((*i)->isShutdown()) {
+ vlog.debug("http client gone, sock %d",fd);
+ httpServer->removeSocket(*i);
+ delete (*i);
+ } else {
+ if ((*i)->outStream().bufferUsage() > 0)
+ FD_SET(fd, fds);
+ }
+ }
+ }
+ } catch (rdr::Exception& e) {
+ vlog.error("XserverDesktop::writeBlockHandler: %s",e.str());
+ }
+}
+
+void XserverDesktop::writeWakeupHandler(fd_set* fds, int nfds)
+{
+ if (nfds < 1)
+ return;
+
+ try {
+ std::list<Socket*> sockets;
+ std::list<Socket*>::iterator i;
+
+ server->getSockets(&sockets);
+ for (i = sockets.begin(); i != sockets.end(); i++) {
+ int fd = (*i)->getFd();
+ if (FD_ISSET(fd, fds)) {
+ FD_CLR(fd, fds);
+ (*i)->outStream().flush();
+ }
+ }
+
+ if (httpServer) {
+ httpServer->getSockets(&sockets);
+ for (i = sockets.begin(); i != sockets.end(); i++) {
+ int fd = (*i)->getFd();
+ if (FD_ISSET(fd, fds)) {
+ FD_CLR(fd, fds);
+ (*i)->outStream().flush();
+ }
+ }
+ }
+ } catch (rdr::Exception& e) {
+ vlog.error("XserverDesktop::writeWakeupHandler: %s",e.str());
+ }
+}
+
void XserverDesktop::addClient(Socket* sock, bool reverse)
{
vlog.debug("new client, sock %d reverse %d",sock->getFd(),reverse);
diff --git a/unix/xserver/hw/vnc/XserverDesktop.h b/unix/xserver/hw/vnc/XserverDesktop.h
index 1c037053..af365117 100644
--- a/unix/xserver/hw/vnc/XserverDesktop.h
+++ b/unix/xserver/hw/vnc/XserverDesktop.h
@@ -72,6 +72,8 @@ public:
void ignoreHooks(bool b) { ignoreHooks_ = b; }
void blockHandler(fd_set* fds);
void wakeupHandler(fd_set* fds, int nfds);
+ void writeBlockHandler(fd_set* fds);
+ void writeWakeupHandler(fd_set* fds, int nfds);
void addClient(network::Socket* sock, bool reverse);
void disconnectClients();
diff --git a/unix/xserver/hw/vnc/vncExtInit.cc b/unix/xserver/hw/vnc/vncExtInit.cc
index d3cfbe26..baa8fa4e 100644
--- a/unix/xserver/hw/vnc/vncExtInit.cc
+++ b/unix/xserver/hw/vnc/vncExtInit.cc
@@ -21,6 +21,7 @@
#endif
#include <stdio.h>
+#include <errno.h>
extern "C" {
#define class c_class
@@ -28,6 +29,7 @@ extern "C" {
#define NEED_EVENTS
#include <X11/X.h>
#include <X11/Xproto.h>
+#include <X11/Xpoll.h>
#include "misc.h"
#include "os.h"
#include "dixstruct.h"
@@ -63,6 +65,8 @@ extern "C" {
static void vncResetProc(ExtensionEntry* extEntry);
static void vncBlockHandler(pointer data, OSTimePtr t, pointer readmask);
static void vncWakeupHandler(pointer data, int nfds, pointer readmask);
+ void vncWriteBlockHandler(fd_set *fds);
+ void vncWriteWakeupHandler(int nfds, fd_set *fds);
static void vncClientStateChange(CallbackListPtr*, pointer, pointer);
static void SendSelectionChangeEvent(Atom selection);
static int ProcVncExtDispatch(ClientPtr client);
@@ -287,6 +291,9 @@ static void vncSelectionCallback(CallbackListPtr *callbacks, pointer data, point
SendSelectionChangeEvent(selection->selection);
}
+static void vncWriteBlockHandlerFallback(OSTimePtr timeout);
+static void vncWriteWakeupHandlerFallback();
+
//
// vncBlockHandler - called just before the X server goes into select(). Call
// on to the block handler for each desktop. Then check whether any of the
@@ -297,6 +304,8 @@ static void vncBlockHandler(pointer data, OSTimePtr timeout, pointer readmask)
{
fd_set* fds = (fd_set*)readmask;
+ vncWriteBlockHandlerFallback(timeout);
+
for (int scr = 0; scr < screenInfo.numScreens; scr++)
if (desktop[scr])
desktop[scr]->blockHandler(fds);
@@ -311,6 +320,85 @@ static void vncWakeupHandler(pointer data, int nfds, pointer readmask)
desktop[scr]->wakeupHandler(fds, nfds);
}
}
+
+ vncWriteWakeupHandlerFallback();
+}
+
+//
+// vncWriteBlockHandler - extra hack to be able to get the main select loop
+// to monitor writeable fds and not just readable. This requirers a modified
+// Xorg and might therefore not be called. When it is called though, it will
+// do so before vncBlockHandler (and vncWriteWakeupHandler called after
+// vncWakeupHandler).
+//
+
+static bool needFallback = true;
+static fd_set fallbackFds;
+static struct timeval tw;
+
+void vncWriteBlockHandler(fd_set *fds)
+{
+ needFallback = false;
+
+ for (int scr = 0; scr < screenInfo.numScreens; scr++)
+ if (desktop[scr])
+ desktop[scr]->writeBlockHandler(fds);
+}
+
+void vncWriteWakeupHandler(int nfds, fd_set *fds)
+{
+ for (int scr = 0; scr < screenInfo.numScreens; scr++) {
+ if (desktop[scr]) {
+ desktop[scr]->writeWakeupHandler(fds, nfds);
+ }
+ }
+}
+
+static void vncWriteBlockHandlerFallback(OSTimePtr timeout)
+{
+ if (!needFallback)
+ return;
+
+ FD_ZERO(&fallbackFds);
+ vncWriteBlockHandler(&fallbackFds);
+ needFallback = true;
+
+ if (!XFD_ANYSET(&fallbackFds))
+ return;
+
+ if ((*timeout == NULL) ||
+ ((*timeout)->tv_sec > 0) || ((*timeout)->tv_usec > 10000)) {
+ tw.tv_sec = 0;
+ tw.tv_usec = 10000;
+ *timeout = &tw;
+ }
+}
+
+static void vncWriteWakeupHandlerFallback()
+{
+ int ret;
+ struct timeval timeout;
+
+ if (!needFallback)
+ return;
+
+ if (!XFD_ANYSET(&fallbackFds))
+ return;
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+
+ ret = select(XFD_SETSIZE, NULL, &fallbackFds, NULL, &timeout);
+ if (ret < 0) {
+ ErrorF("vncWriteWakeupHandlerFallback(): select: %s\n",
+ strerror(errno));
+ return;
+ }
+
+ if (ret == 0)
+ return;
+
+ vncWriteWakeupHandler(ret, &fallbackFds);
}
static void vncClientStateChange(CallbackListPtr*, pointer, pointer p)