[RFC] [PATCH v2 2/12] [xserver] Implemented first part of XResource extension v1.2: X_XResQueryClientIds

Erkki Seppälä erkki.seppala at vincit.fi
Fri Dec 31 05:32:40 PST 2010


This patch implements a part of the XResource extension v1.2 (as specified in
http://patchwork.freedesktop.org/patch/2720/ ). The request implemented is
X_XResQueryClientIds.

This patch depends on the patch
9d0d0115eee6c3c8e5c8a39fc9ed63407d218e9b "dix: Add facilities for
client ID tracking." that can be retrieved from
git://gitorious.org/rjy-fdo/xserver.git .

The patch is still against gitorious/xorg/xserver-xorg because that's
my development environment, but it applies cleanly against meego-w40
as well.

This latest version also adds Doxygen-formatted comments and takes a better
notice of coding conventions (as in http://www.x.org/wiki/CodingStyle ).

Signed-off-by: Erkki Seppälä <erkki.seppala at vincit.fi>
Reviewed-by: Rami Ylimäki <rami.ylimaki at vincit.fi>
---
 Xext/xres.c                 |  311 +++++++++++++++++++++++++++++++++++++++++++
 include/protocol-versions.h |    2 +-
 2 files changed, 312 insertions(+), 1 deletions(-)

diff --git a/Xext/xres.c b/Xext/xres.c
index 06639a2..ff7cf94 100644
--- a/Xext/xres.c
+++ b/Xext/xres.c
@@ -10,6 +10,7 @@
 #include <string.h>
 #include <X11/X.h>
 #include <X11/Xproto.h>
+#include <assert.h>
 #include "misc.h"
 #include "os.h"
 #include "dixstruct.h"
@@ -22,6 +23,97 @@
 #include "gcstruct.h"
 #include "modinit.h"
 #include "protocol-versions.h"
+#include "client.h"
+#include "list.h"
+#include <string.h>
+
+/** @brief Holds fragments of responses for ConstructClientIds.
+ *
+ *  note: there is no consideration for data alignment */
+typedef struct {
+    struct list l;
+    int   bytes;
+    /* data follows */
+} FragmentList;
+
+/** @brief Holds structure for the generated response to
+           ProcXResQueryClientIds; used by ConstructClientId* -functions */
+typedef struct {
+    int           numIds;
+    int           resultBytes;
+    struct list   response;
+    int           sentClientMasks[MAXCLIENTS];
+} ConstructClientIdCtx;
+
+/** @brief Allocate and add a sequence of bytes at the end of a fragment list.
+           Call DestroyFragments to release the list.
+
+    @param frags A pointer to head of an initialized linked list
+    @param bytes Number of bytes to allocate
+    @return Returns a pointer to the allocated non-zeroed region
+            that is to be filled by the caller. On error (out of memory)
+            returns NULL and makes no changes to the list.
+*/
+static void *
+AddFragment(struct list *frags, int bytes)
+{
+    FragmentList *f = malloc(sizeof(FragmentList) + bytes);
+    if (!f) {
+        return NULL;
+    } else {
+        f->bytes = bytes;
+        list_add(&f->l, frags->prev);
+        return (char*) f + sizeof(*f);
+    }
+}
+
+/** @brief Sends all fragments in the list to the client. Does not
+           free anything.
+
+    @param client The client to send the fragments to
+    @param frags The head of the list of fragments
+*/
+static void
+WriteFragmentsToClient(ClientPtr client, struct list *frags)
+{
+    FragmentList *it;
+    list_for_each_entry(it, frags, l) {
+        WriteToClient(client, it->bytes, (char*) it + sizeof(*it));
+    }
+}
+
+/** @brief Frees a list of fragments. Does not free() root node.
+
+    @param frags The head of the list of fragments
+*/
+static void
+DestroyFragments(struct list *frags)
+{
+    FragmentList *it, *tmp;
+    list_for_each_entry_safe(it, tmp, frags, l) {
+        list_del(&it->l);
+        free(it);
+    }
+}
+
+/** @brief Constructs a context record for ConstructClientId* functions
+           to use */
+static void
+InitConstructClientIdCtx(ConstructClientIdCtx *ctx)
+{
+    ctx->numIds = 0;
+    ctx->resultBytes = 0;
+    list_init(&ctx->response);
+    memset(ctx->sentClientMasks, 0, sizeof(ctx->sentClientMasks));
+}
+
+/** @brief Destroys a context record, releases all memory (except the storage
+           for *ctx itself) */
+static void
+DestroyConstructClientIdCtx(ConstructClientIdCtx *ctx)
+{
+    DestroyFragments(&ctx->response);
+}
 
 static int
 ProcXResQueryVersion (ClientPtr client)
@@ -298,6 +390,204 @@ ProcXResQueryClientPixmapBytes (ClientPtr client)
     return Success;
 }
 
+/** @brief Finds out if a client's information need to be put into the
+    response; marks client having been handled, if that is the case.
+
+    @param client   The client to send information about
+    @param mask     The request mask (0 to send everything, otherwise a
+                    bitmask of X_XRes*Mask)
+    @param ctx      The context record that tells which clients and id types
+                    have been already handled
+    @param sendMask Which id type are we now considering. One of X_XRes*Mask.
+
+    @return Returns TRUE if the client information needs to be on the
+            response, otherwise FALSE.
+*/
+static Bool
+WillConstructMask(ClientPtr client, CARD32 mask,
+                  ConstructClientIdCtx *ctx, int sendMask)
+{
+    if ((!mask || (mask & sendMask))
+        && !(ctx->sentClientMasks[client->index] & sendMask)) {
+        ctx->sentClientMasks[client->index] |= sendMask;
+        return TRUE;
+    } else {
+        return FALSE;
+    }
+}
+
+/** @brief Constructs a response about a single client, based on a certain
+           client id spec
+
+    @param sendClient Which client wishes to receive this answer. Used for
+                      byte endianess.
+    @param client     Which client are we considering.
+    @param mask       The client id spec mask indicating which information
+                      we want about this client.
+    @param ctx        The context record containing the constructed response
+                      and information on which clients and masks have been
+                      already handled.
+
+    @return Return TRUE if everything went OK, otherwise FALSE which indicates
+            a memory allocation problem.
+*/
+static Bool
+ConstructClientIdValue(ClientPtr sendClient, ClientPtr client, CARD32 mask,
+                       ConstructClientIdCtx *ctx)
+{
+    xXResClientIdValue rep;
+    int n;
+
+    rep.spec.client = client->clientAsMask;
+    if (client->swapped) {
+        swapl (&rep.spec.client, n);
+    }
+
+    if (WillConstructMask(client, mask, ctx, X_XResClientXidMask)) {
+        void *ptr = AddFragment(&ctx->response, sizeof(rep));
+        if (!ptr) {
+            return FALSE;
+        }
+
+        rep.spec.mask = X_XResClientXidMask;
+        rep.length = 0;
+        if (sendClient->swapped) {
+            swapl (&rep.spec.mask, n);
+            /* swapl (&rep.length, n); - not required for rep.length = 0 */
+        }
+
+        memcpy(ptr, &rep, sizeof(rep));
+
+        ctx->resultBytes += sizeof(rep);
+        ++ctx->numIds;
+    }
+    if (WillConstructMask(client, mask, ctx, X_XResLocalClientPidMask)) {
+        pid_t pid = GetClientPid(client);
+
+        if (pid != -1) {
+            void *ptr = AddFragment(&ctx->response,
+                                    sizeof(rep) + sizeof(CARD32));
+            CARD32 *value = (void*) ((char*) ptr + sizeof(rep));
+
+            if (!ptr) {
+                return FALSE;
+            }
+
+            rep.spec.mask = X_XResLocalClientPidMask;
+            rep.length = 4;
+
+            if (sendClient->swapped) {
+                swapl (&rep.spec.mask, n);
+                swapl (&rep.length, n);
+            }
+
+            if (sendClient->swapped) {
+                swapl (value, n);
+            }
+            memcpy(ptr, &rep, sizeof(rep));
+            *value = pid;
+
+            ctx->resultBytes += sizeof(rep) + sizeof(CARD32);
+            ++ctx->numIds;
+        }
+    }
+
+    /* memory allocation errors earlier may return with FALSE */
+    return TRUE;
+}
+
+/** @brief Constructs a response about all clients, based on a client id specs
+
+    @param client   Which client which we are constructing the response for.
+    @param numSpecs Number of client id specs in specs
+    @param specs    Client id specs
+
+    @return Return Success if everything went OK, otherwise a Bad* (currently
+            BadAlloc or BadValue)
+*/
+static int
+ConstructClientIds(ClientPtr client,
+                   int numSpecs, xXResClientIdSpec* specs,
+                   ConstructClientIdCtx *ctx)
+{
+    int specIdx;
+
+    for (specIdx = 0; specIdx < numSpecs; ++specIdx) {
+        if (specs[specIdx].client == 0) {
+            int c;
+            for (c = 0; c < currentMaxClients; ++c) {
+                if (clients[c]) {
+                    if (!ConstructClientIdValue(client, clients[c],
+                                                specs[specIdx].mask, ctx)) {
+                        return BadAlloc;
+                    }
+                }
+            }
+        } else {
+            int clientID = CLIENT_ID(specs[specIdx].client);
+
+            if ((clientID < currentMaxClients) && clients[clientID]) {
+                if (!ConstructClientIdValue(client, clients[clientID],
+                                            specs[specIdx].mask, ctx)) {
+                    return BadAlloc;
+                }
+            }
+        }
+    }
+
+    /* memory allocation errors earlier may return with BadAlloc */
+    return Success;
+}
+
+/** @brief Response to XResQueryClientIds request introduced in XResProto v1.2
+
+    @param client Which client which we are constructing the response for.
+
+    @return Returns the value returned from ConstructClientIds with the same
+            semantics
+*/
+static int
+ProcXResQueryClientIds (ClientPtr client)
+{
+    REQUEST(xXResQueryClientIdsReq);
+
+    xXResQueryClientIdsReply  rep;
+    xXResClientIdSpec        *specs = (void*) ((char*) stuff + sizeof(*stuff));
+    int                       rc;
+    ConstructClientIdCtx      ctx;
+
+    InitConstructClientIdCtx(&ctx);
+
+    REQUEST_AT_LEAST_SIZE(xXResQueryClientIdsReq);
+    REQUEST_FIXED_SIZE(xXResQueryClientIdsReq,
+                       stuff->numSpecs * sizeof(specs[0]));
+
+    rc = ConstructClientIds(client, stuff->numSpecs, specs, &ctx);
+
+    if (rc == Success) {
+        rep.type = X_Reply;
+        rep.sequenceNumber = client->sequence;
+
+        assert((ctx.resultBytes & 3) == 0);
+        rep.length = bytes_to_int32(ctx.resultBytes);
+        rep.numIds = ctx.numIds;
+
+        if (client->swapped) {
+            int n;
+            swaps (&rep.sequenceNumber, n);
+            swapl (&rep.length, n);
+            swapl (&rep.numIds, n);
+        }
+
+        WriteToClient(client,sizeof(rep),(char*)&rep);
+        WriteFragmentsToClient(client, &ctx.response);
+    }
+
+    DestroyConstructClientIdCtx(&ctx);
+
+    return rc;
+}
+
 static int
 ProcResDispatch (ClientPtr client)
 {
@@ -311,6 +601,11 @@ ProcResDispatch (ClientPtr client)
         return ProcXResQueryClientResources(client);
     case X_XResQueryClientPixmapBytes:
         return ProcXResQueryClientPixmapBytes(client);
+    case X_XResQueryClientIds:
+        return ProcXResQueryClientIds(client);
+    case X_XResQueryResourceBytes:
+        /* not implemented yet */
+        return BadRequest;
     default: break;
     }
 
@@ -352,6 +647,17 @@ SProcXResQueryClientPixmapBytes (ClientPtr client)
 }
 
 static int
