Fix TLS for platforms without library constructors.

Some platforms don't support constructors that get called when the
shared library gets loaded. This results in the thread-local-storage
key to never be allocated. Instead we can check if it was allocated on
each use. Also prevent creating new 'current' state if it already
exists, and avoid pthreads undefined behavior.

Bug b/25629882

Change-Id: I5e2486f88185150b976d88d0144e4d13a349eb79
Reviewed-on: https://swiftshader-review.googlesource.com/11628
Reviewed-by: Nicolas Capens <nicolascapens@google.com>
Tested-by: Nicolas Capens <nicolascapens@google.com>
diff --git a/src/Common/Thread.hpp b/src/Common/Thread.hpp
index 8f6443e..f59a0d4 100644
--- a/src/Common/Thread.hpp
+++ b/src/Common/Thread.hpp
@@ -135,7 +135,7 @@
 			return TlsAlloc();
 		#else
 			LocalStorageKey key;
-			pthread_key_create(&key, 0);
+			pthread_key_create(&key, NULL);
 			return key;
 		#endif
 	}
@@ -145,7 +145,7 @@
 		#if defined(_WIN32)
 			TlsFree(key);
 		#else
-			pthread_key_delete(key);
+			pthread_key_delete(key);   // Using an invalid key is an error but not undefined behavior.
 		#endif
 	}
 
@@ -154,7 +154,10 @@
 		#if defined(_WIN32)
 			TlsSetValue(key, value);
 		#else
-			pthread_setspecific(key, value);
+			if(key != TLS_OUT_OF_INDEXES)   // Avoid undefined behavior.
+			{
+				pthread_setspecific(key, value);
+			}
 		#endif
 	}
 
@@ -163,6 +166,11 @@
 		#if defined(_WIN32)
 			return TlsGetValue(key);
 		#else
+			if(key == TLS_OUT_OF_INDEXES)   // Avoid undefined behavior.
+			{
+				return nullptr;
+			}
+
 			return pthread_getspecific(key);
 		#endif
 	}
diff --git a/src/OpenGL/libEGL/main.cpp b/src/OpenGL/libEGL/main.cpp
index 667d7f4..f340475 100644
--- a/src/OpenGL/libEGL/main.cpp
+++ b/src/OpenGL/libEGL/main.cpp
@@ -27,11 +27,7 @@
 
 #include <EGL/eglext.h>
 
-static sw::Thread::LocalStorageKey currentTLS() {
-	static sw::Thread::LocalStorageKey rval =
-		sw::Thread::allocateLocalStorageKey();
-	return rval;
-}
+static sw::Thread::LocalStorageKey currentTLS = TLS_OUT_OF_INDEXES;
 
 #if !defined(_MSC_VER)
 #define CONSTRUCTOR __attribute__((constructor))
@@ -43,23 +39,31 @@
 
 namespace egl
 {
-void attachThread()
+Current *attachThread()
 {
 	TRACE("()");
 
-	Current *current = new Current;
-
-	if(current)
+	if(currentTLS == TLS_OUT_OF_INDEXES)
 	{
-		sw::Thread::setLocalStorage(currentTLS(), current);
-
-		current->error = EGL_SUCCESS;
-		current->API = EGL_OPENGL_ES_API;
-		current->display = EGL_NO_DISPLAY;
-		current->context = nullptr;
-		current->drawSurface = nullptr;
-		current->readSurface = nullptr;
+		currentTLS = sw::Thread::allocateLocalStorageKey();
 	}
+
+	Current *current = (Current*)sw::Thread::getLocalStorage(currentTLS);
+
+	if(!current)
+	{
+		current = new Current;
+
+		sw::Thread::setLocalStorage(currentTLS, current);
+	}
+
+	current->error = EGL_SUCCESS;
+	current->API = EGL_OPENGL_ES_API;
+	current->context = nullptr;
+	current->drawSurface = nullptr;
+	current->readSurface = nullptr;
+
+	return current;
 }
 
 void detachThread()
@@ -68,8 +72,8 @@
 
 	eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_CONTEXT, EGL_NO_SURFACE, EGL_NO_SURFACE);
 
-	delete (Current*)sw::Thread::getLocalStorage(currentTLS());
-	sw::Thread::setLocalStorage(currentTLS(), nullptr);
+	delete (Current*)sw::Thread::getLocalStorage(currentTLS);
+	sw::Thread::setLocalStorage(currentTLS, nullptr);
 }
 
 CONSTRUCTOR void attachProcess()
@@ -95,7 +99,7 @@
 	TRACE("()");
 
 	detachThread();
-	sw::Thread::freeLocalStorageKey(currentTLS());
+	sw::Thread::freeLocalStorageKey(currentTLS);
 }
 }
 
@@ -170,14 +174,14 @@
 {
 static Current *getCurrent(void)
 {
-	Current *current = (Current*)sw::Thread::getLocalStorage(currentTLS());
+	Current *current = (Current*)sw::Thread::getLocalStorage(currentTLS);
 
 	if(!current)
 	{
-		attachThread();
+		current = attachThread();
 	}
 
-	return (Current*)sw::Thread::getLocalStorage(currentTLS());
+	return current;
 }
 
 void setCurrentError(EGLint error)