[PATCH RFC xserver v2] configurable maximum number of clients

Olivier Fourdan ofourdan at redhat.com
Fri May 29 09:18:18 PDT 2015


Make the maximum number of clients user configurable, either from the command
line or from xorg.conf

This patch works by using the MAXCLIENTS (raised to 512) as the maximum
allowed number of clients, but allowing the actual limit to be set by the
user to a lower value (keeping the default of 256).

There is a limit size of 29 bits to be used to store both the client ID and
the X resources ID, so by reducing the number of clients allowed to connect to
the X server, the user can increase the number of X resources per client or
vice-versa.

Parts of this patch are based on a similar patch from Adam Jackson
<ajax at redhat.com>

Signed-off-by: Adam Jackson <ajax at redhat.com>
Signed-off-by: Olivier Fourdan <ofourdan at redhat.com>
---
 v2: Use the user set client limit in multiple places instead of MAXCLIENTS,
     Bump value for MAXCLIENTS, MAXSELECT, MAXSOCKS and OPEN_MAX to 512,
     Requires an updated Xproto.

 configure.ac                   |  2 +-
 dix/colormap.c                 | 28 ++++++++++++++--------------
 dix/dispatch.c                 |  4 ++--
 dix/main.c                     |  2 +-
 dix/resource.c                 | 33 ++++++++++++++++++++++++++++-----
 hw/dmx/glxProxy/glxext.c       |  2 +-
 hw/xfree86/common/xf86Config.c | 16 ++++++++++++++++
 hw/xfree86/man/xorg.conf.man   |  4 ++++
 include/misc.h                 |  3 ++-
 include/opaque.h               |  1 +
 include/resource.h             | 15 ++-------------
 man/Xserver.man                |  5 +++++
 os/connection.c                |  8 ++++----
 os/osdep.h                     |  8 ++++----
 os/osinit.c                    |  3 +++
 os/utils.c                     | 14 ++++++++++++++
 16 files changed, 102 insertions(+), 46 deletions(-)

diff --git a/configure.ac b/configure.ac
index f760730..1473713 100644
--- a/configure.ac
+++ b/configure.ac
@@ -400,7 +400,7 @@ case $host_os in
 	AC_DEFINE(CSRG_BASED, 1, [System is BSD-like])
 	;;
   cygwin*|mingw*)
-	CFLAGS="$CFLAGS -DFD_SETSIZE=256"
+	CFLAGS="$CFLAGS -DFD_SETSIZE=512"
 	;;
 esac
 
