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));