fix a dead-lock in eglMakeCurrent

this was introduced in a recent change. eglMakeCurrent can
end up calling eglDestroyImageKHR via ANativewWindow::disconnect
when the consumer is in the same process.

we make sure we don't hold the lock while this is happening.

Change-Id: Id17fe4fd76eecf5f962cefb9aa32be41fc1b042d
This commit is contained in:
Mathias Agopian 2012-02-03 15:24:51 -08:00
parent 6f3114cafe
commit a4b2c04182
2 changed files with 53 additions and 21 deletions

View File

@ -345,42 +345,73 @@ EGLBoolean egl_display_t::terminate() {
void egl_display_t::loseCurrent(egl_context_t * cur_c) void egl_display_t::loseCurrent(egl_context_t * cur_c)
{ {
if (cur_c) { if (cur_c) {
egl_surface_t * cur_r = get_surface(cur_c->read); egl_display_t* display = cur_c->getDisplay();
egl_surface_t * cur_d = get_surface(cur_c->draw); if (display) {
display->loseCurrentImpl(cur_c);
}
}
}
// by construction, these are either 0 or valid (possibly terminated) void egl_display_t::loseCurrentImpl(egl_context_t * cur_c)
// it should be impossible for these to be invalid {
ContextRef _cur_c(cur_c); // by construction, these are either 0 or valid (possibly terminated)
SurfaceRef _cur_r(cur_r); // it should be impossible for these to be invalid
SurfaceRef _cur_d(cur_d); ContextRef _cur_c(cur_c);
SurfaceRef _cur_r(cur_c ? get_surface(cur_c->read) : NULL);
SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : NULL);
{ // scope for the lock
Mutex::Autolock _l(lock);
cur_c->onLooseCurrent(); cur_c->onLooseCurrent();
_cur_c.release();
_cur_r.release();
_cur_d.release();
} }
// This cannot be called with the lock held because it might end-up
// calling back into EGL (in particular when a surface is destroyed
// it calls ANativeWindow::disconnect
_cur_c.release();
_cur_r.release();
_cur_d.release();
} }
EGLBoolean egl_display_t::makeCurrent(egl_context_t* c, egl_context_t* cur_c, EGLBoolean egl_display_t::makeCurrent(egl_context_t* c, egl_context_t* cur_c,
EGLSurface draw, EGLSurface read, EGLContext ctx, EGLSurface draw, EGLSurface read, EGLContext ctx,
EGLSurface impl_draw, EGLSurface impl_read, EGLContext impl_ctx) EGLSurface impl_draw, EGLSurface impl_read, EGLContext impl_ctx)
{ {
Mutex::Autolock _l(lock);
EGLBoolean result; EGLBoolean result;
if (c) {
result = c->cnx->egl.eglMakeCurrent( // by construction, these are either 0 or valid (possibly terminated)
disp[c->impl].dpy, impl_draw, impl_read, impl_ctx); // it should be impossible for these to be invalid
} else { ContextRef _cur_c(cur_c);
result = cur_c->cnx->egl.eglMakeCurrent( SurfaceRef _cur_r(cur_c ? get_surface(cur_c->read) : NULL);
disp[cur_c->impl].dpy, impl_draw, impl_read, impl_ctx); SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : NULL);
}
if (result == EGL_TRUE) { { // scope for the lock
loseCurrent(cur_c); Mutex::Autolock _l(lock);
if (c) { if (c) {
c->onMakeCurrent(draw, read); result = c->cnx->egl.eglMakeCurrent(
disp[c->impl].dpy, impl_draw, impl_read, impl_ctx);
if (result == EGL_TRUE) {
c->onMakeCurrent(draw, read);
}
} else {
result = cur_c->cnx->egl.eglMakeCurrent(
disp[cur_c->impl].dpy, impl_draw, impl_read, impl_ctx);
if (result == EGL_TRUE) {
cur_c->onLooseCurrent();
}
} }
} }
if (result == EGL_TRUE) {
// This cannot be called with the lock held because it might end-up
// calling back into EGL (in particular when a surface is destroyed
// it calls ANativeWindow::disconnect
_cur_c.release();
_cur_r.release();
_cur_d.release();
}
return result; return result;
} }

View File

@ -64,6 +64,7 @@ struct egl_config_t {
class EGLAPI egl_display_t { // marked as EGLAPI for testing purposes class EGLAPI egl_display_t { // marked as EGLAPI for testing purposes
static egl_display_t sDisplay[NUM_DISPLAYS]; static egl_display_t sDisplay[NUM_DISPLAYS];
EGLDisplay getDisplay(EGLNativeDisplayType display); EGLDisplay getDisplay(EGLNativeDisplayType display);
void loseCurrentImpl(egl_context_t * cur_c);
public: public:
enum { enum {