Release thread local storage on thread exit.
Calls to the EGL API from different threads may exit without releasing
their current TLS storage. This patch adds a destructor to release
them if they have not been released already. Prevents memory leakage in
processes where many threads are created.
Bug b/63434079
Bug swiftshader:80
Test: cts-tradefed run commandAndExit cts -m CtsMediaTestCases -t \
android.media.cts.DecodeAccuracyTest
Change-Id: I6e94a6d04ce84b884571248ab89b3b1a4e71998b
Reviewed-on: https://swiftshader-review.googlesource.com/18328
Tested-by: David Rim <davidrim@google.com>
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Common/Thread.hpp b/src/Common/Thread.hpp
index 186d1bd..b273e5b 100644
--- a/src/Common/Thread.hpp
+++ b/src/Common/Thread.hpp
@@ -65,7 +65,7 @@
typedef pthread_key_t LocalStorageKey;
#endif
- static LocalStorageKey allocateLocalStorageKey();
+ static LocalStorageKey allocateLocalStorageKey(void (*destructor)(void *storage) = free);
static void freeLocalStorageKey(LocalStorageKey key);
static void *allocateLocalStorage(LocalStorageKey key, size_t size);
static void *getLocalStorage(LocalStorageKey key);
@@ -145,13 +145,13 @@
#endif
}
- inline Thread::LocalStorageKey Thread::allocateLocalStorageKey()
+ inline Thread::LocalStorageKey Thread::allocateLocalStorageKey(void (*destructor)(void *storage))
{
#if defined(_WIN32)
return TlsAlloc();
#else
LocalStorageKey key;
- pthread_key_create(&key, free);
+ pthread_key_create(&key, destructor);
return key;
#endif
}
diff --git a/src/OpenGL/libEGL/main.cpp b/src/OpenGL/libEGL/main.cpp
index b953e4b..a1ff6f1 100644
--- a/src/OpenGL/libEGL/main.cpp
+++ b/src/OpenGL/libEGL/main.cpp
@@ -39,13 +39,41 @@
namespace egl
{
+void releaseCurrent(void *storage)
+{
+ // This pthread destructor is called after the TLS is already reset to NULL,
+ // so we can't call EGL functions here to do the cleanup.
+
+ Current *current = (Current*)storage;
+
+ if(current)
+ {
+ if(current->drawSurface)
+ {
+ current->drawSurface->release();
+ }
+
+ if(current->readSurface)
+ {
+ current->readSurface->release();
+ }
+
+ if(current->context)
+ {
+ current->context->release();
+ }
+
+ free(current);
+ }
+}
+
Current *attachThread()
{
TRACE("()");
if(currentTLS == TLS_OUT_OF_INDEXES)
{
- currentTLS = sw::Thread::allocateLocalStorageKey();
+ currentTLS = sw::Thread::allocateLocalStorageKey(releaseCurrent);
}
Current *current = (Current*)sw::Thread::allocateLocalStorage(currentTLS, sizeof(Current));