Updated patch with some other places with a potential leak.
On Thu, Mar 24, 2016 at 3:52 AM Guilherme Melo <gqm...@gmail.com> wrote: > I've finally got some time to rewrite this patch and now the solution > makes more sense. > I'm sending as an attachment. > I also have some tests on a github repository to check this bug. I don't > know if it is ok to post the link here though. > > > Guilherme > > On Tue, Dec 8, 2015 at 4:48 PM Guilherme Melo <gqm...@gmail.com> wrote: > >> >> This should be lastGLContext->loseCurrent(lastGLContext) I think. cx >> >> >> Yes, you are right. It seems the right thing to do, but actually this >> should be done every place where lastGLContext is set, right? >> It seems to me that every place where lastGLContext is set is a potential >> leak. >> >> While you're at it, it'd be nice to move that big block comment into the >>> commit message >> >> >> I'll do that, thanks. >> >> >> Guilherme >> >> >> >> 2015-12-08 14:44 GMT-02:00 Adam Jackson <a...@nwnk.net>: >> >>> On Fri, 2015-12-04 at 14:16 -0200, Guilherme Quentel Melo wrote: >>> >>> > diff --git a/glx/glxext.c b/glx/glxext.c >>> > index e41b881..16b8039 100644 >>> > --- a/glx/glxext.c >>> > +++ b/glx/glxext.c >>> > @@ -469,6 +469,24 @@ __glXForceCurrent(__GLXclientState * cl, >>> GLXContextTag tag, int *error) >>> > >>> > /* Make this context the current one for the GL. */ >>> > if (!cx->isDirect) { >>> > + /* >>> > + ** If we are forcing the context it means someone already >>> called makeCurrent before. If >>> > + ** we just call makeCurrent again, the drawable of this >>> context will be left with one >>> > + ** refcount more forever and will never be freed. >>> > + ** >>> > + ** This situation happens when there are many X clients >>> using GL: >>> > + ** >>> > + ** 1 - client1: calls glXMakeCurrent >>> > + ** >>> > + ** 2 - client2: calls glXMakeCurrent >>> > + ** This is the first context switch for this client. So >>> old_context_tag=0 >>> > + ** >>> > + ** 3 - client1: calls glXRender >>> > + ** For the client, its context is already current. >>> > + ** For the server side lastGLContext points to client2's >>> context. So the execution path >>> > + ** will get here. >>> > + */ >>> > + (*cx->loseCurrent) (cx); >>> >>> This should be lastGLContext->loseCurrent(lastGLContext) I think. cx >>> here is the current context from client2's perspective, you want to >>> release client1's context. >>> >>> While you're at it, it'd be nice to move that big block comment into >>> the commit message and just note /* drop previous client's context */ >>> or similar in the code. >>> >>> - ajax >> >> >>
From 3dc360e2998392d62af7c8272819e2c91350d183 Mon Sep 17 00:00:00 2001 From: Guilherme Quentel Melo <gqm...@gmail.com> Date: Thu, 24 Mar 2016 03:13:30 -0300 Subject: [PATCH] glx: avoid memory leak when using indirect rendering When multiple processes are using GL with indirect rendering a race condition can make drawables refcount never drop to zero. This situation could happen when there are many X clients using indirect GLX: 1 - client1: calls glXMakeCurrent 2 - client2: calls glXMakeCurrent This is the first context switch for this client. So old_context_tag=0 3 - client1: calls glXRender For the client, its context is already current. For the server side lastGLContext points to client2's context. Signed-off-by: Guilherme Quentel Melo <gqm...@gmail.com> --- glx/glxcmds.c | 20 ++++++++++++++++++-- glx/glxext.c | 18 +++++++++++++++--- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/glx/glxcmds.c b/glx/glxcmds.c index 561faeb..ffc6e9b 100644 --- a/glx/glxcmds.c +++ b/glx/glxcmds.c @@ -188,6 +188,11 @@ validGlxDrawable(ClientPtr client, XID id, int type, int access_mode, void __glXContextDestroy(__GLXcontext * context) { + __GLXcontext *lastglxc; + if (lastGLContext != NULL && lastGLContext != context) { + lastglxc = (__GLXcontext*)lastGLContext; + (*lastglxc->loseCurrent) (lastglxc); + } lastGLContext = NULL; } @@ -563,7 +568,7 @@ DoMakeCurrent(__GLXclientState * cl, { ClientPtr client = cl->client; xGLXMakeCurrentReply reply; - __GLXcontext *glxc, *prevglxc; + __GLXcontext *glxc, *prevglxc, *lastglxc = NULL; __GLXdrawable *drawPriv = NULL; __GLXdrawable *readPriv = NULL; int error; @@ -659,13 +664,24 @@ DoMakeCurrent(__GLXclientState * cl, if (!(*prevglxc->loseCurrent) (prevglxc)) { return __glXError(GLXBadContext); } - lastGLContext = NULL; if (!prevglxc->isDirect) { prevglxc->drawPriv = NULL; prevglxc->readPriv = NULL; } } + /* + ** lastGLContext may be different than prevglxc, so we need lose it to + ** avoid a memory leak + */ + if (lastGLContext != NULL) { + lastglxc = (__GLXcontext*)lastGLContext; + if (!lastglxc->isDirect && lastglxc != prevglxc) { + (*lastglxc->loseCurrent) (lastglxc); + } + lastGLContext = NULL; + } + if ((glxc != 0) && !glxc->isDirect) { glxc->drawPriv = drawPriv; diff --git a/glx/glxext.c b/glx/glxext.c index e41b881..b4fab20 100644 --- a/glx/glxext.c +++ b/glx/glxext.c @@ -117,7 +117,7 @@ static int glxBlockClients; static Bool DrawableGone(__GLXdrawable * glxPriv, XID xid) { - __GLXcontext *c, *next; + __GLXcontext *c, *next, *lastglxc; if (glxPriv->type == GLX_DRAWABLE_WINDOW) { /* If this was created by glXCreateWindow, free the matching resource */ @@ -139,6 +139,10 @@ DrawableGone(__GLXdrawable * glxPriv, XID xid) c->hasUnflushedCommands = GL_FALSE; /* just force a re-bind the next time through */ (*c->loseCurrent) (c); + if (lastGLContext != NULL && lastGLContext != c) { + lastglxc = (__GLXcontext*)lastGLContext; + (*lastglxc->loseCurrent) (lastglxc); + } lastGLContext = NULL; } if (c->drawPriv == glxPriv) @@ -280,7 +284,7 @@ glxClientCallback(CallbackListPtr *list, void *closure, void *data) NewClientInfoRec *clientinfo = (NewClientInfoRec *) data; ClientPtr pClient = clientinfo->client; __GLXclientState *cl = glxGetClient(pClient); - __GLXcontext *c, *next; + __GLXcontext *c, *next, *lastglxc; switch (pClient->clientState) { case ClientStateRunning: @@ -293,6 +297,10 @@ glxClientCallback(CallbackListPtr *list, void *closure, void *data) next = c->next; if (c->currentClient == pClient) { c->loseCurrent(c); + if (lastGLContext != NULL && lastGLContext != c) { + lastglxc = (__GLXcontext*)lastGLContext; + (*lastglxc->loseCurrent) (lastglxc); + } lastGLContext = NULL; c->currentClient = NULL; FreeResourceByType(c->id, __glXContextRes, FALSE); @@ -434,7 +442,7 @@ GlxExtensionInit(void) __GLXcontext * __glXForceCurrent(__GLXclientState * cl, GLXContextTag tag, int *error) { - __GLXcontext *cx; + __GLXcontext *cx, *lastglxc = NULL; /* ** See if the context tag is legal; it is managed by the extension, @@ -469,6 +477,10 @@ __glXForceCurrent(__GLXclientState * cl, GLXContextTag tag, int *error) /* Make this context the current one for the GL. */ if (!cx->isDirect) { + if (lastGLContext != NULL) { + lastglxc = (__GLXcontext*)lastGLContext; + (*lastglxc->loseCurrent) (lastglxc); + } lastGLContext = cx; if (!(*cx->makeCurrent) (cx)) { /* Bind failed, and set the error code. Bummer */ -- 2.5.0
_______________________________________________ xorg-devel@lists.x.org: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: https://lists.x.org/mailman/listinfo/xorg-devel