diff --git a/dix/colormap.c b/dix/colormap.c
index a3e5a2c..80928b4 100644
--- a/dix/colormap.c
+++ b/dix/colormap.c
@@ -249,7 +249,7 @@ CreateColormap(Colormap mid, ScreenPtr pScreen, VisualPtr pVisual,
 
     size = pVisual->ColormapEntries;
     sizebytes = (size * sizeof(Entry)) +
-        (MAXCLIENTS * sizeof(Pixel *)) + (MAXCLIENTS * sizeof(int));
+        (LimitClients * sizeof(Pixel *)) + (LimitClients * sizeof(int));
     if ((class | DynamicClass) == DirectColor)
         sizebytes *= 3;
     sizebytes += sizeof(ColormapRec);
@@ -274,7 +274,7 @@ CreateColormap(Colormap mid, ScreenPtr pScreen, VisualPtr pVisual,
     sizebytes = size * sizeof(Entry);
     pmap->clientPixelsRed = (Pixel **) ((char *) pmap->red + sizebytes);
     pmap->numPixelsRed = (int *) ((char *) pmap->clientPixelsRed +
-                                  (MAXCLIENTS * sizeof(Pixel *)));
+                                  (LimitClients * sizeof(Pixel *)));
     pmap->mid = mid;
     pmap->flags = 0;            /* start out with all flags clear */
     if (mid == pScreen->defColormap)
@@ -286,8 +286,8 @@ CreateColormap(Colormap mid, ScreenPtr pScreen, VisualPtr pVisual,
         size = NUMRED(pVisual);
     pmap->freeRed = size;
     memset((char *) pmap->red, 0, (int) sizebytes);
-    memset((char *) pmap->numPixelsRed, 0, MAXCLIENTS * sizeof(int));
-    for (pptr = &pmap->clientPixelsRed[MAXCLIENTS];
+    memset((char *) pmap->numPixelsRed, 0, LimitClients * sizeof(int));
+    for (pptr = &pmap->clientPixelsRed[LimitClients];
          --pptr >= pmap->clientPixelsRed;)
         *pptr = (Pixel *) NULL;
     if (alloc == AllocAll) {
@@ -310,26 +310,26 @@ CreateColormap(Colormap mid, ScreenPtr pScreen, VisualPtr pVisual,
     if ((class | DynamicClass) == DirectColor) {
         pmap->freeGreen = NUMGREEN(pVisual);
         pmap->green = (EntryPtr) ((char *) pmap->numPixelsRed +
-                                  (MAXCLIENTS * sizeof(int)));
+                                  (LimitClients * sizeof(int)));
         pmap->clientPixelsGreen = (Pixel **) ((char *) pmap->green + sizebytes);
         pmap->numPixelsGreen = (int *) ((char *) pmap->clientPixelsGreen +
-                                        (MAXCLIENTS * sizeof(Pixel *)));
+                                        (LimitClients * sizeof(Pixel *)));
         pmap->freeBlue = NUMBLUE(pVisual);
         pmap->blue = (EntryPtr) ((char *) pmap->numPixelsGreen +
-                                 (MAXCLIENTS * sizeof(int)));
+                                 (LimitClients * sizeof(int)));
         pmap->clientPixelsBlue = (Pixel **) ((char *) pmap->blue + sizebytes);
         pmap->numPixelsBlue = (int *) ((char *) pmap->clientPixelsBlue +
-                                       (MAXCLIENTS * sizeof(Pixel *)));
+                                       (LimitClients * sizeof(Pixel *)));
 
         memset((char *) pmap->green, 0, (int) sizebytes);
         memset((char *) pmap->blue, 0, (int) sizebytes);
 
         memmove((char *) pmap->clientPixelsGreen,
-                (char *) pmap->clientPixelsRed, MAXCLIENTS * sizeof(Pixel *));
+                (char *) pmap->clientPixelsRed, LimitClients * sizeof(Pixel *));
         memmove((char *) pmap->clientPixelsBlue,
-                (char *) pmap->clientPixelsRed, MAXCLIENTS * sizeof(Pixel *));
-        memset((char *) pmap->numPixelsGreen, 0, MAXCLIENTS * sizeof(int));
-        memset((char *) pmap->numPixelsBlue, 0, MAXCLIENTS * sizeof(int));
+                (char *) pmap->clientPixelsRed, LimitClients * sizeof(Pixel *));
+        memset((char *) pmap->numPixelsGreen, 0, LimitClients * sizeof(int));
+        memset((char *) pmap->numPixelsBlue, 0, LimitClients * sizeof(int));
 
         /* If every cell is allocated, mark its refcnt */
         if (alloc == AllocAll) {
@@ -413,7 +413,7 @@ FreeColormap(void *value, XID mid)
     (*pmap->pScreen->DestroyColormap) (pmap);
 
     if (pmap->clientPixelsRed) {
-        for (i = 0; i < MAXCLIENTS; i++)
+        for (i = 0; i < LimitClients; i++)
             free(pmap->clientPixelsRed[i]);
     }
 
@@ -431,7 +431,7 @@ FreeColormap(void *value, XID mid)
         }
     }
     if ((pmap->class | DynamicClass) == DirectColor) {
-        for (i = 0; i < MAXCLIENTS; i++) {
+        for (i = 0; i < LimitClients; i++) {
             free(pmap->clientPixelsGreen[i]);
             free(pmap->clientPixelsBlue[i]);
         }
diff --git a/dix/dispatch.c b/dix/dispatch.c
index 9208582..48b93af 100644
--- a/dix/dispatch.c
+++ b/dix/dispatch.c
@@ -3483,7 +3483,7 @@ NextAvailableClient(void *ospriv)
     xReq data;
 
     i = nextFreeClientID;
-    if (i == MAXCLIENTS)
+    if (i == LimitClients)
         return (ClientPtr) NULL;
     clients[i] = client =
         dixAllocateObjectWithPrivates(ClientRec, PRIVATE_CLIENT);
@@ -3503,7 +3503,7 @@ NextAvailableClient(void *ospriv)
     }
     if (i == currentMaxClients)
         currentMaxClients++;
-    while ((nextFreeClientID < MAXCLIENTS) && clients[nextFreeClientID])
+    while ((nextFreeClientID < LimitClients) && clients[nextFreeClientID])
         nextFreeClientID++;
 
     /* Enable client ID tracking. This must be done before
diff --git a/dix/main.c b/dix/main.c
index 09f9504..cc250f2 100644
--- a/dix/main.c
+++ b/dix/main.c
@@ -163,7 +163,7 @@ dix_main(int argc, char *argv[], char *envp[])
         OsInit();
         if (serverGeneration == 1) {
             CreateWellKnownSockets();
-            for (i = 1; i < MAXCLIENTS; i++)
+            for (i = 1; i < LimitClients; i++)
                 clients[i] = NullClient;
             serverClient = calloc(sizeof(ClientRec), 1);
             if (!serverClient)
diff --git a/dix/resource.c b/dix/resource.c
index af8e162..ad71b24 100644
--- a/dix/resource.c
+++ b/dix/resource.c
@@ -600,6 +600,29 @@ CreateNewResourceClass(void)
 
 static ClientResourceRec clientTable[MAXCLIENTS];
 
+static unsigned int
+ilog2(int val)
+{
+    int bits;
+
+    if (val <= 0)
+	return 0;
+    for (bits = 0; val != 0; bits++)
+	val >>= 1;
+    return bits - 1;
+}
+
+/*****************
+ * ResourceClientBits
+ *    Returns the client bit offset in the client + resources ID field
+ *****************/
+
+unsigned int
+ResourceClientBits(void)
+{
+    return (ilog2(LimitClients));
+}
+
 /*****************
  * InitClientResources
  *    When a new client is created, call this to allocate space
@@ -883,7 +906,7 @@ FreeResource(XID id, RESTYPE skipDeleteFuncType)
     int *eltptr;
     int elements;
 
-    if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) {
+    if (((cid = CLIENT_ID(id)) < LimitClients) && clientTable[cid].buckets) {
         head = &clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)];
         eltptr = &clientTable[cid].elements;
 
@@ -917,7 +940,7 @@ FreeResourceByType(XID id, RESTYPE type, Bool skipFree)
     ResourcePtr res;
     ResourcePtr *prev, *head;
 
-    if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) {
+    if (((cid = CLIENT_ID(id)) < LimitClients) && clientTable[cid].buckets) {
         head = &clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)];
 
         prev = head;
@@ -952,7 +975,7 @@ ChangeResourceValue(XID id, RESTYPE rtype, void *value)
     int cid;
     ResourcePtr res;
 
-    if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) {
+    if (((cid = CLIENT_ID(id)) < LimitClients) && clientTable[cid].buckets) {
         res = clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)];
 
         for (; res; res = res->next)
@@ -1190,7 +1213,7 @@ dixLookupResourceByType(void **result, XID id, RESTYPE rtype,
     if ((rtype & TypeMask) > lastResourceType)
         return BadImplementation;
 
-    if ((cid < MAXCLIENTS) && clientTable[cid].buckets) {
+    if ((cid < LimitClients) && clientTable[cid].buckets) {
         res = clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)];
 
         for (; res; res = res->next)
@@ -1223,7 +1246,7 @@ dixLookupResourceByClass(void **result, XID id, RESTYPE rclass,
 
     *result = NULL;
 
-    if ((cid < MAXCLIENTS) && clientTable[cid].buckets) {
+    if ((cid < LimitClients) && clientTable[cid].buckets) {
         res = clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)];
 
         for (; res; res = res->next)
diff --git a/hw/dmx/glxProxy/glxext.c b/hw/dmx/glxProxy/glxext.c
index 3c5a14b..c858272 100644
--- a/hw/dmx/glxProxy/glxext.c
+++ b/hw/dmx/glxProxy/glxext.c
@@ -347,7 +347,7 @@ GlxExtensionInit(void)
     /*
      ** Initialize table of client state.  There is never a client 0.
      */
-    for (i = 1; i <= MAXCLIENTS; i++) {
+    for (i = 1; i <= LimitClients; i++) {
         __glXClients[i] = 0;
     }
 
diff --git a/hw/xfree86/common/xf86Config.c b/hw/xfree86/common/xf86Config.c
index b8ec8a0..cd6d222 100644
--- a/hw/xfree86/common/xf86Config.c
+++ b/hw/xfree86/common/xf86Config.c
@@ -703,6 +703,7 @@ typedef enum {
     FLAG_DRI2,
     FLAG_USE_SIGIO,
     FLAG_AUTO_ADD_GPU,
+    FLAG_MAX_CLIENTS,
 } FlagValues;
 
 /**
@@ -762,6 +763,8 @@ static OptionInfoRec FlagOptions[] = {
      {0}, FALSE},
     {FLAG_AUTO_ADD_GPU, "AutoAddGPU", OPTV_BOOLEAN,
      {0}, FALSE},
+    {FLAG_MAX_CLIENTS, "MaxClients", OPTV_INTEGER,
+     {0}, FALSE },
     {-1, NULL, OPTV_NONE,
      {0}, FALSE},
 };
@@ -1052,6 +1055,19 @@ configServerFlags(XF86ConfFlagsPtr flagsconf, XF86OptionPtr layoutopts)
         xf86Info.dri2From = X_CONFIG;
     }
 #endif
+
+    from = X_DEFAULT;
+    if (LimitClients != LIMITCLIENTS)
+	from = X_CMDLINE;
+    i = -1;
+    if (xf86GetOptValInteger(FlagOptions, FLAG_MAX_CLIENTS, &i)) {
+	if (i != 64 && i != 128 && i != 256 && i != 512)
+		ErrorF("MaxClients must be one of 64, 128, 256 or 512\n");
+	from = X_CONFIG;
+	LimitClients = i;
+    }
+    xf86Msg(from, "Max clients allowed: %i, resource mask: 0x%x\n",
+	    LimitClients, RESOURCE_ID_MASK);
 }
 
 Bool
diff --git a/hw/xfree86/man/xorg.conf.man b/hw/xfree86/man/xorg.conf.man
index e9b6d99..08eb7a9 100644
--- a/hw/xfree86/man/xorg.conf.man
+++ b/hw/xfree86/man/xorg.conf.man
@@ -621,6 +621,10 @@ It is only enabled for screens that have the
 .B \*qDPMS\*q
 option set (see the MONITOR section below).
 .TP 7
+.BI "Option \*qMaxClients\*q  \*q" integer \*q
+Set the maximum number of clients allowed to connect to the X server.
+Acceptable values are 64, 128, 256 or 512.
+.TP 7
 .BI "Option \*qPixmap\*q  \*q" bpp \*q
 This sets the pixmap format to use for depth 24.
 Allowed values for
diff --git a/include/misc.h b/include/misc.h
index 9b1c03a..56e138c 100644
--- a/include/misc.h
+++ b/include/misc.h
@@ -86,7 +86,8 @@ OF THIS SOFTWARE.
 #ifndef MAXGPUSCREENS
 #define MAXGPUSCREENS	16
 #endif
-#define MAXCLIENTS	256
+#define MAXCLIENTS	512
+#define LIMITCLIENTS	256     /* Must be a power of 2 and <= MAXCLIENTS */
 #define MAXEXTENSIONS   128
 #define MAXFORMATS	8
 #define MAXDEVICES	40      /* input devices */
diff --git a/include/opaque.h b/include/opaque.h
index a2c54aa..0ba0d64 100644
--- a/include/opaque.h
+++ b/include/opaque.h
@@ -36,6 +36,7 @@ from The Open Group.
 extern _X_EXPORT const char *defaultTextFont;
 extern _X_EXPORT const char *defaultCursorFont;
 extern _X_EXPORT int MaxClients;
+extern _X_EXPORT int LimitClients;
 extern _X_EXPORT volatile char isItTimeToYield;
 extern _X_EXPORT volatile char dispatchException;
 
diff --git a/include/resource.h b/include/resource.h
index 772f363..597f7b6 100644
--- a/include/resource.h
+++ b/include/resource.h
@@ -85,21 +85,10 @@ typedef uint32_t RESTYPE;
 #define RT_LASTPREDEF	((RESTYPE)9)
 #define RT_NONE		((RESTYPE)0)
 
+extern unsigned int ResourceClientBits(void);
 /* bits and fields within a resource id */
 #define RESOURCE_AND_CLIENT_COUNT   29  /* 29 bits for XIDs */
-#if MAXCLIENTS == 64
-#define RESOURCE_CLIENT_BITS	6
-#endif
-#if MAXCLIENTS == 128
-#define RESOURCE_CLIENT_BITS	7
-#endif
-#if MAXCLIENTS == 256
-#define RESOURCE_CLIENT_BITS	8
-#endif
-#if MAXCLIENTS == 512
-#define RESOURCE_CLIENT_BITS	9
-#endif
-/* client field offset */
+#define RESOURCE_CLIENT_BITS        ResourceClientBits() /* client field offset */
 #define CLIENTOFFSET	    (RESOURCE_AND_CLIENT_COUNT - RESOURCE_CLIENT_BITS)
 /* resource field */
 #define RESOURCE_ID_MASK	((1 << CLIENTOFFSET) - 1)
diff --git a/man/Xserver.man b/man/Xserver.man
index 3bf844f..aba4f31 100644
--- a/man/Xserver.man
+++ b/man/Xserver.man
@@ -320,6 +320,11 @@ sets the stack space limit of the server to the specified number of kilobytes.
 A value of zero makes the stack size as large as possible.  The default value
 of \-1 leaves the stack space limit unchanged.
 .TP 8
+.B \-maxclients
+.BR 64 | 128 | 256 | 512
+Set the maximum number of clients allowed to connect to the X server.
+Acceptable values are 64, 128, 256 or 512.
+.TP 8
 .B \-render
 .BR default | mono | gray | color
 sets the color allocation policy that will be used by the render extension.
diff --git a/os/connection.c b/os/connection.c
index c36b125..94adb98 100644
--- a/os/connection.c
+++ b/os/connection.c
@@ -161,9 +161,9 @@ int *ConnectionTranslation = NULL;
  */
 
 #undef MAXSOCKS
-#define MAXSOCKS 500
+#define MAXSOCKS 512
 #undef MAXSELECT
-#define MAXSELECT 500
+#define MAXSELECT 512
 
 struct _ct_node {
     struct _ct_node *next;
@@ -296,8 +296,8 @@ InitConnectionLimits(void)
     if (lastfdesc > MAXSELECT)
         lastfdesc = MAXSELECT;
 
-    if (lastfdesc > MAXCLIENTS) {
-        lastfdesc = MAXCLIENTS;
+    if (lastfdesc > LimitClients) {
+        lastfdesc = LimitClients;
         if (debug_conns)
             ErrorF("REACHED MAXIMUM CLIENTS LIMIT %d\n", MAXCLIENTS);
     }
diff --git a/os/osdep.h b/os/osdep.h
index 77a5b53..83d60c1 100644
--- a/os/osdep.h
+++ b/os/osdep.h
@@ -65,7 +65,7 @@ SOFTWARE.
 
 #ifndef OPEN_MAX
 #ifdef SVR4
-#define OPEN_MAX 256
+#define OPEN_MAX MAXCLIENTS
 #else
 #include <sys/param.h>
 #ifndef OPEN_MAX
@@ -75,7 +75,7 @@ SOFTWARE.
 #if !defined(WIN32)
 #define OPEN_MAX NOFILES_MAX
 #else
-#define OPEN_MAX 256
+#define OPEN_MAX 512
 #endif
 #endif
 #endif
@@ -89,10 +89,10 @@ SOFTWARE.
  * like sysconf(_SC_OPEN_MAX) is not supported.
  */
 
-#if OPEN_MAX <= 256
+#if OPEN_MAX <= 512
 #define MAXSOCKS (OPEN_MAX - 1)
 #else
-#define MAXSOCKS 256
+#define MAXSOCKS 512
 #endif
 
 /* MAXSELECT is the number of fds that select() can handle */
diff --git a/os/osinit.c b/os/osinit.c
index 91e3e06..ddd3fce 100644
--- a/os/osinit.c
+++ b/os/osinit.c
@@ -86,6 +86,9 @@ int limitStackSpace = -1;
 int limitNoFile = -1;
 #endif
 
+/* The actual user defined max number of clients */
+int LimitClients = LIMITCLIENTS;
+
 static OsSigWrapperPtr OsSigWrapper = NULL;
 
 OsSigWrapperPtr
diff --git a/os/utils.c b/os/utils.c
index 7fd395b..d27605c 100644
--- a/os/utils.c
+++ b/os/utils.c
@@ -556,6 +556,7 @@ UseMsg(void)
 #ifdef LOCK_SERVER
     ErrorF("-nolock                disable the locking mechanism\n");
 #endif
+    ErrorF("-maxclients n          set maximum number of clients (power of two)\n");
     ErrorF("-nolisten string       don't listen on protocol\n");
     ErrorF("-listen string         listen on protocol\n");
     ErrorF("-noreset               don't reset after last client exists\n");
@@ -860,6 +861,19 @@ ProcessCommandLine(int argc, char *argv[])
                 nolock = TRUE;
         }
 #endif
+	else if ( strcmp( argv[i], "-maxclients") == 0)
+	{
+	    if (++i < argc) {
+		LimitClients = atoi(argv[i]);
+		if (LimitClients != 64 &&
+		    LimitClients != 128 &&
+		    LimitClients != 256 &&
+		    LimitClients != 512) {
+		    FatalError("maxclients must be one of 64, 128, 256 or 512\n");
+		}
+	    } else
+		UseMsg();
+	}
         else if (strcmp(argv[i], "-nolisten") == 0) {
             if (++i < argc) {
                 if (_XSERVTransNoListen(argv[i]))
-- 
2.4.1



More information about the xorg-devel mailing list