+SProcXResQueryClientIds (ClientPtr client)
+{
+    REQUEST(xXResQueryClientIdsReq);
+    int n;
+
+    REQUEST_AT_LEAST_SIZE (xXResQueryClientIdsReq);
+    swaps(&stuff->numSpecs,n);
+    return ProcXResQueryClientIds(client);
+}
+
+static int
 SProcResDispatch (ClientPtr client)
 {
     REQUEST(xReq);
@@ -368,6 +674,11 @@ SProcResDispatch (ClientPtr client)
         return SProcXResQueryClientResources(client);
     case X_XResQueryClientPixmapBytes:
         return SProcXResQueryClientPixmapBytes(client);
+    case X_XResQueryClientIds:
+        return SProcXResQueryClientIds(client);
+    case X_XResQueryResourceBytes:
+        /* not implemented yet */
+        return BadRequest;
     default: break;
     }
 
diff --git a/include/protocol-versions.h b/include/protocol-versions.h
index c8c7f5f..a94ed17 100644
--- a/include/protocol-versions.h
+++ b/include/protocol-versions.h
@@ -139,7 +139,7 @@
 
 /* Resource */
 #define SERVER_XRES_MAJOR_VERSION		1
-#define SERVER_XRES_MINOR_VERSION		0
+#define SERVER_XRES_MINOR_VERSION		2
 
 /* XvMC */
 #define SERVER_XVMC_MAJOR_VERSION		1
-- 
1.7.0.4



More information about the xorg-devel mailing list